ACPI v5.1 defines GTDT for ARM devices as a place to describe timer related information in the system. MADT is also updated with a number of relevant subtables that can describe GIC enabled ARM platforms.
For GTDT the Arch Timer interrupts must be provided, in the case of MADT the GICC and GICD subtables are used to define the GIC regions.
Signed-off-by: Alexander Spyridakis a.spyridakis@virtualopensystems.com --- hw/arm/virt-acpi.c | 65 +++++++++++++++++++++++++++++++++++++--- include/hw/acpi/acpi-defs.h | 73 ++++++++++++++++++++++++++++++++++++++++++++- include/hw/arm/virt-acpi.h | 6 ++++ 3 files changed, 139 insertions(+), 5 deletions(-)
diff --git a/hw/arm/virt-acpi.c b/hw/arm/virt-acpi.c index aca0434..a53a620 100644 --- a/hw/arm/virt-acpi.c +++ b/hw/arm/virt-acpi.c @@ -121,14 +121,71 @@ static void acpi_create_xsdt(void) static void acpi_create_madt(uint32_t smp_cpus, const struct acpi_madt_info *info) { - acpi_table[MADT] = NULL; - acpi_size[MADT] = 0; + AcpiMultipleApicTable *madt; + AcpiMadtGenericInterrupt *gicc; + AcpiMadtGenericDistributor *gicd; + int i, madt_size; + + madt_size = sizeof(*madt) + (smp_cpus * sizeof(*gicc) + sizeof(*gicd)); + madt = g_malloc0(madt_size); + + acpi_fill_common_header_data(madt, "APIC", 1, madt_size); + + madt->local_apic_address = *info->gic_cpu_base_addr; + + /* Point at the end of the madt structure */ + gicc = (AcpiMadtGenericInterrupt *)(madt + 1); + + /* GICC subtable, one for each cpu in the guest*/ + for (i = 0; i < smp_cpus; i++) { + gicc->type = ACPI_APIC_GENERIC_INTERRUPT; + gicc->length = sizeof(*gicc); + + gicc->base_address = *info->gic_cpu_base_addr; + gicc->cpu_interface_number = i; + gicc->arm_mpidr = i; + gicc->uid = i; + gicc->flags = 0x01; + + gicc++; + } + + /* GIC Distributor subtable */ + gicd = (AcpiMadtGenericDistributor *)(gicc); + gicd->type = ACPI_APIC_GENERIC_DISTRIBUTOR; + gicd->length = sizeof(*gicd); + gicd->base_address = *info->gic_dist_base_addr; + + acpi_do_checksum(madt, madt->length, &madt->checksum); + + acpi_table[MADT] = (void *)madt; + acpi_size[MADT] = madt->length; }
static void acpi_create_gtdt(const struct acpi_gtdt_info *irqs) { - acpi_table[GTDT] = NULL; - acpi_size[GTDT] = 0; + AcpiGenericTimerTable *gtdt; + + gtdt = g_malloc0(sizeof(*gtdt)); + acpi_fill_common_header_data(gtdt, "GTDT", 1, sizeof(*gtdt)); + + /* The interrupt values are the same with the device tree when adding 16 */ + gtdt->secure_el1_interrupt = irqs->timer_s_el1; + gtdt->secure_el1_flags = ACPI_EDGE_SENSITIVE; + + gtdt->non_secure_el1_interrupt = irqs->timer_ns_el1; + gtdt->non_secure_el1_flags = ACPI_EDGE_SENSITIVE; + + gtdt->virtual_timer_interrupt = irqs->timer_virt; + gtdt->virtual_timer_flags = ACPI_EDGE_SENSITIVE; + + gtdt->non_secure_el2_interrupt = irqs->timer_ns_el2; + gtdt->non_secure_el2_flags = ACPI_EDGE_SENSITIVE; + + acpi_do_checksum(gtdt, gtdt->length, >dt->checksum); + + acpi_table[GTDT] = (void *)gtdt; + acpi_size[GTDT] = gtdt->length; }
static void acpi_create_fadt(void) diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index ebbd2d0..f5e5222 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -257,7 +257,13 @@ typedef struct AcpiMultipleApicTable AcpiMultipleApicTable; #define ACPI_APIC_IO_SAPIC 6 #define ACPI_APIC_LOCAL_SAPIC 7 #define ACPI_APIC_XRUPT_SOURCE 8 -#define ACPI_APIC_RESERVED 9 /* 9 and greater are reserved */ +#define ACPI_APIC_LOCAL_X2APIC 9 +#define ACPI_APIC_LOCAL_X2APIC_NMI 10 +#define ACPI_APIC_GENERIC_INTERRUPT 11 +#define ACPI_APIC_GENERIC_DISTRIBUTOR 12 +#define ACPI_APIC_GENERIC_MSI_FRAME 13 +#define ACPI_APIC_GENERIC_REDISTRIBUTOR 14 +#define ACPI_APIC_RESERVED 15 /* 15 and greater are reserved */
/* * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE) @@ -305,6 +311,71 @@ struct AcpiMadtLocalNmi { } QEMU_PACKED; typedef struct AcpiMadtLocalNmi AcpiMadtLocalNmi;
+struct AcpiMadtGenericInterrupt { + ACPI_SUB_HEADER_DEF + uint16_t reserved; + uint32_t cpu_interface_number; + uint32_t uid; + uint32_t flags; + uint32_t parking_version; + uint32_t performance_interrupt; + uint64_t parked_address; + uint64_t base_address; + uint64_t gicv_base_address; + uint64_t gich_base_address; + uint32_t vgic_interrupt; + uint64_t gicr_base_address; + uint64_t arm_mpidr; +} QEMU_PACKED; +typedef struct AcpiMadtGenericInterrupt AcpiMadtGenericInterrupt; + +struct AcpiMadtGenericDistributor { + ACPI_SUB_HEADER_DEF + uint16_t reserved; + uint32_t gic_id; + uint64_t base_address; + uint32_t global_irq_base; + uint32_t reserved2; +} QEMU_PACKED; +typedef struct AcpiMadtGenericDistributor AcpiMadtGenericDistributor; + +/* + * Generic Timer Description Table (GTDT) + */ + +#define ACPI_GTDT_INTERRUPT_MODE (1) +#define ACPI_GTDT_INTERRUPT_POLARITY (1<<1) +#define ACPI_GTDT_ALWAYS_ON (1<<2) + +/* Triggering */ + +#define ACPI_LEVEL_SENSITIVE (uint8_t) 0x00 +#define ACPI_EDGE_SENSITIVE (uint8_t) 0x01 + +/* Polarity */ + +#define ACPI_ACTIVE_HIGH (uint8_t) 0x00 +#define ACPI_ACTIVE_LOW (uint8_t) 0x01 +#define ACPI_ACTIVE_BOTH (uint8_t) 0x02 + +struct AcpiGenericTimerTable { + ACPI_TABLE_HEADER_DEF + uint64_t counter_block_addresss; + uint32_t reserved; + uint32_t secure_el1_interrupt; + uint32_t secure_el1_flags; + uint32_t non_secure_el1_interrupt; + uint32_t non_secure_el1_flags; + uint32_t virtual_timer_interrupt; + uint32_t virtual_timer_flags; + uint32_t non_secure_el2_interrupt; + uint32_t non_secure_el2_flags; + uint64_t counter_read_block_address; + uint32_t platform_timer_count; + uint32_t platform_timer_offset; +} QEMU_PACKED; +typedef struct AcpiGenericTimerTable AcpiGenericTimerTable; + /* * HPET Description Table */ diff --git a/include/hw/arm/virt-acpi.h b/include/hw/arm/virt-acpi.h index 66a73eb..216a3a2 100644 --- a/include/hw/arm/virt-acpi.h +++ b/include/hw/arm/virt-acpi.h @@ -41,9 +41,15 @@ enum { };
struct acpi_gtdt_info { + uint32_t timer_virt; + uint32_t timer_s_el1; + uint32_t timer_ns_el1; + uint32_t timer_ns_el2; };
struct acpi_madt_info { + const hwaddr *gic_cpu_base_addr; + const hwaddr *gic_dist_base_addr; };
struct acpi_dsdt_info {