From 4ff9f5dfb2acdbe666a08d101f51b1db025c7215 Mon Sep 17 00:00:00 2001 From: "Grandhi, Sainath" Date: Sat, 26 Jan 2019 00:04:47 -0800 Subject: [PATCH] hv: Enumerate IOAPIC info from MADT IOAPIC info, specifically ID, is needed to map the IOAPIC to corresponding DMAR. DMAR table in ACPI has a field that has IOAPIC ID, that matches the info provided in MADT. Both (IOAPIC info from MADT and from DMAR) is needed for remapping IOAPIC interrupts. Tracked-On: #2426 Signed-off-by: Sainath Grandhi Acked-by: Anthony Xu --- hypervisor/arch/x86/Kconfig | 5 ++ hypervisor/arch/x86/cpu.c | 6 +++ hypervisor/arch/x86/ioapic.c | 34 +++++++++---- hypervisor/boot/acpi.c | 56 ++++++++++++++++++++++ hypervisor/boot/include/acpi.h | 1 + hypervisor/bsp/include/default_acpi_info.h | 1 - hypervisor/include/arch/x86/hv_arch.h | 1 + hypervisor/include/arch/x86/ioapic.h | 8 ++++ 8 files changed, 101 insertions(+), 11 deletions(-) diff --git a/hypervisor/arch/x86/Kconfig b/hypervisor/arch/x86/Kconfig index e8e427f58..98495ba1d 100644 --- a/hypervisor/arch/x86/Kconfig +++ b/hypervisor/arch/x86/Kconfig @@ -324,6 +324,11 @@ config RELOC wherever appropriate. Without relocation the bootloader must put the image to RAM_START, otherwise the hypervisor will not start up. +config MAX_IOAPIC_NUM + int "Maximum number of IO-APICs" + range 1 8 + default 1 + config IOMMU_BUS_NUM hex "Highest PCI bus ID used during IOMMU initialization" default 0x10 if PLATFORM_SBL diff --git a/hypervisor/arch/x86/cpu.c b/hypervisor/arch/x86/cpu.c index e14fbaee5..fc95f1c25 100644 --- a/hypervisor/arch/x86/cpu.c +++ b/hypervisor/arch/x86/cpu.c @@ -87,6 +87,7 @@ uint64_t get_active_pcpu_bitmap(void) void init_cpu_pre(uint16_t pcpu_id_args) { uint16_t pcpu_id = pcpu_id_args; + int32_t ret; if (pcpu_id == BOOT_CPU_ID) { start_tsc = rdtsc(); @@ -114,6 +115,11 @@ void init_cpu_pre(uint16_t pcpu_id_args) early_init_lapic(); init_percpu_lapic_id(); + + ret = init_ioapic_id_info(); + if (ret != 0) { + panic("System IOAPIC info is incorrect!"); + } } else { /* Switch this CPU to use the same page tables set-up by the * primary/boot CPU diff --git a/hypervisor/arch/x86/ioapic.c b/hypervisor/arch/x86/ioapic.c index 4840b69f6..1e1924a01 100644 --- a/hypervisor/arch/x86/ioapic.c +++ b/hypervisor/arch/x86/ioapic.c @@ -6,6 +6,7 @@ #include #include +#include #define IOAPIC_MAX_PIN 240U @@ -14,13 +15,13 @@ * The usable RTEs may be a subset of the total on a per IO APIC basis. */ #define IOAPIC_MAX_LINES 120U -#define NR_MAX_GSI (NR_IOAPICS * IOAPIC_MAX_LINES) +#define NR_MAX_GSI (CONFIG_MAX_IOAPIC_NUM * IOAPIC_MAX_LINES) static struct gsi_table gsi_table_data[NR_MAX_GSI]; static uint32_t ioapic_nr_gsi; static spinlock_t ioapic_lock; -static union ioapic_rte saved_rte[NR_IOAPICS][IOAPIC_MAX_PIN]; +static union ioapic_rte saved_rte[CONFIG_MAX_IOAPIC_NUM][IOAPIC_MAX_PIN]; /* * the irq to ioapic pin mapping should extract from ACPI MADT table @@ -83,6 +84,9 @@ static const uint32_t pic_ioapic_pin_map[NR_LEGACY_PIN] = { 15U, /* pin15*/ }; +static struct ioapic_info ioapic_array[CONFIG_MAX_IOAPIC_NUM]; +static uint16_t ioapic_num; + uint32_t get_pic_pin_from_ioapic_pin(uint32_t pin_index) { uint32_t pin_id = INVALID_INTERRUPT_PIN; @@ -152,10 +156,8 @@ ioapic_write_reg32(void *ioapic_base, const uint32_t offset, const uint32_t valu static inline uint64_t get_ioapic_base(uint8_t apic_id) { - const uint64_t addr[2] = {IOAPIC0_BASE, IOAPIC1_BASE}; - /* the ioapic base should be extracted from ACPI MADT table */ - return addr[apic_id]; + return ioapic_array[apic_id].addr; } void ioapic_get_rte_entry(void *ioapic_addr, uint32_t pin, union ioapic_rte *rte) @@ -368,6 +370,18 @@ ioapic_nr_pins(void *ioapic_base) return nr_pins; } +int32_t init_ioapic_id_info(void) +{ + int32_t ret = 0; + + ioapic_num = parse_madt_ioapic(&ioapic_array[0]); + if (ioapic_num > (uint16_t)CONFIG_MAX_IOAPIC_NUM) { + ret = -EINVAL; + } + + return ret; +} + void ioapic_setup_irqs(void) { uint8_t ioapic_id; @@ -377,16 +391,16 @@ void ioapic_setup_irqs(void) spinlock_init(&ioapic_lock); for (ioapic_id = 0U; - ioapic_id < NR_IOAPICS; ioapic_id++) { + ioapic_id < ioapic_num; ioapic_id++) { void *addr; uint32_t pin, nr_pins; - addr = map_ioapic(get_ioapic_base(ioapic_id)); + addr = map_ioapic(ioapic_array[ioapic_id].addr); hv_access_memory_region_update((uint64_t)addr, PAGE_SIZE); nr_pins = ioapic_nr_pins(addr); for (pin = 0U; pin < nr_pins; pin++) { - gsi_table_data[gsi].ioapic_id = ioapic_id; + gsi_table_data[gsi].ioapic_id = ioapic_array[ioapic_id].id; gsi_table_data[gsi].addr = addr; if (gsi < NR_LEGACY_IRQ) { @@ -432,7 +446,7 @@ void suspend_ioapic(void) uint8_t ioapic_id; uint32_t ioapic_pin; - for (ioapic_id = 0U; ioapic_id < NR_IOAPICS; ioapic_id++) { + for (ioapic_id = 0U; ioapic_id < ioapic_num; ioapic_id++) { void *addr; uint32_t nr_pins; @@ -450,7 +464,7 @@ void resume_ioapic(void) uint8_t ioapic_id; uint32_t ioapic_pin; - for (ioapic_id = 0U; ioapic_id < NR_IOAPICS; ioapic_id++) { + for (ioapic_id = 0U; ioapic_id < ioapic_num; ioapic_id++) { void *addr; uint32_t nr_pins; diff --git a/hypervisor/boot/acpi.c b/hypervisor/boot/acpi.c index 24c357158..efb240af4 100644 --- a/hypervisor/boot/acpi.c +++ b/hypervisor/boot/acpi.c @@ -39,6 +39,7 @@ #define RSDP_CHECKSUM_LENGTH 20 #define ACPI_NAME_SIZE 4U #define ACPI_MADT_TYPE_LOCAL_APIC 0U +#define ACPI_MADT_TYPE_IOAPIC 1U #define ACPI_MADT_ENABLED 1U #define ACPI_OEM_TABLE_ID_SIZE 8 @@ -100,6 +101,14 @@ struct acpi_madt_local_apic { }; static struct acpi_table_rsdp *acpi_rsdp; +struct acpi_madt_ioapic { + struct acpi_subtable_header header; + /* IOAPIC id */ + uint8_t id; + uint8_t rsvd; + uint32_t addr; + uint32_t gsi_base; +}; static struct acpi_table_rsdp* found_rsdp(char *base, int32_t length) @@ -245,6 +254,40 @@ local_parse_madt(struct acpi_table_madt *madt, uint32_t lapic_id_array[CONFIG_MA return pcpu_num; } +static uint16_t +ioapic_parse_madt(void *madt, struct ioapic_info *ioapic_id_array) +{ + struct acpi_madt_ioapic *ioapic; + struct acpi_table_madt *madt_ptr; + void *first, *end, *iterator; + struct acpi_subtable_header *entry; + uint16_t ioapic_idx = 0U; + + madt_ptr = (struct acpi_table_madt *)madt; + + first = madt_ptr + 1; + end = (void *)madt_ptr + madt_ptr->header.length; + + for (iterator = first; (iterator) < (end); iterator += entry->length) { + entry = (struct acpi_subtable_header *)iterator; + if (entry->length < sizeof(struct acpi_subtable_header)) { + break; + } + + if (entry->type == ACPI_MADT_TYPE_IOAPIC) { + ioapic = (struct acpi_madt_ioapic *)iterator; + if (ioapic_idx < CONFIG_MAX_IOAPIC_NUM) { + ioapic_id_array[ioapic_idx].id = ioapic->id; + ioapic_id_array[ioapic_idx].addr = ioapic->addr; + ioapic_id_array[ioapic_idx].gsi_base = ioapic->gsi_base; + } + ioapic_idx++; + } + } + + return ioapic_idx; +} + /* The lapic_id info gotten from madt will be returned in lapic_id_array */ uint16_t parse_madt(uint32_t lapic_id_array[CONFIG_MAX_PCPU_NUM]) { @@ -261,6 +304,19 @@ uint16_t parse_madt(uint32_t lapic_id_array[CONFIG_MAX_PCPU_NUM]) return ret; } +uint16_t parse_madt_ioapic(struct ioapic_info *ioapic_id_array) +{ + void *madt; + + acpi_rsdp = get_rsdp(); + ASSERT(acpi_rsdp != NULL, "fail to get rsdp"); + + madt = get_acpi_tbl(ACPI_SIG_MADT); + ASSERT(madt != NULL, "fail to get madt"); + + return ioapic_parse_madt(madt, ioapic_id_array); +} + void *get_dmar_table(void) { return get_acpi_tbl(ACPI_SIG_DMAR); diff --git a/hypervisor/boot/include/acpi.h b/hypervisor/boot/include/acpi.h index 66d7d6fea..f905cfbc9 100644 --- a/hypervisor/boot/include/acpi.h +++ b/hypervisor/boot/include/acpi.h @@ -8,5 +8,6 @@ #define ACPI_H uint16_t parse_madt(uint32_t lapic_id_array[CONFIG_MAX_PCPU_NUM]); +uint16_t parse_madt_ioapic(struct ioapic_info *ioapic_id_array); #endif /* !ACPI_H */ diff --git a/hypervisor/bsp/include/default_acpi_info.h b/hypervisor/bsp/include/default_acpi_info.h index a92573223..b3ce49fde 100644 --- a/hypervisor/bsp/include/default_acpi_info.h +++ b/hypervisor/bsp/include/default_acpi_info.h @@ -15,7 +15,6 @@ /* APIC */ #define LAPIC_BASE 0xFEE00000UL -#define NR_IOAPICS 1U #define IOAPIC0_BASE 0xFEC00000UL #define IOAPIC1_BASE 0UL diff --git a/hypervisor/include/arch/x86/hv_arch.h b/hypervisor/include/arch/x86/hv_arch.h index b2768378d..5dc55aeee 100644 --- a/hypervisor/include/arch/x86/hv_arch.h +++ b/hypervisor/include/arch/x86/hv_arch.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/hypervisor/include/arch/x86/ioapic.h b/hypervisor/include/arch/x86/ioapic.h index cb71925cf..661bcbd35 100644 --- a/hypervisor/include/arch/x86/ioapic.h +++ b/hypervisor/include/arch/x86/ioapic.h @@ -9,10 +9,18 @@ #define NR_LEGACY_IRQ 16U #define NR_LEGACY_PIN NR_LEGACY_IRQ + +struct ioapic_info { + uint8_t id; + uint32_t addr; + uint32_t gsi_base; +}; + void ioapic_setup_irqs(void); bool ioapic_irq_is_gsi(uint32_t irq); uint32_t ioapic_irq_to_pin(uint32_t irq); +int32_t init_ioapic_id_info(void); /** * @brief Get irq num from pin num