diff mbox series

[v3,05/35] acpi: Support generation of ACPI code

Message ID 20200613205459.v3.5.I8117fef4dff2607848f038cf14f6616f83997480@changeid
State Accepted
Commit 61cc93396a54c1c3fcace092c83def70f3843c2a
Headers show
Series dm: Add programmatic generation of ACPI tables (part B) | expand

Commit Message

Simon Glass June 14, 2020, 2:54 a.m. UTC
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 <sjg at 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

Comments

Wolfgang Wallner June 16, 2020, 11:31 a.m. UTC | #1
Hi Simon,

-----"Simon Glass" <sjg at chromium.org> schrieb: -----
> Betreff: [PATCH v3 05/35] acpi: Support generation of ACPI code
> 
> 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 <sjg at 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

Reviewed-by: Wolfgang Wallner <wolfgang.wallner at br-automation.com>
Bin Meng June 28, 2020, 9:13 a.m. UTC | #2
Hi Simon,

On Sun, Jun 14, 2020 at 10:55 AM Simon Glass <sjg at 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 <sjg at 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 <sjg at 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
diff mbox series

Patch

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;
 
 	/* 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);
+}
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 <sjg at 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);
+	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);