x86: emulation: Support BLOBLIST_TABLES properly

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 <sjg@chromium.org>
diff --git a/drivers/misc/qfw_acpi.c b/drivers/misc/qfw_acpi.c
index 0d0cf76..ec00ba6 100644
--- a/drivers/misc/qfw_acpi.c
+++ b/drivers/misc/qfw_acpi.c
@@ -25,17 +25,18 @@
  *
  * @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 @@
 	 * 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 @@
 		       (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 @@
 	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 @@
 
 	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;