
Hi Simon,
-----"Simon Glass" sjg@chromium.org schrieb: -----
Betreff: [PATCH v2 13/35] acpigen: Support writing a length
It is convenient to write a length value for preceding a block of data. Of course the length is not known or is hard to calculate a priori. So add a way to mark the start on a stack, so the length can be updated when known.
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2: None Changes in v1: None
include/acpi/acpigen.h | 3 ++ include/dm/acpi.h | 7 +++++ lib/acpi/acpigen.c | 33 ++++++++++++++++++++++ test/dm/acpigen.c | 64 ++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 105 insertions(+), 2 deletions(-)
diff --git a/include/acpi/acpigen.h b/include/acpi/acpigen.h index 7365cce738..31366f5e34 100644 --- a/include/acpi/acpigen.h +++ b/include/acpi/acpigen.h @@ -65,4 +65,7 @@ void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size); */ void acpigen_emit_string(struct acpi_ctx *ctx, const char *str);
+void acpigen_write_len_f(struct acpi_ctx *ctx); +void acpigen_pop_len(struct acpi_ctx *ctx);
#endif diff --git a/include/dm/acpi.h b/include/dm/acpi.h index 7563a4c60a..2bd03eaa0a 100644 --- a/include/dm/acpi.h +++ b/include/dm/acpi.h @@ -22,6 +22,9 @@ /* Length of an ACPI name string including nul terminator */ #define ACPI_NAME_MAX (ACPI_NAME_LEN + 1)
+/* Number of nested objects supported */ +#define ACPIGEN_LENSTACK_SIZE 10
#if !defined(__ACPI__)
/** @@ -34,12 +37,16 @@
- adding a new table. The RSDP holds pointers to the RSDT and XSDT.
- @rsdt: Pointer to the Root System Description Table
- @xsdt: Pointer to the Extended System Description Table
- @len_stack: Stack of 'length' words to fix up later
*/
- @ltop: Points to current top of stack (0 = empty)
struct acpi_ctx { void *current; struct acpi_rsdp *rsdp; struct acpi_rsdt *rsdt; struct acpi_xsdt *xsdt;
- char *len_stack[ACPIGEN_LENSTACK_SIZE];
- int ltop;
};
/** diff --git a/lib/acpi/acpigen.c b/lib/acpi/acpigen.c index 1223f0d1c4..bd1fa24fb6 100644 --- a/lib/acpi/acpigen.c +++ b/lib/acpi/acpigen.c @@ -10,6 +10,7 @@
#include <common.h> #include <dm.h> +#include <log.h> #include <acpi/acpigen.h> #include <dm/acpi.h>
@@ -37,6 +38,38 @@ void acpigen_emit_dword(struct acpi_ctx *ctx, uint data) acpigen_emit_byte(ctx, (data >> 24) & 0xff); }
+/*
- Maximum length for an ACPI object generated by this code,
- If you need to change this, change acpigen_write_len_f(ctx) and
- acpigen_pop_len(ctx)
- */
+#define ACPIGEN_MAXLEN 0xfffff
+void acpigen_write_len_f(struct acpi_ctx *ctx) +{
- assert(ctx->ltop < (ACPIGEN_LENSTACK_SIZE - 1));
- ctx->len_stack[ctx->ltop++] = ctx->current;
- acpigen_emit_byte(ctx, 0);
- acpigen_emit_byte(ctx, 0);
- acpigen_emit_byte(ctx, 0);
+}
+void acpigen_pop_len(struct acpi_ctx *ctx) +{
- int len;
- char *p;
- assert(ctx->ltop > 0);
- p = ctx->len_stack[--ctx->ltop];
- len = ctx->current - (void *)p;
- assert(len <= ACPIGEN_MAXLEN);
- /* generate store length for 0xfffff max */
- p[0] = (0x80 | (len & 0xf));
Nit: Without context this code is hard to understand. I would propose adding a comment pointing to "ACPI 6.3 20.2.4 Package Length Encoding" and using a define for 0x80 (something like ACPI_PKG_LEN_3_BYTES ...).
- p[1] = (len >> 4 & 0xff);
- p[2] = (len >> 12 & 0xff);
+}
void acpigen_emit_stream(struct acpi_ctx *ctx, const char *data, int size) { int i; diff --git a/test/dm/acpigen.c b/test/dm/acpigen.c index 3d580a23a5..f9c15b7503 100644 --- a/test/dm/acpigen.c +++ b/test/dm/acpigen.c @@ -22,7 +22,7 @@ #define TEST_STRING "frogmore" #define TEST_STREAM2 "\xfa\xde"
-static int alloc_context(struct acpi_ctx **ctxp) +static int alloc_context_size(struct acpi_ctx **ctxp, int size) { struct acpi_ctx *ctx;
@@ -30,7 +30,8 @@ static int alloc_context(struct acpi_ctx **ctxp) ctx = malloc(sizeof(*ctx)); if (!ctx) return -ENOMEM;
- ctx->current = malloc(150);
- ctx->current = malloc(size);
- ctx->ltop = 0; if (!ctx->current) return -ENOMEM; *ctxp = ctx;
@@ -38,6 +39,11 @@ static int alloc_context(struct acpi_ctx **ctxp) return 0; }
+static int alloc_context(struct acpi_ctx **ctxp) +{
- return alloc_context_size(ctxp, 150);
+}
static void free_context(struct acpi_ctx **ctxp) { free(*ctxp); @@ -334,3 +340,57 @@ static int dm_test_acpi_spi(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_acpi_spi, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+/**
- get_length() - decode a three-byte length field
- @ptr: Length encoded as per ACPI
- @return decoded length, or -EINVAL on error
- */
+static int get_length(u8 *ptr) +{
- if (!(*ptr & 0x80))
return -EINVAL;
- return (*ptr & 0xf) | ptr[1] << 4 | ptr[2] << 12;
+}
+/* Test emitting a length */ +static int dm_test_acpi_len(struct unit_test_state *uts) +{
- const int size = 0xc0000;
- struct acpi_ctx *ctx;
- u8 *ptr;
- int i;
- ut_assertok(alloc_context_size(&ctx, size));
- ptr = acpigen_get_current(ctx);
- /* Write a byte and a 3-byte length */
- acpigen_write_len_f(ctx);
- acpigen_emit_byte(ctx, 0x23);
- acpigen_pop_len(ctx);
- ut_asserteq(1 + 3, get_length(ptr));
- /* Write 200 bytes so we need two length bytes */
- ptr = ctx->current;
- acpigen_write_len_f(ctx);
- for (i = 0; i < 200; i++)
acpigen_emit_byte(ctx, 0x23);
- acpigen_pop_len(ctx);
- ut_asserteq(200 + 3, get_length(ptr));
- /* Write 40KB so we need three length bytes */
- ptr = ctx->current;
- acpigen_write_len_f(ctx);
- for (i = 0; i < 40000; i++)
acpigen_emit_byte(ctx, 0x23);
- acpigen_pop_len(ctx);
- ut_asserteq(40000 + 3, get_length(ptr));
- free_context(&ctx);
- return 0;
+}
+DM_TEST(dm_test_acpi_len, 0);
2.26.2.645.ge9eca65c58-goog
Reviewed-by: Wolfgang Wallner wolfgang.wallner@br-automation.com