The existing QEMU implementation mostly ignored BLOBLIST_TABLES and
allocates the bulk of the tables with malloc(). Update it to place all
tables in the bloblist. Since QEMU declares a size of 128KB regardless
of the size of its tables, this requires a larger bloblist.

Fix up the e820 table to handle this, keeping the old code as an option
for now, to assist with any future bug-fixing.

Signed-off-by: Simon Glass <s...@chromium.org>
---

(no changes since v3)

Changes in v3:
- Add new patch to support BLOBLIST_TABLES properly in QEMU

 arch/x86/cpu/qemu/e820.c      | 18 +++++++++++++-----
 arch/x86/lib/tables.c         |  9 ++++++++-
 configs/qemu-x86_64_defconfig |  2 +-
 configs/qemu-x86_defconfig    |  2 +-
 drivers/misc/qfw_acpi.c       | 32 +++++++++++++++++++++++++++-----
 5 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/arch/x86/cpu/qemu/e820.c b/arch/x86/cpu/qemu/e820.c
index 2b0ad179489..078d1d86b02 100644
--- a/arch/x86/cpu/qemu/e820.c
+++ b/arch/x86/cpu/qemu/e820.c
@@ -6,6 +6,7 @@
  * (C) Copyright 2019 Bin Meng <bmeng...@gmail.com>
  */
 
+#include <bloblist.h>
 #include <env_internal.h>
 #include <malloc.h>
 #include <asm/e820.h>
@@ -27,12 +28,19 @@ unsigned int install_e820_map(unsigned int max_entries,
        e820_next(&ctx, E820_RESERVED, ISA_END_ADDRESS);
 
        /*
-        * since we use memalign(malloc) to allocate high memory for
-        * storing ACPI tables, we need to reserve them in e820 tables,
-        * otherwise kernel will reclaim them and data will be corrupted
+        * if we use bloblist to allocate high memory for storing ACPI tables,
+        * we need to reserve that region in e820 tables, otherwise the kernel
+        * will reclaim them and data will be corrupted. The ACPI tables may not
+        * have been written yet, so use the whole bloblist size
         */
-       e820_to_addr(&ctx, E820_RAM, gd->relocaddr - TOTAL_MALLOC_LEN);
-       e820_next(&ctx, E820_RESERVED, TOTAL_MALLOC_LEN);
+       if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) {
+               e820_to_addr(&ctx, E820_RAM, (ulong)gd->bloblist);
+               e820_next(&ctx, E820_ACPI, bloblist_get_total_size());
+       } else {
+               /* If using memalign() reserve that whole region instead */
+               e820_to_addr(&ctx, E820_RAM, gd->relocaddr - TOTAL_MALLOC_LEN);
+               e820_next(&ctx, E820_ACPI, TOTAL_MALLOC_LEN);
+       }
        e820_to_addr(&ctx, E820_RAM, qemu_get_low_memory_size());
        e820_add(&ctx, E820_RESERVED, CONFIG_PCIE_ECAM_BASE,
                 CONFIG_PCIE_ECAM_SIZE);
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c
index 44fe80c5224..ec52992209f 100644
--- a/arch/x86/lib/tables.c
+++ b/arch/x86/lib/tables.c
@@ -45,6 +45,13 @@ struct table_info {
        int align;
 };
 
