switch to SMBIOS3 tables

allow devicetree from bloblist
 ACPI support for ARM and RISC-V
 -----BEGIN PGP SIGNATURE-----
 
 iQFFBAABCgAvFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAmWbPygRHHNqZ0BjaHJv
 bWl1bS5vcmcACgkQfxc6PpAIrebFRQf+MS1t+wtPFz9Y8i7zBrEV1+fpPOp8XhJ5
 m7uCkCDYO1oYShI1ht6X1nzvprElk/J9ZWTUg2IXOFzSaaBiPrylcc5bDjkd2F7A
 FxqXn2oqKPIXYoZsJgVS2ua5m5pQbZk9ahX5NWzQV8xLMNjgK6BvCUX3zQsLtS1C
 jo3ly+G+FlnFZ187qqxzIQiVkRX6p/U+JLERsgfy9q0Fic5drBydQ3F8UjMdORq2
 NxxxjOl76vC+9O2A+XXC2c/1EiXR/DK2Mtz+lxA/d5/ZDrepp1bnJUjdV5qD4LdX
 +ZuwJBdctrlK0piOIJuAR7YjpNfxeUJl6L9l/3Hg2X3P8U84V0zqiA==
 =AD87
 -----END PGP SIGNATURE-----

Merge tag 'dm-next-7jan23' of https://source.denx.de/u-boot/custodians/u-boot-dm into next

switch to SMBIOS3 tables
allow devicetree from bloblist
ACPI support for ARM and RISC-V
This commit is contained in:
Tom Rini 2024-01-08 09:11:53 -05:00
commit f28a77589e
35 changed files with 556 additions and 372 deletions

View File

@ -53,6 +53,7 @@ Maintainers List (try to look for most precise areas first)
ACPI: ACPI:
M: Simon Glass <sjg@chromium.org> M: Simon Glass <sjg@chromium.org>
S: Maintained S: Maintained
F: board/emulation/configs/acpi.config
F: cmd/acpi.c F: cmd/acpi.c
F: lib/acpi/ F: lib/acpi/

View File

@ -108,6 +108,7 @@ config PPC
config RISCV config RISCV
bool "RISC-V architecture" bool "RISC-V architecture"
select CREATE_ARCH_SYMLINK select CREATE_ARCH_SYMLINK
select SUPPORT_ACPI
select SUPPORT_OF_CONTROL select SUPPORT_OF_CONTROL
select OF_CONTROL select OF_CONTROL
select DM select DM

View File

