[PATCH v2 0/9] acpi: add ACPI support on QEMU ARM and RISC-V

QEMU 8.1.2 can create ACPI tables for the ARM and RISC-V architectures Allow passing them through to the operating system. Provide a new config fragment that enables this.
v2: consider ARM architecture too invoke write_acpi_tables() via EVT_LAST_STAGE_INIT
Heinrich Schuchardt (9): acpi: Kconfig symbol CONFIG_QFW_ACPI acpi: carve out qfw_acpi.c arrm: add ACPI fields to global data risc-v: add ACPI fields to global data acpi: enable writing ACPI tables on QEMU risc-v: add support for QEMU firmware tables riscv: allow usage of ACPI configs: qemu: add config fragment for ACPI arm: enable support for QEMU firmware tables
MAINTAINERS | 1 + arch/Kconfig | 1 + arch/arm/include/asm/global_data.h | 4 + arch/riscv/include/asm/global_data.h | 4 + board/emulation/configs/acpi.config | 3 + board/emulation/qemu-arm/Kconfig | 1 + board/emulation/qemu-riscv/Kconfig | 2 + doc/board/emulation/acpi.rst | 23 +++ doc/board/emulation/index.rst | 1 + drivers/misc/Kconfig | 7 + drivers/misc/Makefile | 1 + drivers/misc/qfw.c | 240 ----------------------- drivers/misc/qfw_acpi.c | 281 +++++++++++++++++++++++++++ lib/acpi/Makefile | 2 +- lib/acpi/acpi_writer.c | 4 +- 15 files changed, 332 insertions(+), 243 deletions(-) create mode 100644 board/emulation/configs/acpi.config create mode 100644 doc/board/emulation/acpi.rst create mode 100644 drivers/misc/qfw_acpi.c