+/* QEMU's tables include quite a bit of empty space */
+#ifdef CONFIG_QEMU
+#define ACPI_SIZE      (192 << 10)
+#else
+#define ACPI_SIZE      SZ_64K
+#endif
+
 static struct table_info table_list[] = {
 #ifdef CONFIG_GENERATE_PIRQ_TABLE
        { "pirq", write_pirq_routing_table },
@@ -60,7 +67,7 @@ static struct table_info table_list[] = {
         * that the calculation of gd->table_end works properly
         */
 #ifdef CONFIG_GENERATE_ACPI_TABLE
-       { "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, SZ_64K, SZ_4K},
+       { "acpi", write_acpi_tables, BLOBLISTT_ACPI_TABLES, ACPI_SIZE, SZ_4K},
 #endif
 #ifdef CONFIG_GENERATE_SMBIOS_TABLE
        /*
diff --git a/configs/qemu-x86_64_defconfig b/configs/qemu-x86_64_defconfig
index ae34cc2a6f8..58b1fbf132d 100644
--- a/configs/qemu-x86_64_defconfig
+++ b/configs/qemu-x86_64_defconfig
@@ -1,7 +1,7 @@
 CONFIG_X86=y
 CONFIG_TEXT_BASE=0x1110000
 CONFIG_SYS_MALLOC_F_LEN=0x1800
-CONFIG_BLOBLIST_SIZE_RELOC=0x20000
+CONFIG_BLOBLIST_SIZE_RELOC=0x40000
 CONFIG_NR_DRAM_BANKS=8
 CONFIG_ENV_SIZE=0x40000
 CONFIG_MAX_CPUS=2
diff --git a/configs/qemu-x86_defconfig b/configs/qemu-x86_defconfig
index 7afa3827e61..099d3f32d1b 100644
--- a/configs/qemu-x86_defconfig
+++ b/configs/qemu-x86_defconfig
@@ -1,7 +1,7 @@
 CONFIG_X86=y
 CONFIG_TEXT_BASE=0xFFF00000
 CONFIG_SYS_MALLOC_F_LEN=0x1000
-CONFIG_BLOBLIST_SIZE_RELOC=0x20000
+CONFIG_BLOBLIST_SIZE_RELOC=0x40000
 CONFIG_NR_DRAM_BANKS=8
 CONFIG_ENV_SIZE=0x40000
 CONFIG_MAX_CPUS=2
diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c
index 0d0cf764689..ec00ba65ade 100644
--- a/drivers/misc/qfw_acpi.c
+++ b/drivers/misc/qfw_acpi.c
@@ -25,17 +25,18 @@ DECLARE_GLOBAL_DATA_PTR;
  *
  * @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
+ * @addr  : The address that should be used for low memory allocation. 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,
+static int bios_linker_allocate(struct acpi_ctx *ctx, struct udevice *dev,
                                struct bios_linker_entry *entry, ulong *addr)
 {
        uint32_t size, align;
        struct fw_file *file;
        unsigned long aligned_addr;
+       struct acpi_rsdp *rsdp;
 
        align = le32_to_cpu(entry->alloc.align);
        /* align must be power of 2 */
@@ -58,7 +59,9 @@ static int bios_linker_allocate(struct udevice *dev,
         * 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) {
+       if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) {
+               aligned_addr = ALIGN(*addr, align);
+       } else 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");
@@ -83,8 +86,13 @@ static int bios_linker_allocate(struct udevice *dev,
                       (void *)aligned_addr);
        file->addr = aligned_addr;
 
+       rsdp = (void *)aligned_addr;
+       if (!strncmp(rsdp->signature, RSDP_SIG, sizeof(rsdp->signature)))
+               ctx->rsdp = rsdp;
+
        /* adjust address for low memory allocation */
-       if (entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG)
+       if (IS_ENABLED(CONFIG_BLOBLIST_TABLES) ||
+           entry->alloc.zone == BIOS_LINKER_LOADER_ALLOC_ZONE_FSEG)
                *addr = (aligned_addr + size);
 
        return 0;
@@ -209,19 +217,23 @@ ulong write_acpi_tables(ulong addr)
        qfw_read_entry(dev, be16_to_cpu(file->cfg.select), size, table_loader);
 
        for (i = 0; i < (size / sizeof(*entry)); i++) {
+               log_content("entry %d: addr %lx\n", i, addr);
                entry = table_loader + i;
                switch (le32_to_cpu(entry->command)) {
                case BIOS_LINKER_LOADER_COMMAND_ALLOCATE:
-                       ret = bios_linker_allocate(dev, entry, &addr);
+                       log_content("   - %s\n", entry->alloc.file);
+                       ret = bios_linker_allocate(ctx, dev, entry, &addr);
                        if (ret)
                                goto out;
                        break;
                case BIOS_LINKER_LOADER_COMMAND_ADD_POINTER:
+                       log_content("   - %s\n", entry->pointer.src_file);
                        ret = bios_linker_add_pointer(dev, entry);
                        if (ret)
                                goto out;
                        break;
                case BIOS_LINKER_LOADER_COMMAND_ADD_CHECKSUM:
+                       log_content("   - %s\n", entry->cksum.file);
                        ret = bios_linker_add_checksum(dev, entry);
                        if (ret)
                                goto out;
@@ -246,6 +258,16 @@ out:
 
        free(table_loader);
 
+       if (!ctx->rsdp) {
+               printf("error: no RSDP found\n");
+               return addr;
+       }
+       struct acpi_rsdp *rsdp = ctx->rsdp;
+
+       rsdp->length = sizeof(*rsdp);
+       rsdp->xsdt_address = 0;
+       rsdp->ext_checksum = table_compute_checksum((u8 *)rsdp, sizeof(*rsdp));
+
        gd_set_acpi_start(acpi_get_rsdp_addr());
 
        return addr;
-- 
2.43.0

Reply via email to