diff --git a/MAINTAINERS b/MAINTAINERS index 417061ae2f..0dedb428de 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -53,6 +53,7 @@ Maintainers List (try to look for most precise areas first) ACPI: M: Simon Glass S: Maintained +F: board/emulation/configs/acpi.config F: cmd/acpi.c F: lib/acpi/ diff --git a/arch/Kconfig b/arch/Kconfig index 2e0528d819..c23d57e4c4 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -108,6 +108,7 @@ config PPC config RISCV bool "RISC-V architecture" select CREATE_ARCH_SYMLINK + select SUPPORT_ACPI select SUPPORT_OF_CONTROL select OF_CONTROL select DM diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index 2bb978d668..452bcd1b8f 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -18,7 +18,12 @@ struct arch_global_data { #if defined(CONFIG_FSL_ESDHC) || defined(CONFIG_FSL_ESDHC_IMX) u32 sdhc_clk; #endif - +#if CONFIG_IS_ENABLED(ACPI) + ulong table_start; /* Start address of ACPI tables */ + ulong table_end; /* End address of ACPI tables */ + ulong table_start_high; /* Start address of high ACPI tables */ + ulong table_end_high; /* End address of high ACPI tables */ +#endif #if defined(CONFIG_FSL_ESDHC) u32 sdhc_per_clk; #endif diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h index d00247ad95..593d9276d3 100644 --- a/arch/riscv/include/asm/global_data.h +++ b/arch/riscv/include/asm/global_data.h @@ -33,6 +33,12 @@ struct arch_global_data { ulong available_harts; #endif #endif +#if CONFIG_IS_ENABLED(ACPI) + ulong table_start; /* Start address of ACPI tables */ + ulong table_end; /* End address of ACPI tables */ + ulong table_start_high; /* Start address of high ACPI tables */ + ulong table_end_high; /* End address of high ACPI tables */ +#endif #ifdef CONFIG_SMBIOS ulong smbios_start; /* Start address of SMBIOS table */ #endif diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h index 3c0a102697..a23bd64994 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/cpu/baytrail/acpi.c b/arch/x86/cpu/baytrail/acpi.c index 4378846f8b..ccc4851b18 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 9a2d682451..0e18ceab68 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 1c667c7d56..1d37cc9e2b 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 c5b33dc65d..5ecd3d4b65 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; @@ -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/board/emulation/configs/acpi.config b/board/emulation/configs/acpi.config new file mode 100644 index 0000000000..b7ed811e33 --- /dev/null +++ b/board/emulation/configs/acpi.config @@ -0,0 +1,3 @@ +CONFIG_CMD_QFW=y +CONFIG_ACPI=y +CONFIG_GENERATE_ACPI_TABLE=y diff --git a/board/emulation/qemu-arm/Kconfig b/board/emulation/qemu-arm/Kconfig index ac2d078f42..e21c135e86 100644 --- a/board/emulation/qemu-arm/Kconfig +++ b/board/emulation/qemu-arm/Kconfig @@ -5,6 +5,7 @@ config TEXT_BASE config BOARD_SPECIFIC_OPTIONS # dummy def_bool y + select QFW if ACPI select QFW_MMIO if CMD_QFW imply VIRTIO_MMIO imply VIRTIO_PCI diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig index cdd0d0d95f..d5f302ffda 100644 --- a/board/emulation/qemu-riscv/Kconfig +++ b/board/emulation/qemu-riscv/Kconfig @@ -33,6 +33,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy def_bool y select GENERIC_RISCV select SUPPORT_SPL + select QFW if ACPI + select QFW_MMIO if QFW imply AHCI imply SMP imply BOARD_LATE_INIT diff --git a/cmd/acpi.c b/cmd/acpi.c index 0c14409242..65caaa5c98 100644 --- a/cmd/acpi.c +++ b/cmd/acpi.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +46,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; @@ -53,10 +54,17 @@ 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)); - if (fadt->firmware_ctrl) - dump_hdr(map_sysmem(fadt->firmware_ctrl, 0)); + if (fadt->header.revision >= 3 && fadt->x_dsdt) + dump_hdr(nomap_sysmem(fadt->x_dsdt, 0)); + else if (fadt->dsdt) + dump_hdr(nomap_sysmem(fadt->dsdt, 0)); + if (!IS_ENABLED(CONFIG_X86) && + !(fadt->flags & ACPI_FADT_HW_REDUCED_ACPI)) + log_err("FADT not ACPI-hardware-reduced-compliant\n"); + if (fadt->header.revision >= 3 && fadt->x_firmware_ctrl) + dump_hdr(nomap_sysmem(fadt->x_firmware_ctrl, 0)); + else if (fadt->firmware_ctrl) + dump_hdr(nomap_sysmem(fadt->firmware_ctrl, 0)); } static void list_rsdt(struct acpi_rsdp *rsdp) @@ -66,11 +74,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 +99,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/doc/board/emulation/acpi.rst b/doc/board/emulation/acpi.rst new file mode 100644 index 0000000000..17b68e1b78 --- /dev/null +++ b/doc/board/emulation/acpi.rst @@ -0,0 +1,23 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +ACPI on QEMU +============ + +QEMU can provide ACPI tables on ARM, RISC-V (since QEMU v8.0.0), and x86. + +The following U-Boot settings are needed for ACPI support:: + + CONFIG_CMD_QFW=y + CONFIG_ACPI=y + CONFIG_GENERATE_ACPI_TABLE=y + +On x86 these settings are already included in the defconfig files. ARM and +RISC-V default to use device-trees. + +Instead of updating the configuration manually you can add the configuration +fragment `acpi.config` to the make command for initializing the configuration. +E.g. + +.. code-block:: bash + + make qemu-riscv64_smode_defconfig acpi.config diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst index 932c65adeb..d3d6b8f3d8 100644 --- a/doc/board/emulation/index.rst +++ b/doc/board/emulation/index.rst @@ -6,6 +6,7 @@ Emulation .. toctree:: :maxdepth: 1 + acpi blkdev ../../usage/semihosting qemu-arm diff --git a/doc/develop/devicetree/control.rst b/doc/develop/devicetree/control.rst index cbb65c9b17..11c92d440f 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/drivers/misc/Kconfig b/drivers/misc/Kconfig index ed7ecedd3a..e8e4400516 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -540,6 +540,13 @@ config QFW Hidden option to enable QEMU fw_cfg interface and uclass. This will be selected by either CONFIG_CMD_QFW or CONFIG_GENERATE_ACPI_TABLE. +config QFW_ACPI + bool + default y + depends on QFW && GENERATE_ACPI_TABLE && !SANDBOX + help + Hidden option to read ACPI tables from QEMU. + config QFW_PIO bool depends on QFW diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index b67b82358a..cda701d38e 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o ifdef CONFIG_QFW obj-y += qfw.o +obj-$(CONFIG_QFW_ACPI) += qfw_acpi.o obj-$(CONFIG_QFW_PIO) += qfw_pio.o obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o obj-$(CONFIG_SANDBOX) += qfw_sandbox.o diff --git a/drivers/misc/qfw.c b/drivers/misc/qfw.c index e3b6b4cd74..db98619fdf 100644 --- a/drivers/misc/qfw.c +++ b/drivers/misc/qfw.c @@ -21,246 +21,6 @@ #include #include -#if defined(CONFIG_GENERATE_ACPI_TABLE) && !defined(CONFIG_SANDBOX) -/* - * This function allocates memory for ACPI tables - * - * @entry : BIOS linker command entry which tells where to allocate memory - * (either high memory or low memory) - * @addr : The address that should be used for low memory allcation. If the - * memory allocation request is 'ZONE_HIGH' then this parameter will - * be ignored. - * @return: 0 on success, or negative value on failure - */ -static int bios_linker_allocate(struct udevice *dev, - struct bios_linker_entry *entry, ulong *addr) -{ - uint32_t size, align; - struct fw_file *file; - unsigned long aligned_addr; - - align = le32_to_cpu(entry->alloc.align); - /* align must be power of 2 */ - if (align & (align - 1)) { - printf("error: wrong alignment %u\n", align); - return -EINVAL; - } - - file = qfw_find_file(dev, entry->alloc.file); - if (!file) { - printf("error: can't find file %s\n", entry->alloc.file); - return -ENOENT; - } - - size = be32_to_cpu(file->cfg.size); - - /* - * ZONE_HIGH means we need to allocate from high memory, since - * malloc space is already at the end of RAM, so we directly use it. - * If allocation zone is ZONE_FSEG, then we use the 'addr' passed - * in which is low memory - */ - if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) { - aligned_addr = (unsigned long)memalign(align, size); - if (!aligned_addr) { - printf("error: allocating resource\n"); - return -ENOMEM; - } - if (aligned_addr < gd->arch.table_start_high) - gd->arch.table_start_high = aligned_addr; - if (aligned_addr + size > gd->arch.table_end_high) - gd->arch.table_end_high = aligned_addr + size; - - } else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) { - aligned_addr = ALIGN(*addr, align); - } else { - printf("error: invalid allocation zone\n"); - return -EINVAL; - } - - debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n", - file->cfg.name, size, entry->alloc.zone, align, aligned_addr); - - qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, - (void *)aligned_addr); - file->addr = aligned_addr; - - /* adjust address for low memory allocation */ - if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) - *addr = (aligned_addr + size); - - return 0; -} - -/* - * This function patches ACPI tables previously loaded - * by bios_linker_allocate() - * - * @entry : BIOS linker command entry which tells how to patch - * ACPI tables - * @return: 0 on success, or negative value on failure - */ -static int bios_linker_add_pointer(struct udevice *dev, - struct bios_linker_entry *entry) -{ - struct fw_file *dest, *src; - uint32_t offset = le32_to_cpu(entry->pointer.offset); - uint64_t pointer = 0; - - dest = qfw_find_file(dev, entry->pointer.dest_file); - if (!dest || !dest->addr) - return -ENOENT; - src = qfw_find_file(dev, entry->pointer.src_file); - if (!src || !src->addr) - return -ENOENT; - - debug("bios_linker_add_pointer: dest->addr 0x%lx, src->addr 0x%lx, offset 0x%x size %u, 0x%llx\n", - dest->addr, src->addr, offset, entry->pointer.size, pointer); - - memcpy(&pointer, (char *)dest->addr + offset, entry->pointer.size); - pointer = le64_to_cpu(pointer); - pointer += (unsigned long)src->addr; - pointer = cpu_to_le64(pointer); - memcpy((char *)dest->addr + offset, &pointer, entry->pointer.size); - - return 0; -} - -/* - * This function updates checksum fields of ACPI tables previously loaded - * by bios_linker_allocate() - * - * @entry : BIOS linker command entry which tells where to update ACPI table - * checksums - * @return: 0 on success, or negative value on failure - */ -static int bios_linker_add_checksum(struct udevice *dev, - struct bios_linker_entry *entry) -{ - struct fw_file *file; - uint8_t *data, cksum = 0; - uint8_t *cksum_start; - - file = qfw_find_file(dev, entry->cksum.file); - if (!file || !file->addr) - return -ENOENT; - - data = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.offset)); - cksum_start = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.start)); - cksum = table_compute_checksum(cksum_start, - le32_to_cpu(entry->cksum.length)); - *data = cksum; - - return 0; -} - -/* This function loads and patches ACPI tables provided by QEMU */ -ulong write_acpi_tables(ulong addr) -{ - int i, ret; - struct fw_file *file; - struct bios_linker_entry *table_loader; - struct bios_linker_entry *entry; - uint32_t size; - struct udevice *dev; - - ret = qfw_get_dev(&dev); - if (ret) { - printf("error: no qfw\n"); - return addr; - } - - /* make sure fw_list is loaded */ - ret = qfw_read_firmware_list(dev); - if (ret) { - printf("error: can't read firmware file list\n"); - return addr; - } - - file = qfw_find_file(dev, "etc/table-loader"); - if (!file) { - printf("error: can't find etc/table-loader\n"); - return addr; - } - - size = be32_to_cpu(file->cfg.size); - if ((size % sizeof(*entry)) != 0) { - printf("error: table-loader maybe corrupted\n"); - return addr; - } - - table_loader = malloc(size); - if (!table_loader) { - printf("error: no memory for table-loader\n"); - return addr; - } - - /* QFW always puts tables at high addresses */ - gd->arch.table_start_high = (ulong)table_loader; - gd->arch.table_end_high = (ulong)table_loader; - - qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader); - - for (i = 0; i < (size / sizeof(*entry)); i++) { - entry = table_loader + i; - switch (le32_to_cpu(entry->command)) { - case BIOS_LINKER_LOADER_COMMAND_ALLOCATE: - ret = bios_linker_allocate(dev, entry, &addr); - if (ret) - goto out; - break; - case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER: - ret = bios_linker_add_pointer(dev, entry); - if (ret) - goto out; - break; - case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM: - ret = bios_linker_add_checksum(dev, entry); - if (ret) - goto out; - break; - default: - break; - } - } - -out: - if (ret) { - struct fw_cfg_file_iter iter; - for (file = qfw_file_iter_init(dev, &iter); - !qfw_file_iter_end(&iter); - file = qfw_file_iter_next(&iter)) { - if (file->addr) { - free((void *)file->addr); - file->addr = 0; - } - } - } - - free(table_loader); - - gd_set_acpi_start(acpi_get_rsdp_addr()); - - return addr; -} - -ulong acpi_get_rsdp_addr(void) -{ - int ret; - struct fw_file *file; - struct udevice *dev; - - ret = qfw_get_dev(&dev); - if (ret) { - printf("error: no qfw\n"); - return 0; - } - - file = qfw_find_file(dev, "etc/acpi/rsdp"); - return file->addr; -} -#endif - static void qfw_read_entry_io(struct qfw_dev *qdev, u16 entry, u32 size, void *address) { diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c new file mode 100644 index 0000000000..7ffed1e8c0 --- /dev/null +++ b/drivers/misc/qfw_acpi.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2015 Miao Yan + * (C) Copyright 2021 Asherah Connor + */ + +#define LOG_CATEGORY UCLASS_QFW + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* + * This function allocates memory for ACPI tables + * + * @entry : BIOS linker command entry which tells where to allocate memory + * (either high memory or low memory) + * @addr : The address that should be used for low memory allcation. If the + * memory allocation request is 'ZONE_HIGH' then this parameter will + * be ignored. + * @return: 0 on success, or negative value on failure + */ +static int bios_linker_allocate(struct udevice *dev, + struct bios_linker_entry *entry, ulong *addr) +{ + uint32_t size, align; + struct fw_file *file; + unsigned long aligned_addr; + + align = le32_to_cpu(entry->alloc.align); + /* align must be power of 2 */ + if (align & (align - 1)) { + printf("error: wrong alignment %u\n", align); + return -EINVAL; + } + + file = qfw_find_file(dev, entry->alloc.file); + if (!file) { + printf("error: can't find file %s\n", entry->alloc.file); + return -ENOENT; + } + + size = be32_to_cpu(file->cfg.size); + + /* + * ZONE_HIGH means we need to allocate from high memory, since + * malloc space is already at the end of RAM, so we directly use it. + * If allocation zone is ZONE_FSEG, then we use the 'addr' passed + * in which is low memory + */ + if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_HIGH) { + aligned_addr = (unsigned long)memalign(align, size); + if (!aligned_addr) { + printf("error: allocating resource\n"); + return -ENOMEM; + } + if (aligned_addr < gd->arch.table_start_high) + gd->arch.table_start_high = aligned_addr; + if (aligned_addr + size > gd->arch.table_end_high) + gd->arch.table_end_high = aligned_addr + size; + + } else if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) { + aligned_addr = ALIGN(*addr, align); + } else { + printf("error: invalid allocation zone\n"); + return -EINVAL; + } + + debug("bios_linker_allocate: allocate file %s, size %u, zone %d, align %u, addr 0x%lx\n", + file->cfg.name, size, entry->alloc.zone, align, aligned_addr); + + qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, + (void *)aligned_addr); + file->addr = aligned_addr; + + /* adjust address for low memory allocation */ + if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG) + *addr = (aligned_addr + size); + + return 0; +} + +/* + * This function patches ACPI tables previously loaded + * by bios_linker_allocate() + * + * @entry : BIOS linker command entry which tells how to patch + * ACPI tables + * @return: 0 on success, or negative value on failure + */ +static int bios_linker_add_pointer(struct udevice *dev, + struct bios_linker_entry *entry) +{ + struct fw_file *dest, *src; + uint32_t offset = le32_to_cpu(entry->pointer.offset); + uint64_t pointer = 0; + + dest = qfw_find_file(dev, entry->pointer.dest_file); + if (!dest || !dest->addr) + return -ENOENT; + src = qfw_find_file(dev, entry->pointer.src_file); + if (!src || !src->addr) + return -ENOENT; + + debug("bios_linker_add_pointer: dest->addr 0x%lx, src->addr 0x%lx, offset 0x%x size %u, 0x%llx\n", + dest->addr, src->addr, offset, entry->pointer.size, pointer); + + memcpy(&pointer, (char *)dest->addr + offset, entry->pointer.size); + pointer = le64_to_cpu(pointer); + pointer += (unsigned long)src->addr; + pointer = cpu_to_le64(pointer); + memcpy((char *)dest->addr + offset, &pointer, entry->pointer.size); + + return 0; +} + +/* + * This function updates checksum fields of ACPI tables previously loaded + * by bios_linker_allocate() + * + * @entry : BIOS linker command entry which tells where to update ACPI table + * checksums + * @return: 0 on success, or negative value on failure + */ +static int bios_linker_add_checksum(struct udevice *dev, + struct bios_linker_entry *entry) +{ + struct fw_file *file; + uint8_t *data, cksum = 0; + uint8_t *cksum_start; + + file = qfw_find_file(dev, entry->cksum.file); + if (!file || !file->addr) + return -ENOENT; + + data = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.offset)); + cksum_start = (uint8_t *)(file->addr + le32_to_cpu(entry->cksum.start)); + cksum = table_compute_checksum(cksum_start, + le32_to_cpu(entry->cksum.length)); + *data = cksum; + + return 0; +} + +/* This function loads and patches ACPI tables provided by QEMU */ +ulong write_acpi_tables(ulong addr) +{ + int i, ret; + struct fw_file *file; + struct bios_linker_entry *table_loader; + struct bios_linker_entry *entry; + uint32_t size; + struct udevice *dev; + + ret = qfw_get_dev(&dev); + if (ret) { + printf("error: no qfw\n"); + return addr; + } + + /* make sure fw_list is loaded */ + ret = qfw_read_firmware_list(dev); + if (ret) { + printf("error: can't read firmware file list\n"); + return addr; + } + + file = qfw_find_file(dev, "etc/table-loader"); + if (!file) { + printf("error: can't find etc/table-loader\n"); + return addr; + } + + size = be32_to_cpu(file->cfg.size); + if ((size % sizeof(*entry)) != 0) { + printf("error: table-loader maybe corrupted\n"); + return addr; + } + + table_loader = malloc(size); + if (!table_loader) { + printf("error: no memory for table-loader\n"); + return addr; + } + + /* QFW always puts tables at high addresses */ + gd->arch.table_start_high = (ulong)table_loader; + gd->arch.table_end_high = (ulong)table_loader; + + qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader); + + for (i = 0; i < (size / sizeof(*entry)); i++) { + entry = table_loader + i; + switch (le32_to_cpu(entry->command)) { + case BIOS_LINKER_LOADER_COMMAND_ALLOCATE: + ret = bios_linker_allocate(dev, entry, &addr); + if (ret) + goto out; + break; + case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER: + ret = bios_linker_add_pointer(dev, entry); + if (ret) + goto out; + break; + case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM: + ret = bios_linker_add_checksum(dev, entry); + if (ret) + goto out; + break; + default: + break; + } + } + +out: + if (ret) { + struct fw_cfg_file_iter iter; + for (file = qfw_file_iter_init(dev, &iter); + !qfw_file_iter_end(&iter); + file = qfw_file_iter_next(&iter)) { + if (file->addr) { + free((void *)file->addr); + file->addr = 0; + } + } + } + + free(table_loader); + + gd_set_acpi_start(acpi_get_rsdp_addr()); + + return addr; +} + +ulong acpi_get_rsdp_addr(void) +{ + int ret; + struct fw_file *file; + struct udevice *dev; + + ret = qfw_get_dev(&dev); + if (ret) { + printf("error: no qfw\n"); + return 0; + } + + file = qfw_find_file(dev, "etc/acpi/rsdp"); + return file->addr; +} + +#ifndef CONFIG_X86 +static int evt_write_acpi_tables(void) +{ + ulong addr, end; + void *ptr; + + /* Reserve 64K for ACPI tables, aligned to a 4K boundary */ + ptr = memalign(SZ_4K, SZ_64K); + if (!ptr) + return -ENOMEM; + addr = map_to_sysmem(ptr); + + /* Generate ACPI tables */ + end = write_acpi_tables(addr); + gd->arch.table_start = addr; + gd->arch.table_end = addr; + + return 0; +} + +EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, evt_write_acpi_tables); +#endif diff --git a/include/acpi/acpi_table.h b/include/acpi/acpi_table.h index 20ac3b51ba..e67562ef65 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; diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 99bde9ec7e..fcc3c6e14c 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/include/efi_api.h b/include/efi_api.h index 0e92cb8a7f..ab40b1b5dd 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/include/fdtdec.h b/include/fdtdec.h index bd1149f46d..e80de24076 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/include/mapmem.h b/include/mapmem.h index bb68b4c11a..f496c96d16 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/include/smbios.h b/include/smbios.h index c9df2706f5..49de32fec2 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 */ @@ -54,6 +54,36 @@ 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; +}; + +/* 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) @@ -228,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/acpi/Makefile b/lib/acpi/Makefile index c1c9675b5d..cc2868488a 100644 --- a/lib/acpi/Makefile +++ b/lib/acpi/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_$(SPL_)ACPIGEN) += acpi_table.o obj-y += acpi_writer.o # With QEMU the ACPI tables come from there, not from U-Boot -ifndef CONFIG_QEMU +ifndef CONFIG_QFW_ACPI obj-y += base.o obj-y += csrt.o obj-y += mcfg.o diff --git a/lib/acpi/acpi.c b/lib/acpi/acpi.c index 939a638bb5..f4d5c1e25d 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,38 @@ 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); - if (!memcmp(sig, "FACS", ACPI_NAME_LEN) && - fadt->firmware_ctrl) - return map_sysmem(fadt->firmware_ctrl, 0); + if (!memcmp(sig, "DSDT", ACPI_NAME_LEN)) { + void *dsdt; + + if (fadt->header.revision >= 3 && fadt->x_dsdt) + dsdt = nomap_sysmem(fadt->x_dsdt, 0); + else if (fadt->dsdt) + dsdt = nomap_sysmem(fadt->dsdt, 0); + else + dsdt = NULL; + return dsdt; + } + + if (!memcmp(sig, "FACS", ACPI_NAME_LEN)) { + void *facs; + + if (fadt->header.revision >= 3 && + fadt->x_firmware_ctrl) + facs = nomap_sysmem(fadt->x_firmware_ctrl, 0); + else if (fadt->firmware_ctrl) + facs = nomap_sysmem(fadt->firmware_ctrl, 0); + else + facs = NULL; + return facs; + } } } diff --git a/lib/acpi/acpi_table.c b/lib/acpi/acpi_table.c index e74522e997..39dd53ec40 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/acpi_writer.c b/lib/acpi/acpi_writer.c index a8dc207557..bbb9b54786 100644 --- a/lib/acpi/acpi_writer.c +++ b/lib/acpi/acpi_writer.c @@ -48,7 +48,7 @@ int acpi_write_one(struct acpi_ctx *ctx, const struct acpi_writer *entry) return 0; } -#ifndef CONFIG_QEMU +#ifndef CONFIG_QFW_ACPI static int acpi_write_all(struct acpi_ctx *ctx) { const struct acpi_writer *writer = @@ -115,7 +115,7 @@ ulong acpi_get_rsdp_addr(void) return map_to_sysmem(gd->acpi_ctx->rsdp); } -#endif /* QEMU */ +#endif /* QFW_ACPI */ void acpi_setup_ctx(struct acpi_ctx *ctx, ulong start) { diff --git a/lib/acpi/base.c b/lib/acpi/base.c index 07b53e0c56..8b6af2bc43 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/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c index bbb8421ce1..eb6d2ba43c 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, }; @@ -27,8 +29,9 @@ efi_status_t efi_smbios_register(void) { ulong addr; efi_status_t ret; + void *buf; - addr = gd->arch.smbios_start; + addr = gd_smbios_start(); if (!addr) { log_err("No SMBIOS tables to install\n"); return EFI_NOT_FOUND; @@ -42,33 +45,34 @@ 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); + ret = efi_install_configuration_table(&smbios3_guid, buf); + unmap_sysmem(buf); + + return ret; } static int install_smbios_table(void) { - u64 addr; - efi_status_t ret; + ulong addr; + void *buf; if (!IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE) || IS_ENABLED(CONFIG_X86)) return 0; - addr = SZ_4G; - ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, - efi_size_in_pages(TABLE_SIZE), &addr); - if (ret != EFI_SUCCESS) + /* Align the table to a 4KB boundary to keep EFI happy */ + buf = memalign(SZ_4K, TABLE_SIZE); + if (!buf) return log_msg_ret("mem", -ENOMEM); - addr = map_to_sysmem((void *)(uintptr_t)addr); + addr = map_to_sysmem(buf); if (!write_smbios_table(addr)) { log_err("Failed to write SMBIOS table\n"); return log_msg_ret("smbios", -EINVAL); } /* Make a note of where we put it */ - log_debug("SMBIOS tables written to %llx\n", addr); + log_debug("SMBIOS tables written to %lx\n", addr); gd->arch.smbios_start = addr; return 0; diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 4016bf3c11..b2c59ab381 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; - /* 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; + /* 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; + } + } + } + + /* 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 */ diff --git a/lib/smbios.c b/lib/smbios.c index 45480b01af..d9d52bd58d 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -544,15 +544,13 @@ static struct smbios_write_method smbios_write_funcs[] = { ulong write_smbios_table(ulong addr) { ofnode parent_node = ofnode_null(); - struct smbios_entry *se; + ulong table_addr, start_addr; + struct smbios3_entry *se; struct smbios_ctx ctx; - ulong table_addr; ulong tables; int len = 0; int max_struct_size = 0; int handle = 0; - char *istart; - int isize; int i; ctx.node = ofnode_null(); @@ -564,14 +562,10 @@ ulong write_smbios_table(ulong addr) ctx.dev = NULL; } - /* 16 byte align the table address */ - addr = ALIGN(addr, 16); + start_addr = addr; - se = map_sysmem(addr, sizeof(struct smbios_entry)); - memset(se, 0, sizeof(struct smbios_entry)); - - addr += sizeof(struct smbios_entry); - addr = ALIGN(addr, 16); + /* move past the (so-far-unwritten) header to start writing structs */ + addr = ALIGN(addr + sizeof(struct smbios3_entry), 16); tables = addr; /* populate minimum required tables */ @@ -589,40 +583,25 @@ ulong write_smbios_table(ulong addr) len += tmp; } - memcpy(se->anchor, "_SM_", 4); - se->length = sizeof(struct smbios_entry); - se->major_ver = SMBIOS_MAJOR_VER; - se->minor_ver = SMBIOS_MINOR_VER; - se->max_struct_size = max_struct_size; - memcpy(se->intermediate_anchor, "_DMI_", 5); - se->struct_table_length = len; - /* * 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. */ table_addr = (ulong)map_sysmem(tables, 0); - if (sizeof(table_addr) > sizeof(u32) && table_addr > (ulong)UINT_MAX) { - /* - * 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; - goto out; - } + + /* now go back and write the SMBIOS3 header */ + 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->struct_count = handle; - - /* calculate checksums */ - istart = (char *)se + SMBIOS_INTERMEDIATE_OFFSET; - isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET; - se->intermediate_checksum = table_compute_checksum(istart, isize); - se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry)); -out: + se->checksum = table_compute_checksum(se, sizeof(struct smbios3_entry)); unmap_sysmem(se); return addr; diff --git a/test/dm/acpi.c b/test/dm/acpi.c index fb071902b4..c53ebcdb1c 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]); @@ -330,7 +330,7 @@ static int dm_test_acpi_basic(struct unit_test_state *uts) DM_TEST(dm_test_acpi_basic, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); /* Test setup_ctx_and_base_tables */ -static int dm_test_setup_ctx_and_base_tables(struct unit_test_state *uts) +static int dm_test_acpi_ctx_and_base_tables(struct unit_test_state *uts) { struct acpi_rsdp *rsdp; struct acpi_rsdt *rsdt; @@ -371,12 +371,12 @@ static int dm_test_setup_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; } -DM_TEST(dm_test_setup_ctx_and_base_tables, +DM_TEST(dm_test_acpi_ctx_and_base_tables, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); /* Test 'acpi list' command */ @@ -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();