From de4b91ca686f1bedf46319f31b626cfe26665810 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 31 Dec 2023 08:25:46 -0700 Subject: smbios: SMBIOS 3.0 (64-bit) Entry Point structure Add definition of the SMBIOS 3.0 (64-bit) Entry Point structure. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Reviewed-by: Ilias Apalodimas Signed-off-by: Simon Glass --- include/smbios.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'include') diff --git a/include/smbios.h b/include/smbios.h index c9df2706f5a..e601283d293 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -54,6 +54,32 @@ struct __packed smbios_entry { u8 bcd_rev; }; +/** + * struct smbios3_entry - SMBIOS 3.0 (64-bit) Entry Point structure + */ +struct __packed smbios3_entry { + /** @anchor: anchor string */ + u8 anchor[5]; + /** @checksum: checksum of the entry point structure */ + u8 checksum; + /** @length: length of the entry point structure */ + u8 length; + /** @major_ver: major version of the SMBIOS specification */ + u8 major_ver; + /** @minor_ver: minor version of the SMBIOS specification */ + u8 minor_ver; + /** @docrev: revision of the SMBIOS specification */ + u8 doc_rev; + /** @entry_point_rev: revision of the entry point structure */ + u8 entry_point_rev; + /** @reserved: reserved */ + u8 reserved; + /** maximum size of SMBIOS table */ + u32 max_struct_size; + /** @struct_table_address: 64-bit physical starting address */ + u64 struct_table_address; +}; + /* BIOS characteristics */ #define BIOS_CHARACTERISTICS_PCI_SUPPORTED (1 << 7) #define BIOS_CHARACTERISTICS_UPGRADEABLE (1 << 11) -- cgit v1.3.1 From 70924294f375c351339f029b9615b52608e04cf4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 31 Dec 2023 08:25:47 -0700 Subject: smbios: Use SMBIOS 3.0 to support an address above 4GB When the SMBIOS table is written to an address above 4GB a 32-bit table address is not large enough. Use an SMBIOS3 table in that case. Note that we cannot use efi_allocate_pages() since this function has nothing to do with EFI. There is no equivalent function to allocate memory below 4GB in U-Boot. One solution would be to create a separate malloc() pool, or just always put the malloc() pool below 4GB. - Use log_debug() for warning - Rebase on Heinrich's smbios.h patch - Set the checksum for SMBIOS3 Signed-off-by: Simon Glass Reviewed-by: Heinrich Schuchardt --- include/smbios.h | 6 +++++- lib/smbios.c | 30 +++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/smbios.h b/include/smbios.h index e601283d293..77be58887a2 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -12,7 +12,7 @@ /* SMBIOS spec version implemented */ #define SMBIOS_MAJOR_VER 3 -#define SMBIOS_MINOR_VER 0 +#define SMBIOS_MINOR_VER 7 enum { SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */ @@ -80,6 +80,10 @@ struct __packed smbios3_entry { u64 struct_table_address; }; +/* These two structures should use the same amount of 16-byte-aligned space */ +static_assert(ALIGN(16, sizeof(struct smbios_entry)) == + ALIGN(16, sizeof(struct smbios3_entry))); + /* BIOS characteristics */ #define BIOS_CHARACTERISTICS_PCI_SUPPORTED (1 << 7) #define BIOS_CHARACTERISTICS_UPGRADEABLE (1 << 11) diff --git a/lib/smbios.c b/lib/smbios.c index eea72670bd9..7f79d969c92 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -567,7 +567,11 @@ ulong write_smbios_table(ulong addr) addr = ALIGN(addr, 16); start_addr = addr; - addr += sizeof(struct smbios_entry); + /* + * So far we don't know which struct will be used, but they both end + * up using the same amount of 16-bit-aligned space + */ + addr += max(sizeof(struct smbios_entry), sizeof(struct smbios3_entry)); addr = ALIGN(addr, 16); tables = addr; @@ -590,16 +594,32 @@ ulong write_smbios_table(ulong addr) * We must use a pointer here so things work correctly on sandbox. The * user of this table is not aware of the mapping of addresses to * sandbox's DRAM buffer. + * + * Check the address of the end of the tables. If it is above 4GB then + * it is sensible to use SMBIOS3 even if the start of the table is below + * 4GB (this case is very unlikely to happen in practice) */ table_addr = (ulong)map_sysmem(tables, 0); - if (sizeof(table_addr) > sizeof(u32) && table_addr > (ulong)UINT_MAX) { + if (sizeof(table_addr) > sizeof(u32) && addr >= (ulong)UINT_MAX) { + struct smbios3_entry *se; /* * We need to put this >32-bit pointer into the table but the * field is only 32 bits wide. */ - printf("WARNING: SMBIOS table_address overflow %llx\n", - (unsigned long long)table_addr); - addr = 0; + log_debug("WARNING: Using SMBIOS3.0 due to table-address overflow %lx\n", + table_addr); + se = map_sysmem(start_addr, sizeof(struct smbios_entry)); + memset(se, '\0', sizeof(struct smbios_entry)); + memcpy(se->anchor, "_SM3_", 5); + se->length = sizeof(struct smbios3_entry); + se->major_ver = SMBIOS_MAJOR_VER; + se->minor_ver = SMBIOS_MINOR_VER; + se->doc_rev = 0; + se->entry_point_rev = 1; + se->max_struct_size = len; + se->struct_table_address = table_addr; + se->checksum = table_compute_checksum(se, + sizeof(struct smbios3_entry)); } else { struct smbios_entry *se; -- cgit v1.3.1 From b2b58e1ef5c3f60ce6db1d6192c265d4ee45b170 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 31 Dec 2023 08:25:48 -0700 Subject: smbios: Correct gd_smbios_start() This should access arch-specific properties. Fix it and update the existing usage. Signed-off-by: Simon Glass Reviewed-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- include/asm-generic/global_data.h | 2 +- lib/efi_loader/efi_smbios.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 99bde9ec7e4..fcc3c6e14ca 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -553,7 +553,7 @@ static_assert(sizeof(struct global_data) == GD_SIZE); #endif #ifdef CONFIG_SMBIOS -#define gd_smbios_start() gd->smbios_start +#define gd_smbios_start() gd->arch.smbios_start #define gd_set_smbios_start(addr) gd->arch.smbios_start = addr #else #define gd_smbios_start() 0UL diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c index bbb8421ce14..49adc87e45a 100644 --- a/lib/efi_loader/efi_smbios.c +++ b/lib/efi_loader/efi_smbios.c @@ -28,7 +28,7 @@ efi_status_t efi_smbios_register(void) ulong addr; efi_status_t ret; - addr = gd->arch.smbios_start; + addr = gd_smbios_start(); if (!addr) { log_err("No SMBIOS tables to install\n"); return EFI_NOT_FOUND; -- cgit v1.3.1 From 138e69149b84180753da4dca59d4cb4f03da3ca7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 31 Dec 2023 08:25:49 -0700 Subject: efi: Use the correct GUID for the SMBIOS table EFI does not use the 'anchor string' to determine the SMBIOS table version, instead preferring to have two separate GUIDs. Use the correct one, depending on the table version. Call unmap_system() to balance to the use of map_sysmem() Signed-off-by: Simon Glass Reviewed-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- include/efi_api.h | 4 ++++ lib/efi_loader/efi_smbios.c | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/efi_api.h b/include/efi_api.h index 0e92cb8a7f6..ab40b1b5ddf 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -433,6 +433,10 @@ struct efi_runtime_services { EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \ 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) +#define SMBIOS3_TABLE_GUID \ + EFI_GUID(0xf2fd1544, 0x9794, 0x4a2c, \ + 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94) + #define EFI_LOAD_FILE_PROTOCOL_GUID \ EFI_GUID(0x56ec3091, 0x954c, 0x11d2, \ 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c index 49adc87e45a..5cbce6dc4eb 100644 --- a/lib/efi_loader/efi_smbios.c +++ b/lib/efi_loader/efi_smbios.c @@ -14,6 +14,8 @@ #include #include +const efi_guid_t smbios3_guid = SMBIOS3_TABLE_GUID; + enum { TABLE_SIZE = SZ_4K, }; @@ -25,8 +27,10 @@ enum { */ efi_status_t efi_smbios_register(void) { + const efi_guid_t *guid; ulong addr; efi_status_t ret; + void *buf; addr = gd_smbios_start(); if (!addr) { @@ -42,8 +46,12 @@ efi_status_t efi_smbios_register(void) log_debug("EFI using SMBIOS tables at %lx\n", addr); /* Install SMBIOS information as configuration table */ - return efi_install_configuration_table(&smbios_guid, - map_sysmem(addr, 0)); + buf = map_sysmem(addr, 0); + guid = !memcmp(buf, "_SM_", 4) ? &smbios_guid : &smbios3_guid; + ret = efi_install_configuration_table(guid, buf); + unmap_sysmem(buf); + + return ret; } static int install_smbios_table(void) -- cgit v1.3.1 From 31f950a963a382d48193ecd79698f795b7603846 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 31 Dec 2023 08:25:50 -0700 Subject: smbios: Require the caller to align the SMBIOS table All callers handle this alignment, so drop the unnecessary code. This simplifies things a little. Signed-off-by: Simon Glass Reviewed-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- include/smbios.h | 9 +++++---- lib/smbios.c | 2 -- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/include/smbios.h b/include/smbios.h index 77be58887a2..49de32fec2d 100644 --- a/include/smbios.h +++ b/include/smbios.h @@ -258,12 +258,13 @@ static inline void fill_smbios_header(void *table, int type, * * This writes SMBIOS table at a given address. * - * @addr: start address to write SMBIOS table. If this is not - * 16-byte-aligned then it will be aligned before the table is - * written. + * @addr: start address to write SMBIOS table, 16-byte-alignment + * recommended. Note that while the SMBIOS tables themself have no alignment + * requirement, some systems may requires alignment. For example x86 systems + * which put tables at f0000 require 16-byte alignment + * * Return: end address of SMBIOS table (and start address for next entry) * or NULL in case of an error - * */ ulong write_smbios_table(ulong addr); diff --git a/lib/smbios.c b/lib/smbios.c index 7f79d969c92..cfd451e4088 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -563,8 +563,6 @@ ulong write_smbios_table(ulong addr) ctx.dev = NULL; } - /* 16 byte align the table address */ - addr = ALIGN(addr, 16); start_addr = addr; /* -- cgit v1.3.1 From a8efebe71978b3b21e04c7f104987ada879e0800 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 31 Dec 2023 08:25:54 -0700 Subject: acpi: Write pointers to tables instead of addresses Sandbox uses an API to map between addresses and pointers. This allows it to have (emulated) memory at zero and avoid arch-specific addressing details. It also allows memory-mapped peripherals to work. As an example, on many machines sandbox maps address 100 to pointer value 10000000. However this is not correct for ACPI, if sandbox starts another program (e.g EFI app) and passes it the tables. That app has no knowledge of sandbox's address mapping. So to make this work we want to store 10000000 as the value in the table. Add two new 'nomap' functions which clearly make this exeption to how sandbox works. This should allow EFI apps to access ACPI tables with sandbox, e.g. for testing purposes. Signed-off-by: Simon Glass Suggested-by: Heinrich Schuchardt --- arch/sandbox/include/asm/io.h | 16 ++++++++++++++++ arch/x86/lib/acpi_table.c | 6 +++--- cmd/acpi.c | 12 ++++++------ include/mapmem.h | 18 ++++++++++++++++++ lib/acpi/acpi.c | 12 ++++++------ lib/acpi/acpi_table.c | 4 ++-- lib/acpi/base.c | 4 ++-- test/dm/acpi.c | 10 +++++----- 8 files changed, 58 insertions(+), 24 deletions(-) (limited to 'include') diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h index 3c0a102697e..a23bd64994a 100644 --- a/arch/sandbox/include/asm/io.h +++ b/arch/sandbox/include/asm/io.h @@ -231,5 +231,21 @@ static inline void unmap_sysmem(const void *vaddr) unmap_physmem(vaddr, MAP_WRBACK); } +/** + * nomap_sysmem() - pass through an address unchanged + * + * This is used to indicate an address which should NOT be mapped, e.g. in + * SMBIOS tables. Using this function instead of a case shows that the sandbox + * conversion has been done + */ +static inline void *nomap_sysmem(phys_addr_t paddr, unsigned long len) +{ + return (void *)(uintptr_t)paddr; +} + +static inline phys_addr_t nomap_to_sysmem(const void *ptr) +{ + return (phys_addr_t)(uintptr_t)ptr; +} #endif diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index c5b33dc65de..b366e44e337 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -197,7 +197,7 @@ int acpi_write_tcpa(struct acpi_ctx *ctx, const struct acpi_writer *entry) tcpa->platform_class = 0; tcpa->laml = size; - tcpa->lasa = map_to_sysmem(log); + tcpa->lasa = nomap_to_sysmem(log); /* (Re)calculate length and checksum */ current = (u32)tcpa + sizeof(struct acpi_tcpa); @@ -268,7 +268,7 @@ static int acpi_write_tpm2(struct acpi_ctx *ctx, /* Fill the log area size and start address fields. */ tpm2->laml = tpm2_log_len; - tpm2->lasa = map_to_sysmem(lasa); + tpm2->lasa = nomap_to_sysmem(lasa); /* Calculate checksum. */ header->checksum = table_compute_checksum(tpm2, header->length); @@ -430,7 +430,7 @@ int acpi_write_gnvs(struct acpi_ctx *ctx, const struct acpi_writer *entry) u32 *gnvs = (u32 *)((u32)ctx->dsdt + i); if (*gnvs == ACPI_GNVS_ADDR) { - *gnvs = map_to_sysmem(ctx->current); + *gnvs = nomap_to_sysmem(ctx->current); log_debug("Fix up global NVS in DSDT to %#08x\n", *gnvs); break; diff --git a/cmd/acpi.c b/cmd/acpi.c index 0c144092420..79e9335b5db 100644 --- a/cmd/acpi.c +++ b/cmd/acpi.c @@ -45,7 +45,7 @@ static int dump_table_name(const char *sig) if (!hdr) return -ENOENT; printf("%.*s @ %16lx\n", ACPI_NAME_LEN, hdr->signature, - (ulong)map_to_sysmem(hdr)); + (ulong)nomap_to_sysmem(hdr)); print_buffer(0, hdr, 1, hdr->length, 0); return 0; @@ -54,9 +54,9 @@ static int dump_table_name(const char *sig) static void list_fadt(struct acpi_fadt *fadt) { if (fadt->dsdt) - dump_hdr(map_sysmem(fadt->dsdt, 0)); + dump_hdr(nomap_sysmem(fadt->dsdt, 0)); if (fadt->firmware_ctrl) - dump_hdr(map_sysmem(fadt->firmware_ctrl, 0)); + dump_hdr(nomap_sysmem(fadt->firmware_ctrl, 0)); } static void list_rsdt(struct acpi_rsdp *rsdp) @@ -66,11 +66,11 @@ static void list_rsdt(struct acpi_rsdp *rsdp) struct acpi_xsdt *xsdt; if (rsdp->rsdt_address) { - rsdt = map_sysmem(rsdp->rsdt_address, 0); + rsdt = nomap_sysmem(rsdp->rsdt_address, 0); dump_hdr(&rsdt->header); } if (rsdp->xsdt_address) { - xsdt = map_sysmem(rsdp->xsdt_address, 0); + xsdt = nomap_sysmem(rsdp->xsdt_address, 0); dump_hdr(&xsdt->header); len = xsdt->header.length - sizeof(xsdt->header); count = len / sizeof(u64); @@ -91,7 +91,7 @@ static void list_rsdt(struct acpi_rsdp *rsdp) entry = rsdt->entry[i]; if (!entry) break; - hdr = map_sysmem(entry, 0); + hdr = nomap_sysmem(entry, 0); dump_hdr(hdr); if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) list_fadt((struct acpi_fadt *)hdr); diff --git a/include/mapmem.h b/include/mapmem.h index bb68b4c11af..f496c96d16c 100644 --- a/include/mapmem.h +++ b/include/mapmem.h @@ -28,6 +28,24 @@ static inline phys_addr_t map_to_sysmem(const void *ptr) { return (phys_addr_t)(uintptr_t)ptr; } + +/** + * nomap_sysmem() - pass through an address unchanged + * + * This is used to indicate an address which should NOT be mapped, e.g. in + * SMBIOS tables. Using this function instead of a case shows that the sandbox + * conversion has been done + */ +static inline void *nomap_sysmem(phys_addr_t paddr, unsigned long len) +{ + return (void *)(uintptr_t)paddr; +} + +static inline phys_addr_t nomap_to_sysmem(const void *ptr) +{ + return (phys_addr_t)(uintptr_t)ptr; +} + # endif #endif /* __MAPMEM_H */ diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c index 939a638bb5b..bcafd771750 100644 --- a/lib/acpi/acpi.c +++ b/lib/acpi/acpi.c @@ -22,13 +22,13 @@ struct acpi_table_header *acpi_find_table(const char *sig) if (!rsdp) return NULL; if (rsdp->xsdt_address) { - xsdt = map_sysmem(rsdp->xsdt_address, 0); + xsdt = nomap_sysmem(rsdp->xsdt_address, 0); len = xsdt->header.length - sizeof(xsdt->header); count = len / sizeof(u64); } else { if (!rsdp->rsdt_address) return NULL; - rsdt = map_sysmem(rsdp->rsdt_address, 0); + rsdt = nomap_sysmem(rsdp->rsdt_address, 0); len = rsdt->header.length - sizeof(rsdt->header); count = len / sizeof(u32); } @@ -36,19 +36,19 @@ struct acpi_table_header *acpi_find_table(const char *sig) struct acpi_table_header *hdr; if (rsdp->xsdt_address) - hdr = map_sysmem(xsdt->entry[i], 0); + hdr = nomap_sysmem(xsdt->entry[i], 0); else - hdr = map_sysmem(rsdt->entry[i], 0); + hdr = nomap_sysmem(rsdt->entry[i], 0); if (!memcmp(hdr->signature, sig, ACPI_NAME_LEN)) return hdr; if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) { struct acpi_fadt *fadt = (struct acpi_fadt *)hdr; if (!memcmp(sig, "DSDT", ACPI_NAME_LEN) && fadt->dsdt) - return map_sysmem(fadt->dsdt, 0); + return nomap_sysmem(fadt->dsdt, 0); if (!memcmp(sig, "FACS", ACPI_NAME_LEN) && fadt->firmware_ctrl) - return map_sysmem(fadt->firmware_ctrl, 0); + return nomap_sysmem(fadt->firmware_ctrl, 0); } } diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index e74522e9972..39dd53ec402 100644 --- a/lib/acpi/acpi_table.c +++ b/lib/acpi/acpi_table.c @@ -167,7 +167,7 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table) } /* Add table to the RSDT */ - rsdt->entry[i] = map_to_sysmem(table); + rsdt->entry[i] = nomap_to_sysmem(table); /* Fix RSDT length or the kernel will assume invalid entries */ rsdt->header.length = sizeof(struct acpi_table_header) + @@ -185,7 +185,7 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table) xsdt = ctx->xsdt; /* Add table to the XSDT */ - xsdt->entry[i] = map_to_sysmem(table); + xsdt->entry[i] = nomap_to_sysmem(table); /* Fix XSDT length */ xsdt->header.length = sizeof(struct acpi_table_header) + diff --git a/lib/acpi/base.c b/lib/acpi/base.c index 07b53e0c561..8b6af2bc43a 100644 --- a/lib/acpi/base.c +++ b/lib/acpi/base.c @@ -24,10 +24,10 @@ void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, memcpy(rsdp->oem_id, OEM_ID, 6); if (rsdt) - rsdp->rsdt_address = map_to_sysmem(rsdt); + rsdp->rsdt_address = nomap_to_sysmem(rsdt); if (xsdt) - rsdp->xsdt_address = map_to_sysmem(xsdt); + rsdp->xsdt_address = nomap_to_sysmem(xsdt); rsdp->length = sizeof(struct acpi_rsdp); rsdp->revision = ACPI_RSDP_REV_ACPI_2_0; diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 1211e2f0e7f..c53ebcdb1c1 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -291,8 +291,8 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts) /* Check that the pointers were added correctly */ for (i = 0; i < 3; i++) { - ut_asserteq(map_to_sysmem(dmar + i), ctx.rsdt->entry[i]); - ut_asserteq(map_to_sysmem(dmar + i), ctx.xsdt->entry[i]); + ut_asserteq(nomap_to_sysmem(dmar + i), ctx.rsdt->entry[i]); + ut_asserteq(nomap_to_sysmem(dmar + i), ctx.xsdt->entry[i]); } ut_asserteq(0, ctx.rsdt->entry[3]); ut_asserteq(0, ctx.xsdt->entry[3]); @@ -371,8 +371,8 @@ static int dm_test_acpi_ctx_and_base_tables(struct unit_test_state *uts) end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64); ut_asserteq_ptr(end, ctx.current); - ut_asserteq(map_to_sysmem(rsdt), rsdp->rsdt_address); - ut_asserteq(map_to_sysmem(xsdt), rsdp->xsdt_address); + ut_asserteq(nomap_to_sysmem(rsdt), rsdp->rsdt_address); + ut_asserteq(nomap_to_sysmem(xsdt), rsdp->xsdt_address); return 0; } @@ -445,7 +445,7 @@ static int dm_test_acpi_cmd_dump(struct unit_test_state *uts) /* Now a real table */ console_record_reset(); run_command("acpi dump dmar", 0); - addr = ALIGN(map_to_sysmem(ctx.xsdt) + sizeof(struct acpi_xsdt), 64); + addr = ALIGN(nomap_to_sysmem(ctx.xsdt) + sizeof(struct acpi_xsdt), 64); ut_assert_nextline("DMAR @ %16lx", addr); ut_assert_nextlines_are_dump(0x30); ut_assert_console_end(); -- cgit v1.3.1 From 70fe23859437ffe4efe0793423937d8b78ebf9d6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 3 Jan 2024 18:49:19 -0700 Subject: fdt: Allow the devicetree to come from a bloblist Standard passage provides for a bloblist to be passed from one firmware phase to the next. That can be used to pass the devicetree along as well. Add an option to support this. Tests for this will be added as part of the Universal Payload work. Signed-off-by: Simon Glass Reviewed-by: Tom Rini Reviewed-by: Ilias Apalodimas --- doc/develop/devicetree/control.rst | 3 +++ include/fdtdec.h | 6 ++++-- lib/fdtdec.c | 44 +++++++++++++++++++++++++++++--------- 3 files changed, 41 insertions(+), 12 deletions(-) (limited to 'include') diff --git a/doc/develop/devicetree/control.rst b/doc/develop/devicetree/control.rst index cbb65c9b177..11c92d440f4 100644 --- a/doc/develop/devicetree/control.rst +++ b/doc/develop/devicetree/control.rst @@ -108,6 +108,9 @@ If CONFIG_OF_BOARD is defined, a board-specific routine will provide the devicetree at runtime, for example if an earlier bootloader stage creates it and passes it to U-Boot. +If CONFIG_BLOBLIST is defined, the devicetree may come from a bloblist passed +from a previous stage, if present. + If CONFIG_SANDBOX is defined, then it will be read from a file on startup. Use the -d flag to U-Boot to specify the file to read, -D for the default and -T for the test devicetree, used to run sandbox unit tests. diff --git a/include/fdtdec.h b/include/fdtdec.h index bd1149f46d0..e80de24076c 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -72,7 +72,7 @@ struct bd_info; * U-Boot is packaged as an ELF file, e.g. for debugging purposes * @FDTSRC_ENV: Provided by the fdtcontroladdr environment variable. This should * be used for debugging/development only - * @FDTSRC_NONE: No devicetree at all + * @FDTSRC_BLOBLIST: Provided by a bloblist from an earlier phase */ enum fdt_source_t { FDTSRC_SEPARATE, @@ -80,6 +80,7 @@ enum fdt_source_t { FDTSRC_BOARD, FDTSRC_EMBED, FDTSRC_ENV, + FDTSRC_BLOBLIST, }; /* @@ -1190,7 +1191,8 @@ int fdtdec_resetup(int *rescan); * * The existing devicetree is available at gd->fdt_blob * - * @err internal error code if we fail to setup a DTB + * @err: 0 on success, -EEXIST if the devicetree is already correct, or other + * internal error code if we fail to setup a DTB * @returns new devicetree blob pointer */ void *board_fdt_blob_setup(int *err); diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 4016bf3c113..b2c59ab3818 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -7,6 +7,10 @@ */ #ifndef USE_HOSTCC + +#define LOG_CATEGORY LOGC_DT + +#include #include #include #include @@ -86,6 +90,7 @@ static const char *const fdt_src_name[] = { [FDTSRC_BOARD] = "board", [FDTSRC_EMBED] = "embed", [FDTSRC_ENV] = "env", + [FDTSRC_BLOBLIST] = "bloblist", }; const char *fdtdec_get_srcname(void) @@ -1662,23 +1667,42 @@ static void setup_multi_dtb_fit(void) int fdtdec_setup(void) { - int ret; + int ret = -ENOENT; + + /* If allowing a bloblist, check that first */ + if (CONFIG_IS_ENABLED(BLOBLIST)) { + ret = bloblist_maybe_init(); + if (!ret) { + gd->fdt_blob = bloblist_find(BLOBLISTT_CONTROL_FDT, 0); + if (gd->fdt_blob) { + gd->fdt_src = FDTSRC_BLOBLIST; + log_debug("Devicetree is in bloblist at %p\n", + gd->fdt_blob); + } else { + log_debug("No FDT found in bloblist\n"); + ret = -ENOENT; + } + } + } - /* The devicetree is typically appended to U-Boot */ - if (IS_ENABLED(CONFIG_OF_SEPARATE)) { - gd->fdt_blob = fdt_find_separate(); - gd->fdt_src = FDTSRC_SEPARATE; - } else { /* embed dtb in ELF file for testing / development */ - gd->fdt_blob = dtb_dt_embedded(); - gd->fdt_src = FDTSRC_EMBED; + /* Otherwise, the devicetree is typically appended to U-Boot */ + if (ret) { + if (IS_ENABLED(CONFIG_OF_SEPARATE)) { + gd->fdt_blob = fdt_find_separate(); + gd->fdt_src = FDTSRC_SEPARATE; + } else { /* embed dtb in ELF file for testing / development */ + gd->fdt_blob = dtb_dt_embedded(); + gd->fdt_src = FDTSRC_EMBED; + } } /* Allow the board to override the fdt address. */ if (IS_ENABLED(CONFIG_OF_BOARD)) { gd->fdt_blob = board_fdt_blob_setup(&ret); - if (ret) + if (!ret) + gd->fdt_src = FDTSRC_BOARD; + else if (ret != -EEXIST) return ret; - gd->fdt_src = FDTSRC_BOARD; } /* Allow the early environment to override the fdt address */ -- cgit v1.3.1 From a083ae71e085535e2caa0fd5de991bddced6dc94 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 16 Dec 2023 09:11:57 +0100 Subject: acpi: use 64-bit addresses in FADT table Fields X_FIRMWAE_CTRL and X_DSDT must be 64bit wide. Convert pointers to to uintptr_t to fill these. If field X_FIRMWARE_CTRL is filled, field FIRMWARE must be ignored. If field X_DSDT is filled, field DSDT must be ignored. We should not fill unused fields. See the field definitions in chapter "5.2.9 Fixed ACPI Description Table (FADT)" of the ACPI Specification 6.5. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass --- arch/x86/cpu/baytrail/acpi.c | 9 +++------ arch/x86/cpu/quark/acpi.c | 9 +++------ arch/x86/cpu/tangier/acpi.c | 9 +++------ arch/x86/lib/acpi_table.c | 9 ++------- include/acpi/acpi_table.h | 6 ++---- 5 files changed, 13 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/arch/x86/cpu/baytrail/acpi.c b/arch/x86/cpu/baytrail/acpi.c index 4378846f8b0..ccc4851b188 100644 --- a/arch/x86/cpu/baytrail/acpi.c +++ b/arch/x86/cpu/baytrail/acpi.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -31,8 +32,6 @@ static int baytrail_write_fadt(struct acpi_ctx *ctx, header->length = sizeof(struct acpi_fadt); header->revision = 4; - fadt->firmware_ctrl = (u32)ctx->facs; - fadt->dsdt = (u32)ctx->dsdt; fadt->preferred_pm_profile = ACPI_PM_MOBILE; fadt->sci_int = 9; fadt->smi_cmd = 0; @@ -79,10 +78,8 @@ static int baytrail_write_fadt(struct acpi_ctx *ctx, fadt->reset_reg.addrh = 0; fadt->reset_value = SYS_RST | RST_CPU | FULL_RST; - fadt->x_firmware_ctl_l = (u32)ctx->facs; - fadt->x_firmware_ctl_h = 0; - fadt->x_dsdt_l = (u32)ctx->dsdt; - fadt->x_dsdt_h = 0; + fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs); + fadt->x_dsdt = map_to_sysmem(ctx->dsdt); fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; diff --git a/arch/x86/cpu/quark/acpi.c b/arch/x86/cpu/quark/acpi.c index 9a2d682451b..0e18ceab68d 100644 --- a/arch/x86/cpu/quark/acpi.c +++ b/arch/x86/cpu/quark/acpi.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -26,8 +27,6 @@ static int quark_write_fadt(struct acpi_ctx *ctx, header->length = sizeof(struct acpi_fadt); header->revision = 4; - fadt->firmware_ctrl = (u32)ctx->facs; - fadt->dsdt = (u32)ctx->dsdt; fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED; fadt->sci_int = 9; fadt->smi_cmd = 0; @@ -74,10 +73,8 @@ static int quark_write_fadt(struct acpi_ctx *ctx, fadt->reset_reg.addrh = 0; fadt->reset_value = SYS_RST | RST_CPU | FULL_RST; - fadt->x_firmware_ctl_l = (u32)ctx->facs; - fadt->x_firmware_ctl_h = 0; - fadt->x_dsdt_l = (u32)ctx->dsdt; - fadt->x_dsdt_h = 0; + fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs); + fadt->x_dsdt = map_to_sysmem(ctx->dsdt); fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; diff --git a/arch/x86/cpu/tangier/acpi.c b/arch/x86/cpu/tangier/acpi.c index 1c667c7d569..1d37cc9e2b0 100644 --- a/arch/x86/cpu/tangier/acpi.c +++ b/arch/x86/cpu/tangier/acpi.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -31,8 +32,6 @@ static int tangier_write_fadt(struct acpi_ctx *ctx, header->length = sizeof(struct acpi_fadt); header->revision = 6; - fadt->firmware_ctrl = (u32)ctx->facs; - fadt->dsdt = (u32)ctx->dsdt; fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED; fadt->iapc_boot_arch = ACPI_FADT_VGA_NOT_PRESENT | @@ -45,10 +44,8 @@ static int tangier_write_fadt(struct acpi_ctx *ctx, fadt->minor_revision = 2; - fadt->x_firmware_ctl_l = (u32)ctx->facs; - fadt->x_firmware_ctl_h = 0; - fadt->x_dsdt_l = (u32)ctx->dsdt; - fadt->x_dsdt_h = 0; + fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs); + fadt->x_dsdt = map_to_sysmem(ctx->dsdt); header->checksum = table_compute_checksum(fadt, header->length); diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index b366e44e337..5ecd3d4b651 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -572,13 +572,8 @@ void acpi_fadt_common(struct acpi_fadt *fadt, struct acpi_facs *facs, memcpy(header->aslc_id, ASLC_ID, 4); header->aslc_revision = 1; - fadt->firmware_ctrl = (unsigned long)facs; - fadt->dsdt = (unsigned long)dsdt; - - fadt->x_firmware_ctl_l = (unsigned long)facs; - fadt->x_firmware_ctl_h = 0; - fadt->x_dsdt_l = (unsigned long)dsdt; - fadt->x_dsdt_h = 0; + fadt->x_firmware_ctrl = map_to_sysmem(facs); + fadt->x_dsdt = map_to_sysmem(dsdt); fadt->preferred_pm_profile = ACPI_PM_MOBILE; diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h index 20ac3b51ba7..e67562ef654 100644 --- a/include/acpi/acpi_table.h +++ b/include/acpi/acpi_table.h @@ -228,10 +228,8 @@ struct __packed acpi_fadt { u8 reset_value; u16 arm_boot_arch; u8 minor_revision; - u32 x_firmware_ctl_l; - u32 x_firmware_ctl_h; - u32 x_dsdt_l; - u32 x_dsdt_h; + u64 x_firmware_ctrl; + u64 x_dsdt; struct acpi_gen_regaddr x_pm1a_evt_blk; struct acpi_gen_regaddr x_pm1b_evt_blk; struct acpi_gen_regaddr x_pm1a_cnt_blk; -- cgit v1.3.1