@ -18,7 +18,12 @@ struct arch_global_data {
#if defined(CONFIG_FSL_ESDHC) || defined(CONFIG_FSL_ESDHC_IMX) #if defined(CONFIG_FSL_ESDHC) || defined(CONFIG_FSL_ESDHC_IMX)
u32 sdhc_clk; u32 sdhc_clk;
#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
#if defined(CONFIG_FSL_ESDHC) #if defined(CONFIG_FSL_ESDHC)
u32 sdhc_per_clk; u32 sdhc_per_clk;
#endif #endif

View File

@ -33,6 +33,12 @@ struct arch_global_data {
ulong available_harts; ulong available_harts;
#endif #endif
#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 #ifdef CONFIG_SMBIOS
ulong smbios_start; /* Start address of SMBIOS table */ ulong smbios_start; /* Start address of SMBIOS table */
#endif #endif

View File

@ -231,5 +231,21 @@ static inline void unmap_sysmem(const void *vaddr)
unmap_physmem(vaddr, MAP_WRBACK); 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 #endif

View File

@ -7,6 +7,7 @@
#include <cpu.h> #include <cpu.h>
#include <dm.h> #include <dm.h>
#include <log.h> #include <log.h>
#include <mapmem.h>
#include <acpi/acpi_s3.h> #include <acpi/acpi_s3.h>
#include <acpi/acpi_table.h> #include <acpi/acpi_table.h>
#include <asm/io.h> #include <asm/io.h>
@ -31,8 +32,6 @@ static int baytrail_write_fadt(struct acpi_ctx *ctx,
header->length = sizeof(struct acpi_fadt); header->length = sizeof(struct acpi_fadt);
header->revision = 4; header->revision = 4;
fadt->firmware_ctrl = (u32)ctx->facs;
fadt->dsdt = (u32)ctx->dsdt;
fadt->preferred_pm_profile = ACPI_PM_MOBILE; fadt->preferred_pm_profile = ACPI_PM_MOBILE;
fadt->sci_int = 9; fadt->sci_int = 9;
fadt->smi_cmd = 0; fadt->smi_cmd = 0;
@ -79,10 +78,8 @@ static int baytrail_write_fadt(struct acpi_ctx *ctx,
fadt->reset_reg.addrh = 0; fadt->reset_reg.addrh = 0;
fadt->reset_value = SYS_RST | RST_CPU | FULL_RST; fadt->reset_value = SYS_RST | RST_CPU | FULL_RST;
fadt->x_firmware_ctl_l = (u32)ctx->facs; fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs);
fadt->x_firmware_ctl_h = 0; fadt->x_dsdt = map_to_sysmem(ctx->dsdt);
fadt->x_dsdt_l = (u32)ctx->dsdt;
fadt->x_dsdt_h = 0;
fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8;

View File

@ -4,6 +4,7 @@
*/ */
#include <common.h> #include <common.h>
#include <mapmem.h>
#include <acpi/acpi_table.h> #include <acpi/acpi_table.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/tables.h> #include <asm/tables.h>
@ -26,8 +27,6 @@ static int quark_write_fadt(struct acpi_ctx *ctx,
header->length = sizeof(struct acpi_fadt); header->length = sizeof(struct acpi_fadt);
header->revision = 4; header->revision = 4;
fadt->firmware_ctrl = (u32)ctx->facs;
fadt->dsdt = (u32)ctx->dsdt;
fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED; fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED;
fadt->sci_int = 9; fadt->sci_int = 9;
fadt->smi_cmd = 0; fadt->smi_cmd = 0;
@ -74,10 +73,8 @@ static int quark_write_fadt(struct acpi_ctx *ctx,
fadt->reset_reg.addrh = 0; fadt->reset_reg.addrh = 0;
fadt->reset_value = SYS_RST | RST_CPU | FULL_RST; fadt->reset_value = SYS_RST | RST_CPU | FULL_RST;
fadt->x_firmware_ctl_l = (u32)ctx->facs; fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs);
fadt->x_firmware_ctl_h = 0; fadt->x_dsdt = map_to_sysmem(ctx->dsdt);
fadt->x_dsdt_l = (u32)ctx->dsdt;
fadt->x_dsdt_h = 0;
fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO; fadt->x_pm1a_evt_blk.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8; fadt->x_pm1a_evt_blk.bit_width = fadt->pm1_evt_len * 8;

View File

@ -8,6 +8,7 @@
#include <common.h> #include <common.h>
#include <cpu.h> #include <cpu.h>
#include <dm.h> #include <dm.h>
#include <mapmem.h>
#include <acpi/acpi_table.h> #include <acpi/acpi_table.h>
#include <asm/ioapic.h> #include <asm/ioapic.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
@ -31,8 +32,6 @@ static int tangier_write_fadt(struct acpi_ctx *ctx,
header->length = sizeof(struct acpi_fadt); header->length = sizeof(struct acpi_fadt);
header->revision = 6; header->revision = 6;
fadt->firmware_ctrl = (u32)ctx->facs;
fadt->dsdt = (u32)ctx->dsdt;
fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED; fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED;
fadt->iapc_boot_arch = ACPI_FADT_VGA_NOT_PRESENT | 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->minor_revision = 2;
fadt->x_firmware_ctl_l = (u32)ctx->facs; fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs);
fadt->x_firmware_ctl_h = 0; fadt->x_dsdt = map_to_sysmem(ctx->dsdt);
fadt->x_dsdt_l = (u32)ctx->dsdt;
fadt->x_dsdt_h = 0;
header->checksum = table_compute_checksum(fadt, header->length); header->checksum = table_compute_checksum(fadt, header->length);

View File

@ -197,7 +197,7 @@ int acpi_write_tcpa(struct acpi_ctx *ctx, const struct acpi_writer *entry)
tcpa->platform_class = 0; tcpa->platform_class = 0;
tcpa->laml = size; tcpa->laml = size;
tcpa->lasa = map_to_sysmem(log); tcpa->lasa = nomap_to_sysmem(log);
/* (Re)calculate length and checksum */ /* (Re)calculate length and checksum */
current = (u32)tcpa + sizeof(struct acpi_tcpa); 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. */ /* Fill the log area size and start address fields. */
tpm2->laml = tpm2_log_len; tpm2->laml = tpm2_log_len;
tpm2->lasa = map_to_sysmem(lasa); tpm2->lasa = nomap_to_sysmem(lasa);
/* Calculate checksum. */ /* Calculate checksum. */
header->checksum = table_compute_checksum(tpm2, header->length); 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); u32 *gnvs = (u32 *)((u32)ctx->dsdt + i);
if (*gnvs == ACPI_GNVS_ADDR) { 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", log_debug("Fix up global NVS in DSDT to %#08x\n",
*gnvs); *gnvs);
break; break;
@ -572,13 +572,8 @@ void acpi_fadt_common(struct acpi_fadt *fadt, struct acpi_facs *facs,
memcpy(header->aslc_id, ASLC_ID, 4); memcpy(header->aslc_id, ASLC_ID, 4);
header->aslc_revision = 1; header->aslc_revision = 1;
fadt->firmware_ctrl = (unsigned long)facs; fadt->x_firmware_ctrl = map_to_sysmem(facs);
fadt->dsdt = (unsigned long)dsdt; fadt->x_dsdt = map_to_sysmem(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->preferred_pm_profile = ACPI_PM_MOBILE; fadt->preferred_pm_profile = ACPI_PM_MOBILE;

View File

@ -0,0 +1,3 @@
CONFIG_CMD_QFW=y
CONFIG_ACPI=y
CONFIG_GENERATE_ACPI_TABLE=y

View File

@ -5,6 +5,7 @@ config TEXT_BASE
config BOARD_SPECIFIC_OPTIONS # dummy config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y def_bool y
select QFW if ACPI
select QFW_MMIO if CMD_QFW select QFW_MMIO if CMD_QFW
imply VIRTIO_MMIO imply VIRTIO_MMIO
imply VIRTIO_PCI imply VIRTIO_PCI

View File

@ -33,6 +33,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy
def_bool y def_bool y
select GENERIC_RISCV select GENERIC_RISCV
select SUPPORT_SPL select SUPPORT_SPL
select QFW if ACPI
select QFW_MMIO if QFW
imply AHCI imply AHCI
imply SMP imply SMP
imply BOARD_LATE_INIT imply BOARD_LATE_INIT

View File

@ -6,6 +6,7 @@
#include <common.h> #include <common.h>
#include <command.h> #include <command.h>
#include <display_options.h> #include <display_options.h>
#include <log.h>
#include <mapmem.h> #include <mapmem.h>
#include <acpi/acpi_table.h> #include <acpi/acpi_table.h>
#include <asm/acpi_table.h> #include <asm/acpi_table.h>
@ -45,7 +46,7 @@ static int dump_table_name(const char *sig)
if (!hdr) if (!hdr)
return -ENOENT; return -ENOENT;
printf("%.*s @ %16lx\n", ACPI_NAME_LEN, hdr->signature, 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); print_buffer(0, hdr, 1, hdr->length, 0);
return 0; return 0;
@ -53,10 +54,17 @@ static int dump_table_name(const char *sig)
static void list_fadt(struct acpi_fadt *fadt) static void list_fadt(struct acpi_fadt *fadt)
{ {
if (fadt->dsdt) if (fadt->header.revision >= 3 && fadt->x_dsdt)
dump_hdr(map_sysmem(fadt->dsdt, 0)); dump_hdr(nomap_sysmem(fadt->x_dsdt, 0));
if (fadt->firmware_ctrl) else if (fadt->dsdt)
dump_hdr(map_sysmem(fadt->firmware_ctrl, 0)); 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) static void list_rsdt(struct acpi_rsdp *rsdp)
@ -66,11 +74,11 @@ static void list_rsdt(struct acpi_rsdp *rsdp)
struct acpi_xsdt *xsdt; struct acpi_xsdt *xsdt;
if (rsdp->rsdt_address) { if (rsdp->rsdt_address) {
rsdt = map_sysmem(rsdp->rsdt_address, 0); rsdt = nomap_sysmem(rsdp->rsdt_address, 0);
dump_hdr(&rsdt->header); dump_hdr(&rsdt->header);
} }
if (rsdp->xsdt_address) { if (rsdp->xsdt_address) {
xsdt = map_sysmem(rsdp->xsdt_address, 0); xsdt = nomap_sysmem(rsdp->xsdt_address, 0);
dump_hdr(&xsdt->header); dump_hdr(&xsdt->header);
len = xsdt->header.length - sizeof(xsdt->header); len = xsdt->header.length - sizeof(xsdt->header);
count = len / sizeof(u64); count = len / sizeof(u64);
@ -91,7 +99,7 @@ static void list_rsdt(struct acpi_rsdp *rsdp)
entry = rsdt->entry[i]; entry = rsdt->entry[i];
if (!entry) if (!entry)
break; break;
hdr = map_sysmem(entry, 0); hdr = nomap_sysmem(entry, 0);
dump_hdr(hdr); dump_hdr(hdr);
if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN))
list_fadt((struct acpi_fadt *)hdr); list_fadt((struct acpi_fadt *)hdr);

View File

@ -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

View File

@ -6,6 +6,7 @@ Emulation
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
acpi
blkdev blkdev
../../usage/semihosting ../../usage/semihosting
qemu-arm qemu-arm

View File

@ -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 devicetree at runtime, for example if an earlier bootloader stage creates
it and passes it to U-Boot. 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 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 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. default and -T for the test devicetree, used to run sandbox unit tests.

View File

@ -540,6 +540,13 @@ config QFW
Hidden option to enable QEMU fw_cfg interface and uclass. This will Hidden option to enable QEMU fw_cfg interface and uclass. This will
be selected by either CONFIG_CMD_QFW or CONFIG_GENERATE_ACPI_TABLE. 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 config QFW_PIO
bool bool
depends on QFW depends on QFW

View File

@ -63,6 +63,7 @@ obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
ifdef CONFIG_QFW ifdef CONFIG_QFW
obj-y += qfw.o obj-y += qfw.o
obj-$(CONFIG_QFW_ACPI) += qfw_acpi.o
obj-$(CONFIG_QFW_PIO) += qfw_pio.o obj-$(CONFIG_QFW_PIO) += qfw_pio.o
obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o obj-$(CONFIG_QFW_MMIO) += qfw_mmio.o
obj-$(CONFIG_SANDBOX) += qfw_sandbox.o obj-$(CONFIG_SANDBOX) += qfw_sandbox.o

View File

@ -21,246 +21,6 @@
#include <tables_csum.h> #include <tables_csum.h>
#include <asm/acpi_table.h> #include <asm/acpi_table.h>
#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, static void qfw_read_entry_io(struct qfw_dev *qdev, u16 entry, u32 size,
void *address) void *address)
{ {

281
drivers/misc/qfw_acpi.c Normal file
View File

@ -0,0 +1,281 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
* (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
*/
#define LOG_CATEGORY UCLASS_QFW
#include <acpi/acpi_table.h>
#include <errno.h>
#include <malloc.h>
#include <mapmem.h>
#include <qfw.h>
#include <tables_csum.h>
#include <stdio.h>
#include <linux/sizes.h>
#include <asm/byteorder.h>
#include <asm/global_data.h>
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

View File

@ -228,10 +228,8 @@ struct __packed acpi_fadt {
u8 reset_value; u8 reset_value;
u16 arm_boot_arch; u16 arm_boot_arch;
u8 minor_revision; u8 minor_revision;
u32 x_firmware_ctl_l; u64 x_firmware_ctrl;
u32 x_firmware_ctl_h; u64 x_dsdt;
u32 x_dsdt_l;
u32 x_dsdt_h;
struct acpi_gen_regaddr x_pm1a_evt_blk; struct acpi_gen_regaddr x_pm1a_evt_blk;
struct acpi_gen_regaddr x_pm1b_evt_blk; struct acpi_gen_regaddr x_pm1b_evt_blk;
struct acpi_gen_regaddr x_pm1a_cnt_blk; struct acpi_gen_regaddr x_pm1a_cnt_blk;

View File

@ -553,7 +553,7 @@ static_assert(sizeof(struct global_data) == GD_SIZE);
#endif #endif
#ifdef CONFIG_SMBIOS #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 #define gd_set_smbios_start(addr) gd->arch.smbios_start = addr
#else #else
#define gd_smbios_start() 0UL #define gd_smbios_start() 0UL

View File

@ -433,6 +433,10 @@ struct efi_runtime_services {
EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \ EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, \
0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) 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 \ #define EFI_LOAD_FILE_PROTOCOL_GUID \
EFI_GUID(0x56ec3091, 0x954c, 0x11d2, \ EFI_GUID(0x56ec3091, 0x954c, 0x11d2, \
0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)

View File

@ -72,7 +72,7 @@ struct bd_info;
* U-Boot is packaged as an ELF file, e.g. for debugging purposes * U-Boot is packaged as an ELF file, e.g. for debugging purposes
* @FDTSRC_ENV: Provided by the fdtcontroladdr environment variable. This should * @FDTSRC_ENV: Provided by the fdtcontroladdr environment variable. This should
* be used for debugging/development only * 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 { enum fdt_source_t {
FDTSRC_SEPARATE, FDTSRC_SEPARATE,
@ -80,6 +80,7 @@ enum fdt_source_t {
FDTSRC_BOARD, FDTSRC_BOARD,
FDTSRC_EMBED, FDTSRC_EMBED,
FDTSRC_ENV, FDTSRC_ENV,
FDTSRC_BLOBLIST,
}; };
/* /*
@ -1190,7 +1191,8 @@ int fdtdec_resetup(int *rescan);
* *
* The existing devicetree is available at gd->fdt_blob * 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 * @returns new devicetree blob pointer
*/ */
void *board_fdt_blob_setup(int *err); void *board_fdt_blob_setup(int *err);

View File

@ -28,6 +28,24 @@ static inline phys_addr_t map_to_sysmem(const void *ptr)
{ {
return (phys_addr_t)(uintptr_t)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
#endif /* __MAPMEM_H */ #endif /* __MAPMEM_H */

View File

@ -12,7 +12,7 @@
/* SMBIOS spec version implemented */ /* SMBIOS spec version implemented */
#define SMBIOS_MAJOR_VER 3 #define SMBIOS_MAJOR_VER 3
#define SMBIOS_MINOR_VER 0 #define SMBIOS_MINOR_VER 7
enum { enum {
SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */ SMBIOS_STR_MAX = 64, /* Maximum length allowed for a string */
@ -54,6 +54,36 @@ struct __packed smbios_entry {
u8 bcd_rev; 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 */ /* BIOS characteristics */
#define BIOS_CHARACTERISTICS_PCI_SUPPORTED (1 << 7) #define BIOS_CHARACTERISTICS_PCI_SUPPORTED (1 << 7)
#define BIOS_CHARACTERISTICS_UPGRADEABLE (1 << 11) #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. * This writes SMBIOS table at a given address.
* *
* @addr: start address to write SMBIOS table. If this is not * @addr: start address to write SMBIOS table, 16-byte-alignment
* 16-byte-aligned then it will be aligned before the table is * recommended. Note that while the SMBIOS tables themself have no alignment
* written. * 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) * Return: end address of SMBIOS table (and start address for next entry)
* or NULL in case of an error * or NULL in case of an error
*
*/ */
ulong write_smbios_table(ulong addr); ulong write_smbios_table(ulong addr);

View File

@ -12,7 +12,7 @@ obj-$(CONFIG_$(SPL_)ACPIGEN) += acpi_table.o
obj-y += acpi_writer.o obj-y += acpi_writer.o
# With QEMU the ACPI tables come from there, not from U-Boot # 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 += base.o
obj-y += csrt.o obj-y += csrt.o
obj-y += mcfg.o obj-y += mcfg.o

View File

@ -22,13 +22,13 @@ struct acpi_table_header *acpi_find_table(const char *sig)
if (!rsdp) if (!rsdp)
return NULL; return NULL;
if (rsdp->xsdt_address) { 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); len = xsdt->header.length - sizeof(xsdt->header);
count = len / sizeof(u64); count = len / sizeof(u64);
} else { } else {
if (!rsdp->rsdt_address) if (!rsdp->rsdt_address)
return NULL; return NULL;
rsdt = map_sysmem(rsdp->rsdt_address, 0); rsdt = nomap_sysmem(rsdp->rsdt_address, 0);
len = rsdt->header.length - sizeof(rsdt->header); len = rsdt->header.length - sizeof(rsdt->header);
count = len / sizeof(u32); count = len / sizeof(u32);
} }
@ -36,19 +36,38 @@ struct acpi_table_header *acpi_find_table(const char *sig)
struct acpi_table_header *hdr; struct acpi_table_header *hdr;
if (rsdp->xsdt_address) if (rsdp->xsdt_address)
hdr = map_sysmem(xsdt->entry[i], 0); hdr = nomap_sysmem(xsdt->entry[i], 0);
else else
hdr = map_sysmem(rsdt->entry[i], 0); hdr = nomap_sysmem(rsdt->entry[i], 0);
if (!memcmp(hdr->signature, sig, ACPI_NAME_LEN)) if (!memcmp(hdr->signature, sig, ACPI_NAME_LEN))
return hdr; return hdr;
if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) { if (!memcmp(hdr->signature, "FACP", ACPI_NAME_LEN)) {
struct acpi_fadt *fadt = (struct acpi_fadt *)hdr; struct acpi_fadt *fadt = (struct acpi_fadt *)hdr;
if (!memcmp(sig, "DSDT", ACPI_NAME_LEN) && fadt->dsdt) if (!memcmp(sig, "DSDT", ACPI_NAME_LEN)) {
return map_sysmem(fadt->dsdt, 0); void *dsdt;
if (!memcmp(sig, "FACS", ACPI_NAME_LEN) &&
fadt->firmware_ctrl) if (fadt->header.revision >= 3 && fadt->x_dsdt)
return map_sysmem(fadt->firmware_ctrl, 0); 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;
}
} }
} }

View File

@ -167,7 +167,7 @@ int acpi_add_table(struct acpi_ctx *ctx, void *table)
} }
/* Add table to the RSDT */ /* 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 */ /* Fix RSDT length or the kernel will assume invalid entries */
rsdt->header.length = sizeof(struct acpi_table_header) + 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; xsdt = ctx->xsdt;
/* Add table to the XSDT */ /* Add table to the XSDT */
xsdt->entry[i] = map_to_sysmem(table); xsdt->entry[i] = nomap_to_sysmem(table);
/* Fix XSDT length */ /* Fix XSDT length */
xsdt->header.length = sizeof(struct acpi_table_header) + xsdt->header.length = sizeof(struct acpi_table_header) +

View File

@ -48,7 +48,7 @@ int acpi_write_one(struct acpi_ctx *ctx, const struct acpi_writer *entry)
return 0; return 0;
} }
#ifndef CONFIG_QEMU #ifndef CONFIG_QFW_ACPI
static int acpi_write_all(struct acpi_ctx *ctx) static int acpi_write_all(struct acpi_ctx *ctx)
{ {
const struct acpi_writer *writer = const struct acpi_writer *writer =
@ -115,7 +115,7 @@ ulong acpi_get_rsdp_addr(void)
return map_to_sysmem(gd->acpi_ctx->rsdp); return map_to_sysmem(gd->acpi_ctx->rsdp);
} }
#endif /* QEMU */ #endif /* QFW_ACPI */
void acpi_setup_ctx(struct acpi_ctx *ctx, ulong start) void acpi_setup_ctx(struct acpi_ctx *ctx, ulong start)
{ {

View File

@ -24,10 +24,10 @@ void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
memcpy(rsdp->oem_id, OEM_ID, 6); memcpy(rsdp->oem_id, OEM_ID, 6);
if (rsdt) if (rsdt)
rsdp->rsdt_address = map_to_sysmem(rsdt); rsdp->rsdt_address = nomap_to_sysmem(rsdt);
if (xsdt) if (xsdt)
rsdp->xsdt_address = map_to_sysmem(xsdt); rsdp->xsdt_address = nomap_to_sysmem(xsdt);
rsdp->length = sizeof(struct acpi_rsdp); rsdp->length = sizeof(struct acpi_rsdp);
rsdp->revision = ACPI_RSDP_REV_ACPI_2_0; rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;

View File

@ -14,6 +14,8 @@
#include <smbios.h> #include <smbios.h>
#include <linux/sizes.h> #include <linux/sizes.h>
const efi_guid_t smbios3_guid = SMBIOS3_TABLE_GUID;
enum { enum {
TABLE_SIZE = SZ_4K, TABLE_SIZE = SZ_4K,
}; };
@ -27,8 +29,9 @@ efi_status_t efi_smbios_register(void)
{ {
ulong addr; ulong addr;
efi_status_t ret; efi_status_t ret;
void *buf;
addr = gd->arch.smbios_start; addr = gd_smbios_start();
if (!addr) { if (!addr) {
log_err("No SMBIOS tables to install\n"); log_err("No SMBIOS tables to install\n");
return EFI_NOT_FOUND; 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); log_debug("EFI using SMBIOS tables at %lx\n", addr);
/* Install SMBIOS information as configuration table */ /* Install SMBIOS information as configuration table */
return efi_install_configuration_table(&smbios_guid, buf = map_sysmem(addr, 0);
map_sysmem(addr, 0)); ret = efi_install_configuration_table(&smbios3_guid, buf);
unmap_sysmem(buf);
return ret;
} }
static int install_smbios_table(void) static int install_smbios_table(void)
{ {
u64 addr; ulong addr;
efi_status_t ret; void *buf;
if (!IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE) || IS_ENABLED(CONFIG_X86)) if (!IS_ENABLED(CONFIG_GENERATE_SMBIOS_TABLE) || IS_ENABLED(CONFIG_X86))
return 0; return 0;
addr = SZ_4G; /* Align the table to a 4KB boundary to keep EFI happy */
ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, buf = memalign(SZ_4K, TABLE_SIZE);
EFI_RUNTIME_SERVICES_DATA, if (!buf)
efi_size_in_pages(TABLE_SIZE), &addr);
if (ret != EFI_SUCCESS)
return log_msg_ret("mem", -ENOMEM); return log_msg_ret("mem", -ENOMEM);
addr = map_to_sysmem((void *)(uintptr_t)addr); addr = map_to_sysmem(buf);
if (!write_smbios_table(addr)) { if (!write_smbios_table(addr)) {
log_err("Failed to write SMBIOS table\n"); log_err("Failed to write SMBIOS table\n");
return log_msg_ret("smbios", -EINVAL); return log_msg_ret("smbios", -EINVAL);
} }
/* Make a note of where we put it */ /* 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; gd->arch.smbios_start = addr;
return 0; return 0;

View File

@ -7,6 +7,10 @@
*/ */
#ifndef USE_HOSTCC #ifndef USE_HOSTCC
#define LOG_CATEGORY LOGC_DT
#include <bloblist.h>
#include <boot_fit.h> #include <boot_fit.h>
#include <display_options.h> #include <display_options.h>
#include <dm.h> #include <dm.h>
@ -86,6 +90,7 @@ static const char *const fdt_src_name[] = {
[FDTSRC_BOARD] = "board", [FDTSRC_BOARD] = "board",
[FDTSRC_EMBED] = "embed", [FDTSRC_EMBED] = "embed",
[FDTSRC_ENV] = "env", [FDTSRC_ENV] = "env",
[FDTSRC_BLOBLIST] = "bloblist",
}; };
const char *fdtdec_get_srcname(void) const char *fdtdec_get_srcname(void)
@ -1662,23 +1667,42 @@ static void setup_multi_dtb_fit(void)
int fdtdec_setup(void) int fdtdec_setup(void)
{ {
int ret; int ret = -ENOENT;
/* The devicetree is typically appended to U-Boot */ /* If allowing a bloblist, check that first */
if (IS_ENABLED(CONFIG_OF_SEPARATE)) { if (CONFIG_IS_ENABLED(BLOBLIST)) {
gd->fdt_blob = fdt_find_separate(); ret = bloblist_maybe_init();
gd->fdt_src = FDTSRC_SEPARATE; if (!ret) {
} else { /* embed dtb in ELF file for testing / development */ gd->fdt_blob = bloblist_find(BLOBLISTT_CONTROL_FDT, 0);
gd->fdt_blob = dtb_dt_embedded(); if (gd->fdt_blob) {
gd->fdt_src = FDTSRC_EMBED; 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. */ /* Allow the board to override the fdt address. */
if (IS_ENABLED(CONFIG_OF_BOARD)) { if (IS_ENABLED(CONFIG_OF_BOARD)) {
gd->fdt_blob = board_fdt_blob_setup(&ret); gd->fdt_blob = board_fdt_blob_setup(&ret);
if (ret) if (!ret)
gd->fdt_src = FDTSRC_BOARD;
else if (ret != -EEXIST)
return ret; return ret;
gd->fdt_src = FDTSRC_BOARD;
} }
/* Allow the early environment to override the fdt address */ /* Allow the early environment to override the fdt address */

View File

@ -544,15 +544,13 @@ static struct smbios_write_method smbios_write_funcs[] = {
ulong write_smbios_table(ulong addr) ulong write_smbios_table(ulong addr)
{ {
ofnode parent_node = ofnode_null(); ofnode parent_node = ofnode_null();
struct smbios_entry *se; ulong table_addr, start_addr;
struct smbios3_entry *se;
struct smbios_ctx ctx; struct smbios_ctx ctx;
ulong table_addr;
ulong tables; ulong tables;
int len = 0; int len = 0;
int max_struct_size = 0; int max_struct_size = 0;
int handle = 0; int handle = 0;
char *istart;
int isize;
int i; int i;
ctx.node = ofnode_null(); ctx.node = ofnode_null();
@ -564,14 +562,10 @@ ulong write_smbios_table(ulong addr)
ctx.dev = NULL; ctx.dev = NULL;
} }
/* 16 byte align the table address */ start_addr = addr;
addr = ALIGN(addr, 16);
se = map_sysmem(addr, sizeof(struct smbios_entry)); /* move past the (so-far-unwritten) header to start writing structs */
memset(se, 0, sizeof(struct smbios_entry)); addr = ALIGN(addr + sizeof(struct smbios3_entry), 16);
addr += sizeof(struct smbios_entry);
addr = ALIGN(addr, 16);
tables = addr; tables = addr;
/* populate minimum required tables */ /* populate minimum required tables */
@ -589,40 +583,25 @@ ulong write_smbios_table(ulong addr)
len += tmp; 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 * 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 * user of this table is not aware of the mapping of addresses to
* sandbox's DRAM buffer. * sandbox's DRAM buffer.
*/ */
table_addr = (ulong)map_sysmem(tables, 0); table_addr = (ulong)map_sysmem(tables, 0);
if (sizeof(table_addr) > sizeof(u32) && table_addr > (ulong)UINT_MAX) {
/* /* now go back and write the SMBIOS3 header */
* We need to put this >32-bit pointer into the table but the se = map_sysmem(start_addr, sizeof(struct smbios_entry));
* field is only 32 bits wide. memset(se, '\0', sizeof(struct smbios_entry));
*/ memcpy(se->anchor, "_SM3_", 5);
printf("WARNING: SMBIOS table_address overflow %llx\n", se->length = sizeof(struct smbios3_entry);
(unsigned long long)table_addr); se->major_ver = SMBIOS_MAJOR_VER;
addr = 0; se->minor_ver = SMBIOS_MINOR_VER;
goto out; se->doc_rev = 0;
} se->entry_point_rev = 1;
se->max_struct_size = len;
se->struct_table_address = table_addr; se->struct_table_address = table_addr;
se->checksum = table_compute_checksum(se, sizeof(struct smbios3_entry));
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:
unmap_sysmem(se); unmap_sysmem(se);
return addr; return addr;

View File

@ -291,8 +291,8 @@ static int dm_test_acpi_write_tables(struct unit_test_state *uts)
/* Check that the pointers were added correctly */ /* Check that the pointers were added correctly */
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
ut_asserteq(map_to_sysmem(dmar + i), ctx.rsdt->entry[i]); ut_asserteq(nomap_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.xsdt->entry[i]);
} }
ut_asserteq(0, ctx.rsdt->entry[3]); ut_asserteq(0, ctx.rsdt->entry[3]);
ut_asserteq(0, ctx.xsdt->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); DM_TEST(dm_test_acpi_basic, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
/* Test setup_ctx_and_base_tables */ /* 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_rsdp *rsdp;
struct acpi_rsdt *rsdt; 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); end = PTR_ALIGN((void *)xsdt + sizeof(*xsdt), 64);
ut_asserteq_ptr(end, ctx.current); ut_asserteq_ptr(end, ctx.current);
ut_asserteq(map_to_sysmem(rsdt), rsdp->rsdt_address); ut_asserteq(nomap_to_sysmem(rsdt), rsdp->rsdt_address);
ut_asserteq(map_to_sysmem(xsdt), rsdp->xsdt_address); ut_asserteq(nomap_to_sysmem(xsdt), rsdp->xsdt_address);
return 0; 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); UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
/* Test 'acpi list' command */ /* Test 'acpi list' command */
@ -445,7 +445,7 @@ static int dm_test_acpi_cmd_dump(struct unit_test_state *uts)
/* Now a real table */ /* Now a real table */
console_record_reset(); console_record_reset();
run_command("acpi dump dmar", 0); 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_nextline("DMAR @ %16lx", addr);
ut_assert_nextlines_are_dump(0x30); ut_assert_nextlines_are_dump(0x30);
ut_assert_console_end(); ut_assert_console_end();