We have two implementations of write_acpi_tables(). One for writing ACPI tables based on ACPI_WRITER() entries another based on copying tables from QEMU.
Create a symbol CONFIG_QFW_ACPI that signifies copying ACPI tables from QEMU and use it consistently.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Reviewed-by: Simon Glass sjg@chromium.org --- v2: no change --- drivers/misc/Kconfig | 7 +++++++ drivers/misc/qfw.c | 4 ++-- lib/acpi/Makefile | 2 +- lib/acpi/acpi_writer.c | 4 ++-- 4 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 97057de8bf..86529efb2e 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/qfw.c b/drivers/misc/qfw.c index e3b6b4cd74..307334faf4 100644 --- a/drivers/misc/qfw.c +++ b/drivers/misc/qfw.c @@ -21,7 +21,7 @@ #include <tables_csum.h> #include <asm/acpi_table.h>
-#if defined(CONFIG_GENERATE_ACPI_TABLE) && !defined(CONFIG_SANDBOX) +#ifdef QFW_ACPI /* * This function allocates memory for ACPI tables * @@ -259,7 +259,7 @@ ulong acpi_get_rsdp_addr(void) file = qfw_find_file(dev, "etc/acpi/rsdp"); return file->addr; } -#endif +#endif /* QFW_ACPI */
static void qfw_read_entry_io(struct qfw_dev *qdev, u16 entry, u32 size, void *address) 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_writer.c b/lib/acpi/acpi_writer.c index 946f90e8e7..9b9fdc190b 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) {

Move the code related to copying tables from QEMU to a separate code module.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Reviewed-by: Tom Rini trini@konsulko.com Reviewed-by: Simon Glass sjg@chromium.org --- v2: add missing blank line --- drivers/misc/Makefile | 1 + drivers/misc/qfw.c | 240 ------------------------------------- drivers/misc/qfw_acpi.c | 257 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 258 insertions(+), 240 deletions(-) create mode 100644 drivers/misc/qfw_acpi.c
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 307334faf4..db98619fdf 100644 --- a/drivers/misc/qfw.c +++ b/drivers/misc/qfw.c @@ -21,246 +21,6 @@ #include <tables_csum.h> #include <asm/acpi_table.h>
-#ifdef QFW_ACPI -/* - * 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 /* QFW_ACPI */ - 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..fd5f4b3337 --- /dev/null +++ b/drivers/misc/qfw_acpi.c @@ -0,0 +1,257 @@ +// 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 <qfw.h> +#include <tables_csum.h> +#include <stdio.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; +}

Add fields for the location of ACPI tables to the global data.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com --- v2: new patch --- arch/arm/include/asm/global_data.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index 75bd9d56f8..9505399bb1 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -19,6 +19,10 @@ struct arch_global_data { #if defined(CONFIG_FSL_ESDHC) || defined(CONFIG_FSL_ESDHC_IMX) u32 sdhc_clk; #endif + 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 */
#if defined(CONFIG_FSL_ESDHC) u32 sdhc_per_clk;

Hi Heinrich,
On Fri, 15 Dec 2023 at 06:32, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Add fields for the location of ACPI tables to the global data.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
v2: new patch
arch/arm/include/asm/global_data.h | 4 ++++ 1 file changed, 4 insertions(+)
These need to be #ifdefed as they affect global_data size, particularly in SPL. In fact, we have a problem there.
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index 75bd9d56f8..9505399bb1 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -19,6 +19,10 @@ struct arch_global_data { #if defined(CONFIG_FSL_ESDHC) || defined(CONFIG_FSL_ESDHC_IMX) u32 sdhc_clk; #endif
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 */
#if defined(CONFIG_FSL_ESDHC) u32 sdhc_per_clk; -- 2.40.1
Regards, Simon

On 12/16/23 19:46, Simon Glass wrote:
Hi Heinrich,
On Fri, 15 Dec 2023 at 06:32, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Add fields for the location of ACPI tables to the global data.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
v2: new patch
arch/arm/include/asm/global_data.h | 4 ++++ 1 file changed, 4 insertions(+)
These need to be #ifdefed as they affect global_data size, particularly in SPL. In fact, we have a problem there.
Why would it be problematic to have more unused fields in global data?
Best regards
Heinrich
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h index 75bd9d56f8..9505399bb1 100644 --- a/arch/arm/include/asm/global_data.h +++ b/arch/arm/include/asm/global_data.h @@ -19,6 +19,10 @@ struct arch_global_data { #if defined(CONFIG_FSL_ESDHC) || defined(CONFIG_FSL_ESDHC_IMX) u32 sdhc_clk; #endif
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 */
#if defined(CONFIG_FSL_ESDHC) u32 sdhc_per_clk;
-- 2.40.1
Regards, Simon

Hi Heinrich,
On Sat, 16 Dec 2023 at 12:23, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
On 12/16/23 19:46, Simon Glass wrote:
Hi Heinrich,
On Fri, 15 Dec 2023 at 06:32, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Add fields for the location of ACPI tables to the global data.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
v2: new patch
arch/arm/include/asm/global_data.h | 4 ++++ 1 file changed, 4 insertions(+)
These need to be #ifdefed as they affect global_data size, particularly in SPL. In fact, we have a problem there.
Why would it be problematic to have more unused fields in global data?
It uses memory, i.e. SRAM, which is not that large.
Regards, Simon

Add fields for the location of ACPI tables to the global data.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Reviewed-by: Simon Glass sjg@chromium.org --- v2: no change --- arch/riscv/include/asm/global_data.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h index 937fa4d154..a8f6a217f1 100644 --- a/arch/riscv/include/asm/global_data.h +++ b/arch/riscv/include/asm/global_data.h @@ -32,6 +32,10 @@ struct arch_global_data { ulong available_harts; #endif #endif + 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 */ #ifdef CONFIG_SMBIOS ulong smbios_start; /* Start address of SMBIOS table */ #endif

Invoke write_acpi_tables() via EVT_LAST_STAGE_INIT on QEMU except on X86. X86 calls write_acpi_tables() in write_tables().
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com --- v2: new patch --- drivers/misc/qfw_acpi.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c index 6e14b2a504..7ffed1e8c0 100644 --- a/drivers/misc/qfw_acpi.c +++ b/drivers/misc/qfw_acpi.c @@ -9,9 +9,11 @@ #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>
@@ -254,3 +256,26 @@ ulong acpi_get_rsdp_addr(void) 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

Hi Heinrich,
On Fri, 15 Dec 2023 at 06:33, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Invoke write_acpi_tables() via EVT_LAST_STAGE_INIT on QEMU except on X86. X86 calls write_acpi_tables() in write_tables().
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
v2: new patch
drivers/misc/qfw_acpi.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
This is fine for now.
Reviewed-by: Simon Glass sjg@chromium.org
I would like to collect all tables generation into one piece, using a bloblist to hold them, so they are contiguous. This is implemented on x86, but is optional.
Still, this patch gets things running and makes it possible to make such a change later.
diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c index 6e14b2a504..7ffed1e8c0 100644 --- a/drivers/misc/qfw_acpi.c +++ b/drivers/misc/qfw_acpi.c @@ -9,9 +9,11 @@ #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>
@@ -254,3 +256,26 @@ ulong acpi_get_rsdp_addr(void) 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
2.40.1
Regards, Simon

Enable the QEMU firmware interface if ACPI tables are to be supported on the QEMU platform.
Enable the QFW MMIO interface if the QEMU firmware interface is enabled.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Reviewed-by: Simon Glass sjg@chromium.org --- v2: no change --- board/emulation/qemu-riscv/Kconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig index 2709c9ca1e..59cf66896e 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

On Fri, 15 Dec 2023 at 15:32, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Enable the QEMU firmware interface if ACPI tables are to be supported on the QEMU platform.
Enable the QFW MMIO interface if the QEMU firmware interface is enabled.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Reviewed-by: Simon Glass sjg@chromium.org
v2: no change
board/emulation/qemu-riscv/Kconfig | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig index 2709c9ca1e..59cf66896e 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
-- 2.40.1
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

Select CONFIG_SUPPORT_ACPI to allow usage of ACPI tables with RISC-V.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Reviewed-by: Simon Glass sjg@chromium.org --- v2: no change --- arch/Kconfig | 1 + 1 file changed, 1 insertion(+)
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

Provide a configuration fragment to enable ACPI on QEMU.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org --- v2: no change --- MAINTAINERS | 1 + board/emulation/configs/acpi.config | 3 +++ doc/board/emulation/acpi.rst | 23 +++++++++++++++++++++++ doc/board/emulation/index.rst | 1 + 4 files changed, 28 insertions(+) create mode 100644 board/emulation/configs/acpi.config create mode 100644 doc/board/emulation/acpi.rst
diff --git a/MAINTAINERS b/MAINTAINERS index d77b9ffc9b..c1562d8115 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -53,6 +53,7 @@ Maintainers List (try to look for most precise areas first) ACPI: M: Simon Glass sjg@chromium.org S: Maintained +F: board/emulation/configs/acpi.config F: cmd/acpi.c F: lib/acpi/
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/doc/board/emulation/acpi.rst b/doc/board/emulation/acpi.rst new file mode 100644 index 0000000000..e1208ca51e --- /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, and x86. + +The following settings are needed:: + + 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

On Fri, 15 Dec 2023 at 06:33, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Provide a configuration fragment to enable ACPI on QEMU.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org
v2: no change
MAINTAINERS | 1 + board/emulation/configs/acpi.config | 3 +++ doc/board/emulation/acpi.rst | 23 +++++++++++++++++++++++ doc/board/emulation/index.rst | 1 + 4 files changed, 28 insertions(+) create mode 100644 board/emulation/configs/acpi.config create mode 100644 doc/board/emulation/acpi.rst
Reviewed-by: Simon Glass sjg@chromium.org

On 12/16/23 19:46, Simon Glass wrote:
On Fri, 15 Dec 2023 at 06:33, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Provide a configuration fragment to enable ACPI on QEMU.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org
v2: no change
MAINTAINERS | 1 + board/emulation/configs/acpi.config | 3 +++ doc/board/emulation/acpi.rst | 23 +++++++++++++++++++++++ doc/board/emulation/index.rst | 1 + 4 files changed, 28 insertions(+) create mode 100644 board/emulation/configs/acpi.config create mode 100644 doc/board/emulation/acpi.rst
Reviewed-by: Simon Glass sjg@chromium.org
Are you planning to enable binman to build configurations with config fragments? This would be needed for testing in CI.
Best regards
Heinrich

Hi Heinrich,
On Sat, 16 Dec 2023 at 12:27, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
On 12/16/23 19:46, Simon Glass wrote:
On Fri, 15 Dec 2023 at 06:33, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Provide a configuration fragment to enable ACPI on QEMU.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org
v2: no change
MAINTAINERS | 1 + board/emulation/configs/acpi.config | 3 +++ doc/board/emulation/acpi.rst | 23 +++++++++++++++++++++++ doc/board/emulation/index.rst | 1 + 4 files changed, 28 insertions(+) create mode 100644 board/emulation/configs/acpi.config create mode 100644 doc/board/emulation/acpi.rst
Reviewed-by: Simon Glass sjg@chromium.org
Are you planning to enable binman to build configurations with config fragments? This would be needed for testing in CI.
We still have not decided on a mechanism to name things which are made up of a base config and a fragment. The current proposal is [1] which I think is probably OK, but I have not tried to look at this in buildman yet.
Regards, Simon
[1] https://patchwork.ozlabs.org/user/todo/uboot/?series=380278

On Mon, Dec 18, 2023 at 08:01:34AM -0700, Simon Glass wrote:
Hi Heinrich,
On Sat, 16 Dec 2023 at 12:27, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
On 12/16/23 19:46, Simon Glass wrote:
On Fri, 15 Dec 2023 at 06:33, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Provide a configuration fragment to enable ACPI on QEMU.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org
v2: no change
MAINTAINERS | 1 + board/emulation/configs/acpi.config | 3 +++ doc/board/emulation/acpi.rst | 23 +++++++++++++++++++++++ doc/board/emulation/index.rst | 1 + 4 files changed, 28 insertions(+) create mode 100644 board/emulation/configs/acpi.config create mode 100644 doc/board/emulation/acpi.rst
Reviewed-by: Simon Glass sjg@chromium.org
Are you planning to enable binman to build configurations with config fragments? This would be needed for testing in CI.
We still have not decided on a mechanism to name things which are made up of a base config and a fragment. The current proposal is [1] which I think is probably OK, but I have not tried to look at this in buildman yet.
Regards, Simon
[1] https://patchwork.ozlabs.org/user/todo/uboot/?series=380278
Patchwork a little frustrating about links sometimes, this should be: https://patchwork.ozlabs.org/project/uboot/list/?series=380278&state=*
Which _I_ don't think we need, but I'm also in the minority here so I'm not nak'ing it.

Enable the QEMU firmware interface if ACPI tables are to be supported on the QEMU platform.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com --- v2: new patch --- board/emulation/qemu-arm/Kconfig | 1 + 1 file changed, 1 insertion(+)
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

On Fri, 15 Dec 2023 at 06:33, Heinrich Schuchardt heinrich.schuchardt@canonical.com wrote:
Enable the QEMU firmware interface if ACPI tables are to be supported on the QEMU platform.
Signed-off-by: Heinrich Schuchardt heinrich.schuchardt@canonical.com
v2: new patch
board/emulation/qemu-arm/Kconfig | 1 + 1 file changed, 1 insertion(+)
Reviewed-by: Simon Glass sjg@chromium.org
participants (4)
-
Heinrich Schuchardt
-
Ilias Apalodimas
-
Simon Glass
-
Tom Rini