Expose the needed device information to the table generation insfrastructure and assemble the final compacted ACPI binary blob in the guest memory.
Signed-off-by: Alvise Rigo a.rigo@virtualopensystems.com --- hw/arm/boot.c | 26 +++++++++++++++++++++++++ hw/arm/virt-acpi.c | 18 +++++++++++++++++- hw/arm/virt.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++---- include/hw/arm/arm.h | 2 ++ 4 files changed, 95 insertions(+), 5 deletions(-)
diff --git a/hw/arm/boot.c b/hw/arm/boot.c index bffbea5..74c8eb5 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -179,6 +179,11 @@ static inline bool have_dtb(const struct arm_boot_info *info) return info->dtb_filename || info->get_dtb; }
+static inline bool have_acpi(const struct arm_boot_info *info) +{ + return info->get_acpi; +} + #define WRITE_WORD(p, value) do { \ stl_phys_notdirty(&address_space_memory, p, value); \ p += 4; \ @@ -438,6 +443,20 @@ fail: return -1; }
+static int load_acpi(hwaddr addr, const struct arm_boot_info *binfo, + hwaddr addr_limit) +{ + void *acpi_blob = NULL; + int acpi_size; + + acpi_blob = binfo->get_acpi(binfo, &acpi_size); + rom_add_blob_fixed("acpi", acpi_blob, acpi_size, binfo->acpi_base_addr); + g_free(acpi_blob); + /* TODO: check to not write outside memory boundaries */ + + return 0; +} + static void do_cpu_reset(void *opaque) { ARMCPU *cpu = opaque; @@ -497,6 +516,13 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) qemu_register_reset(do_cpu_reset, ARM_CPU(cs)); }
+ /* load ACPI blob */ + if (have_acpi(info)) { + if (load_acpi(info->acpi_base_addr, info, 0) < 0) { + exit(1); + } + } + /* Load the kernel. */ if (!info->kernel_filename) {
diff --git a/hw/arm/virt-acpi.c b/hw/arm/virt-acpi.c index be490e7..19e6779 100644 --- a/hw/arm/virt-acpi.c +++ b/hw/arm/virt-acpi.c @@ -535,5 +535,21 @@ void acpi_build_tables(int smp_cpus,
uint32_t acpi_make_blob(void **blob_ptr) { - return 0; + uint8_t *acpi_blob_ptr = NULL; + uint32_t blob_size, n; + + for (n = RSDP, blob_size = 0; n <= DSDT; n++) { + blob_size += acpi_size[n]; + } + + *blob_ptr = (void *)g_malloc0(blob_size); + acpi_blob_ptr = *blob_ptr; + + for (n = RSDP; n <= DSDT; n++) { + memcpy(acpi_blob_ptr, acpi_table[n], acpi_size[n]); + acpi_blob_ptr += acpi_size[n]; + g_free(acpi_table[n]); + } + + return blob_size; } diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 78f618d..5b40292 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -42,6 +42,8 @@ #include "exec/address-spaces.h" #include "qemu/bitops.h" #include "qemu/error-report.h" +#include "hw/acpi/acpi-defs.h" +#include "hw/arm/virt-acpi.h"
#define NUM_VIRTIO_TRANSPORTS 32
@@ -59,6 +61,11 @@ #define GIC_FDT_IRQ_PPI_CPU_START 8 #define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
+#define ARCH_TIMER_VIRT_IRQ 11 +#define ARCH_TIMER_S_EL1_IRQ 13 +#define ARCH_TIMER_NS_EL1_IRQ 14 +#define ARCH_TIMER_NS_EL2_IRQ 10 + enum { VIRT_FLASH, VIRT_MEM, @@ -83,6 +90,8 @@ typedef struct VirtBoardInfo { int smp_cpus; void *fdt; int fdt_size; + void *acpi; + int acpi_size; uint32_t clock_phandle; } VirtBoardInfo;
@@ -119,6 +128,29 @@ static const int a15irqmap[] = { [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ };
+static const struct acpi_madt_info madt_info = { + &a15memmap[VIRT_GIC_CPU].base, + &a15memmap[VIRT_GIC_DIST].base +}; + +static const struct acpi_dsdt_info dsdt_info = { + .uart_addr = &a15memmap[VIRT_UART].base, + .uart_irq = &a15irqmap[VIRT_UART], + .virtio_mmio_addr = &a15memmap[VIRT_MMIO].base, + .virtio_mmio_irq = &a15irqmap[VIRT_MMIO], + .virtio_mmio_num = NUM_VIRTIO_TRANSPORTS, + .rtc_addr = &a15memmap[VIRT_RTC].base, + .rtc_irq = &a15irqmap[VIRT_RTC], + .flash_addr = &a15memmap[VIRT_FLASH].base, +}; + +static const struct acpi_gtdt_info gtdt_info = { + ARCH_TIMER_VIRT_IRQ + 16, + ARCH_TIMER_S_EL1_IRQ + 16, + ARCH_TIMER_NS_EL1_IRQ + 16, + ARCH_TIMER_NS_EL2_IRQ + 16 +}; + static VirtBoardInfo machines[] = { { .cpu_model = "cortex-a15", @@ -259,10 +291,10 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi) "arm,armv7-timer"); } qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts", - GIC_FDT_IRQ_TYPE_PPI, 13, irqflags, - GIC_FDT_IRQ_TYPE_PPI, 14, irqflags, - GIC_FDT_IRQ_TYPE_PPI, 11, irqflags, - GIC_FDT_IRQ_TYPE_PPI, 10, irqflags); + GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags, + GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags, + GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_VIRT_IRQ, irqflags, + GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags); }
static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) @@ -527,6 +559,14 @@ static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size) return board->fdt; }
+static void *machvirt_acpi(const struct arm_boot_info *binfo, int *acpi_size) +{ + const VirtBoardInfo *board = (const VirtBoardInfo *)binfo; + + *acpi_size = board->acpi_size; + return board->acpi; +} + static void machvirt_init(MachineState *machine) { qemu_irq pic[NUM_IRQS]; @@ -604,6 +644,10 @@ static void machvirt_init(MachineState *machine) */ create_virtio_devices(vbi, pic);
+ /* Build ACPI tables and form the binary blob */ + acpi_build_tables(vbi->smp_cpus, >dt_info, &madt_info, &dsdt_info); + vbi->acpi_size = acpi_make_blob(&vbi->acpi); + vbi->bootinfo.ram_size = machine->ram_size; vbi->bootinfo.kernel_filename = machine->kernel_filename; vbi->bootinfo.kernel_cmdline = machine->kernel_cmdline; @@ -612,6 +656,8 @@ static void machvirt_init(MachineState *machine) vbi->bootinfo.board_id = -1; vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base; vbi->bootinfo.get_dtb = machvirt_dtb; + vbi->bootinfo.acpi_base_addr = ACPI_BASE_ADDRESS; + vbi->bootinfo.get_acpi = machvirt_acpi; arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo); }
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h index cefc9e6..806faaf 100644 --- a/include/hw/arm/arm.h +++ b/include/hw/arm/arm.h @@ -27,6 +27,7 @@ struct arm_boot_info { const char *initrd_filename; const char *dtb_filename; hwaddr loader_start; + hwaddr acpi_base_addr; /* multicore boards that use the default secondary core boot functions * need to put the address of the secondary boot code, the boot reg, * and the GIC address in the next 3 values, respectively. boards that @@ -61,6 +62,7 @@ struct arm_boot_info { * the user it should implement this hook. */ void (*modify_dtb)(const struct arm_boot_info *info, void *fdt); + void *(*get_acpi)(const struct arm_boot_info *info, int *size); /* Used internally by arm_boot.c */ int is_linux; hwaddr initrd_start;