Re: [U-Boot] [PATCH v2 4/4] x86: qemu: add the ability to load and link ACPI tables from QEMU

2016-01-20 Thread Bin Meng
On Wed, Jan 20, 2016 at 12:24 PM, Miao Yan  wrote:
> This patch adds the ability to load and link ACPI tables provided by QEMU.
> QEMU tells guests how to load and patch ACPI tables through its fw_cfg
> interface, by adding a firmware file 'etc/table-loader'. Guests are
> supposed to parse this file and execute corresponding QEMU commands.
>
> Signed-off-by: Miao Yan 
> ---
> Changes in v2:
>   - add function comment
>   - improve error handling
>
>  arch/x86/cpu/qemu/fw_cfg.c| 253 
> ++
>  arch/x86/include/asm/fw_cfg.h |  61 ++
>  arch/x86/lib/acpi_table.c |   4 +
>  3 files changed, 318 insertions(+)
>

Reviewed-by: Bin Meng 
Tested-by: Bin Meng 
___
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot


[U-Boot] [PATCH v2 4/4] x86: qemu: add the ability to load and link ACPI tables from QEMU

2016-01-19 Thread Miao Yan
This patch adds the ability to load and link ACPI tables provided by QEMU.
QEMU tells guests how to load and patch ACPI tables through its fw_cfg
interface, by adding a firmware file 'etc/table-loader'. Guests are
supposed to parse this file and execute corresponding QEMU commands.

Signed-off-by: Miao Yan 
---
Changes in v2:
  - add function comment
  - improve error handling

 arch/x86/cpu/qemu/fw_cfg.c| 253 ++
 arch/x86/include/asm/fw_cfg.h |  61 ++
 arch/x86/lib/acpi_table.c |   4 +
 3 files changed, 318 insertions(+)

diff --git a/arch/x86/cpu/qemu/fw_cfg.c b/arch/x86/cpu/qemu/fw_cfg.c
index bcd34af..5ea7a6e 100644
--- a/arch/x86/cpu/qemu/fw_cfg.c
+++ b/arch/x86/cpu/qemu/fw_cfg.c
@@ -10,7 +10,10 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 #include 
+#include 
 
 static bool fwcfg_present;
 static bool fwcfg_dma_present;
@@ -204,6 +207,256 @@ err:
return -ENOMEM;
 }
 
+#ifdef CONFIG_QEMU_ACPI_TABLE
+static struct fw_file *qemu_fwcfg_find_file(const char *name)
+{
+   struct list_head *entry;
+   struct fw_file *file;
+
+   list_for_each(entry, &fw_list) {
+   file = list_entry(entry, struct fw_file, list);
+   if (!strcmp(file->cfg.name, name))
+   return file;
+   }
+
+   return NULL;
+}
+
+/*
+ * 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 bios_linker_entry *entry,
+  unsigned long *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 = qemu_fwcfg_find_file(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;
+   }
+   } 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);
+
+   qemu_fwcfg_read_entry(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 bios_linker_entry *entry)
+{
+   struct fw_file *dest, *src;
+   uint32_t offset = le32_to_cpu(entry->pointer.offset);
+   uint64_t pointer = 0;
+
+   dest = qemu_fwcfg_find_file(entry->pointer.dest_file);
+   if (!dest || !dest->addr)
+   return -ENOENT;
+   src = qemu_fwcfg_find_file(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);
+
+