Hi Simon, On Sun, Jun 14, 2020 at 10:55 AM Simon Glass <s...@chromium.org> wrote: > > Add a new file to handle generating ACPI code programatically. This is > used when information must be dynamically added to the tables, e.g. the > SSDT. > > Initial support is just for writing simple values. Also add a 'base' value > so that the table can be freed. This likely doesn't happen in normal code, > but is nice to do in tests. > > Signed-off-by: Simon Glass <s...@chromium.org> > --- > > (no changes since v2) > > Changes in v2: > - Update to add a new 'base' field to struct acpi_ctx > - Free the memory allocated to the table and context > > include/acpi/acpigen.h | 49 ++++++++++++++++++++++++++++++ > include/dm/acpi.h | 2 ++ > lib/acpi/Makefile | 1 + > lib/acpi/acpi_table.c | 1 + > lib/acpi/acpigen.c | 38 +++++++++++++++++++++++ > test/dm/Makefile | 1 + > test/dm/acpigen.c | 69 ++++++++++++++++++++++++++++++++++++++++++ > 7 files changed, 161 insertions(+) > create mode 100644 include/acpi/acpigen.h > create mode 100644 lib/acpi/acpigen.c > create mode 100644 test/dm/acpigen.c > > diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h > new file mode 100644 > index 0000000000..8809cdb4e1 > --- /dev/null > +++ b/include/acpi/acpigen.h > @@ -0,0 +1,49 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Core ACPI (Advanced Configuration and Power Interface) support > + * > + * Copyright 2019 Google LLC > + * > + * Modified from coreboot file acpigen.h > + */ > + > +#ifndef __ACPI_ACPIGEN_H > +#define __ACPI_ACPIGEN_H > + > +#include <linux/types.h> > + > +struct acpi_ctx; > + > +/** > + * acpigen_get_current() - Get the current ACPI code output pointer > + * > + * @ctx: ACPI context pointer > + * @return output pointer > + */ > +u8 *acpigen_get_current(struct acpi_ctx *ctx); > + > +/** > + * acpigen_emit_byte() - Emit a byte to the ACPI code > + * > + * @ctx: ACPI context pointer > + * @data: Value to output > + */ > +void acpigen_emit_byte(struct acpi_ctx *ctx, uint data); > + > +/** > + * acpigen_emit_word() - Emit a 16-bit word to the ACPI code > + * > + * @ctx: ACPI context pointer > + * @data: Value to output > + */ > +void acpigen_emit_word(struct acpi_ctx *ctx, uint data); > + > +/** > + * acpigen_emit_dword() - Emit a 32-bit 'double word' to the ACPI code > + * > + * @ctx: ACPI context pointer > + * @data: Value to output > + */ > +void acpigen_emit_dword(struct acpi_ctx *ctx, uint data); > + > +#endif > diff --git a/include/dm/acpi.h b/include/dm/acpi.h > index 7563a4c60a..696b1a96a0 100644 > --- a/include/dm/acpi.h > +++ b/include/dm/acpi.h > @@ -29,6 +29,7 @@ > * > * This contains a few useful pieces of information used when writing > * > + * @base: Base address of ACPI tables > * @current: Current address for writing > * @rsdp: Pointer to the Root System Description Pointer, typically used when > * adding a new table. The RSDP holds pointers to the RSDT and XSDT. > @@ -36,6 +37,7 @@ > * @xsdt: Pointer to the Extended System Description Table > */ > struct acpi_ctx { > + void *base; > void *current; > struct acpi_rsdp *rsdp; > struct acpi_rsdt *rsdt; > diff --git a/lib/acpi/Makefile b/lib/acpi/Makefile > index caae6c01bd..85a1f774ad 100644 > --- a/lib/acpi/Makefile > +++ b/lib/acpi/Makefile > @@ -1,5 +1,6 @@ > # SPDX-License-Identifier: GPL-2.0+ > # > > +obj-y += acpigen.o > obj-y += acpi_device.o > obj-y += acpi_table.o > diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c > index 431776666e..17d5258438 100644 > --- a/lib/acpi/acpi_table.c > +++ b/lib/acpi/acpi_table.c > @@ -238,6 +238,7 @@ static void acpi_write_xsdt(struct acpi_xsdt *xsdt) > void acpi_setup_base_tables(struct acpi_ctx *ctx, void *start) > { > ctx->current = start; > + ctx->current = start;
This seems to be unnecessary. > > /* Align ACPI tables to 16 byte */ > acpi_align(ctx); > diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c > new file mode 100644 > index 0000000000..59bd3af0b7 > --- /dev/null > +++ b/lib/acpi/acpigen.c > @@ -0,0 +1,38 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Generation of ACPI (Advanced Configuration and Power Interface) tables > + * > + * Copyright 2019 Google LLC > + * Mostly taken from coreboot > + */ > + > +#define LOG_CATEGORY LOGC_ACPI > + > +#include <common.h> > +#include <dm.h> > +#include <acpi/acpigen.h> > +#include <dm/acpi.h> > + > +u8 *acpigen_get_current(struct acpi_ctx *ctx) > +{ > + return ctx->current; > +} > + > +void acpigen_emit_byte(struct acpi_ctx *ctx, uint data) > +{ > + *(u8 *)ctx->current++ = data; > +} > + > +void acpigen_emit_word(struct acpi_ctx *ctx, uint data) > +{ > + acpigen_emit_byte(ctx, data & 0xff); > + acpigen_emit_byte(ctx, (data >> 8) & 0xff); > +} > + > +void acpigen_emit_dword(struct acpi_ctx *ctx, uint data) > +{ > + acpigen_emit_byte(ctx, data & 0xff); > + acpigen_emit_byte(ctx, (data >> 8) & 0xff); > + acpigen_emit_byte(ctx, (data >> 16) & 0xff); > + acpigen_emit_byte(ctx, (data >> 24) & 0xff); It would be better to document the endianness which is little-endian. > +} > diff --git a/test/dm/Makefile b/test/dm/Makefile > index 6c18fd04ce..e3e0cccf01 100644 > --- a/test/dm/Makefile > +++ b/test/dm/Makefile > @@ -14,6 +14,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o > obj-$(CONFIG_UT_DM) += core.o > ifneq ($(CONFIG_SANDBOX),) > obj-$(CONFIG_ACPIGEN) += acpi.o > +obj-$(CONFIG_ACPIGEN) += acpigen.o > obj-$(CONFIG_SOUND) += audio.o > obj-$(CONFIG_BLK) += blk.o > obj-$(CONFIG_BOARD) += board.o > diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c > new file mode 100644 > index 0000000000..c353408021 > --- /dev/null > +++ b/test/dm/acpigen.c > @@ -0,0 +1,69 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Tests for ACPI code generation > + * > + * Copyright 2019 Google LLC > + * Written by Simon Glass <s...@chromium.org> > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <malloc.h> > +#include <acpi/acpigen.h> > +#include <asm/unaligned.h> > +#include <dm/acpi.h> > +#include <dm/test.h> > +#include <test/ut.h> > + > +static int alloc_context(struct acpi_ctx **ctxp) > +{ > + struct acpi_ctx *ctx; > + > + *ctxp = NULL; > + ctx = malloc(sizeof(*ctx)); > + if (!ctx) > + return -ENOMEM; > + ctx->base = malloc(150); nits: avoid magic number > + if (!ctx->base) { > + free(ctx); > + return -ENOMEM; > + } > + ctx->current = ctx->base; > + *ctxp = ctx; > + > + return 0; > +} > + > +static void free_context(struct acpi_ctx **ctxp) > +{ > + free((*ctxp)->base); > + free(*ctxp); > + *ctxp = NULL; > +} > + > +/* Test emitting simple types and acpigen_get_current() */ > +static int dm_test_acpi_emit_simple(struct unit_test_state *uts) > +{ > + struct acpi_ctx *ctx; > + u8 *ptr; > + > + ut_assertok(alloc_context(&ctx)); > + > + ptr = acpigen_get_current(ctx); > + acpigen_emit_byte(ctx, 0x23); > + ut_asserteq(1, acpigen_get_current(ctx) - ptr); > + ut_asserteq(0x23, *(u8 *)ptr); > + > + acpigen_emit_word(ctx, 0x1234); > + ut_asserteq(3, acpigen_get_current(ctx) - ptr); > + ut_asserteq(0x1234, get_unaligned((u16 *)(ptr + 1))); > + > + acpigen_emit_dword(ctx, 0x87654321); > + ut_asserteq(7, acpigen_get_current(ctx) - ptr); > + ut_asserteq(0x87654321, get_unaligned((u32 *)(ptr + 3))); > + > + free_context(&ctx); > + > + return 0; > +} > +DM_TEST(dm_test_acpi_emit_simple, 0); > -- Regards, Bin