diff options
author | Simon Glass <sjg@chromium.org> | 2020-04-26 18:19:50 +0300 |
---|---|---|
committer | Bin Meng <bmeng.cn@gmail.com> | 2020-04-30 12:16:12 +0300 |
commit | 29b351122ed23124f70473a411c65074d5a61146 (patch) | |
tree | 3291b96b1660fcc0fad1db917def8f2f14768370 /lib/acpi/acpi_table.c | |
parent | 288edc78213433526e42cbc7c3dabca4fdf8e671 (diff) | |
download | u-boot-29b351122ed23124f70473a411c65074d5a61146.tar.xz |
acpi: Move acpi_add_table() to generic code
Move this code to a generic location so that we can test it with sandbox.
This requires adding a few new fields to acpi_ctx, so drop the local
variables used in the original code.
Also use mapmem to avoid pointer-to-address casts which don't work on
sandbox.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
Diffstat (limited to 'lib/acpi/acpi_table.c')
-rw-r--r-- | lib/acpi/acpi_table.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index 07d9bbb0af..4e354d313f 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -8,6 +8,8 @@ #include <common.h> #include <dm.h> #include <cpu.h> +#include <mapmem.h> +#include <tables_csum.h> #include <version.h> #include <acpi/acpi_table.h> #include <dm/acpi.h> @@ -120,3 +122,62 @@ void acpi_inc_align(struct acpi_ctx *ctx, uint amount) ctx->current += amount; acpi_align(ctx); } + +/** + * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length + * and checksum. + */ +int acpi_add_table(struct acpi_ctx *ctx, void *table) +{ + int i, entries_num; + struct acpi_rsdt *rsdt; + struct acpi_xsdt *xsdt; + + /* The RSDT is mandatory while the XSDT is not */ + rsdt = ctx->rsdt; + + /* This should always be MAX_ACPI_TABLES */ + entries_num = ARRAY_SIZE(rsdt->entry); + + for (i = 0; i < entries_num; i++) { + if (rsdt->entry[i] == 0) + break; + } + + if (i >= entries_num) { + log_err("ACPI: Error: too many tables\n"); + return -E2BIG; + } + + /* Add table to the RSDT */ + rsdt->entry[i] = map_to_sysmem(table); + + /* Fix RSDT length or the kernel will assume invalid entries */ + rsdt->header.length = sizeof(struct acpi_table_header) + + (sizeof(u32) * (i + 1)); + + /* Re-calculate checksum */ + rsdt->header.checksum = 0; + rsdt->header.checksum = table_compute_checksum((u8 *)rsdt, + rsdt->header.length); + + /* + * And now the same thing for the XSDT. We use the same index as for + * now we want the XSDT and RSDT to always be in sync in U-Boot + */ + xsdt = map_sysmem(ctx->rsdp->xsdt_address, sizeof(*xsdt)); + + /* Add table to the XSDT */ + xsdt->entry[i] = map_to_sysmem(table); + + /* Fix XSDT length */ + xsdt->header.length = sizeof(struct acpi_table_header) + + (sizeof(u64) * (i + 1)); + + /* Re-calculate checksum */ + xsdt->header.checksum = 0; + xsdt->header.checksum = table_compute_checksum((u8 *)xsdt, + xsdt->header.length); + + return 0; +} |