diff options
Diffstat (limited to 'hw/arm')
-rw-r--r-- | hw/arm/virt-acpi-build.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index b8a5bd83fd..2cf2cc5f09 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -40,6 +40,134 @@ #include "hw/hw.h" #include "hw/acpi/aml-build.h" +#define ARM_SPI_BASE 32 + +static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus) +{ + uint16_t i; + + for (i = 0; i < smp_cpus; i++) { + Aml *dev = aml_device("C%03x", i); + aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0007"))); + aml_append(dev, aml_name_decl("_UID", aml_int(i))); + aml_append(scope, dev); + } +} + +static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, + int uart_irq) +{ + Aml *dev = aml_device("COM0"); + aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0011"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(uart_memmap->base, + uart_memmap->size, AML_READ_WRITE)); + aml_append(crs, + aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, uart_irq)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + +static void acpi_dsdt_add_rtc(Aml *scope, const MemMapEntry *rtc_memmap, + int rtc_irq) +{ + Aml *dev = aml_device("RTC0"); + aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0013"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(rtc_memmap->base, + rtc_memmap->size, AML_READ_WRITE)); + aml_append(crs, + aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, rtc_irq)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + +static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap) +{ + Aml *dev, *crs; + hwaddr base = flash_memmap->base; + hwaddr size = flash_memmap->size; + + dev = aml_device("FLS0"); + aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); + + dev = aml_device("FLS1"); + aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0015"))); + aml_append(dev, aml_name_decl("_UID", aml_int(1))); + crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(base + size, size, AML_READ_WRITE)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + +static void acpi_dsdt_add_virtio(Aml *scope, + const MemMapEntry *virtio_mmio_memmap, + int mmio_irq, int num) +{ + hwaddr base = virtio_mmio_memmap->base; + hwaddr size = virtio_mmio_memmap->size; + int irq = mmio_irq; + int i; + + for (i = 0; i < num; i++) { + Aml *dev = aml_device("VR%02u", i); + aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005"))); + aml_append(dev, aml_name_decl("_UID", aml_int(i))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE)); + aml_append(crs, + aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, + AML_EXCLUSIVE, irq + i)); + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); + base += size; + } +} + +/* DSDT */ +static void +build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) +{ + Aml *scope, *dsdt; + const MemMapEntry *memmap = guest_info->memmap; + const int *irqmap = guest_info->irqmap; + + dsdt = init_aml_allocator(); + /* Reserve space for header */ + acpi_data_push(dsdt->buf, sizeof(AcpiTableHeader)); + + scope = aml_scope("\\_SB"); + acpi_dsdt_add_cpus(scope, guest_info->smp_cpus); + acpi_dsdt_add_uart(scope, &memmap[VIRT_UART], + (irqmap[VIRT_UART] + ARM_SPI_BASE)); + acpi_dsdt_add_rtc(scope, &memmap[VIRT_RTC], + (irqmap[VIRT_RTC] + ARM_SPI_BASE)); + acpi_dsdt_add_flash(scope, &memmap[VIRT_FLASH]); + acpi_dsdt_add_virtio(scope, &memmap[VIRT_MMIO], + (irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS); + aml_append(dsdt, scope); + + /* copy AML table into ACPI tables blob and patch header there */ + g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len); + build_header(linker, table_data, + (void *)(table_data->data + table_data->len - dsdt->buf->len), + "DSDT", dsdt->buf->len, 5); + free_aml_allocator(); +} + typedef struct AcpiBuildState { /* Copy of table in RAM (for patching). */ @@ -55,6 +183,7 @@ static void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) { GArray *table_offsets; + GArray *tables_blob = tables->table_data; table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); @@ -72,6 +201,9 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) * DSDT */ + /* DSDT is pointed to by FADT */ + build_dsdt(tables_blob, tables->linker, guest_info); + /* Cleanup memory that's no longer used. */ g_array_free(table_offsets, true); } |