diff --git a/headers/private/kernel/acpi.h b/headers/private/kernel/acpi.h index 1c0a5b4c04..5b3795ebe4 100644 --- a/headers/private/kernel/acpi.h +++ b/headers/private/kernel/acpi.h @@ -65,7 +65,12 @@ enum { ACPI_MADT_LOCAL_SAPIC = 7, ACPI_MADT_PLATFORM_INTERRUPT_SOURCE = 8, ACPI_MADT_PROCESSOR_LOCAL_X2_APIC_NMI = 9, - ACPI_MADT_LOCAL_X2_APIC_NMI = 0XA + ACPI_MADT_LOCAL_X2_APIC_NMI = 0xA, + ACPI_MADT_GIC_INTERFACE = 0xB, + ACPI_MADT_GIC_DISTRIBUTOR = 0xC, + ACPI_MADT_GIC_MSI_FRAME = 0xD, + ACPI_MADT_GIC_REDISTRIBUTOR = 0xE, + ACPI_MADT_GIC_ITS = 0xF }; typedef struct acpi_apic { @@ -203,6 +208,38 @@ typedef struct acpi_local_x2_apic_nmi { uint8 reserved3; /* reserved (must be set to zero) */ } _PACKED acpi_local_x2_apic_nmi; +typedef struct acpi_gic_interface { + uint8 type; + uint8 length; + uint16 reserved1; + uint32 cpu_interface_num; + uint32 acpi_processor_uid; + uint32 flags; + uint32 parking_protocol_ver; + uint32 performance_gsiv; + uint64 parked_address; + uint64 base_address; + uint64 gicv_address; + uint64 gich_address; + uint32 vgic_maintenance_gsiv; + uint64 gicr_address; + uint64 mpidr; + uint8 efficiency_class; + uint8 reserved2; + uint16 spe_overflow_gsiv; +} _PACKED acpi_gic_interface; + +typedef struct acpi_gic_distributor { + uint8 type; + uint8 length; + uint16 reserved1; + uint32 gic_id; + uint64 base_address; + uint32 reserved2; + uint8 gic_version; + uint8 reserved[3]; +} _PACKED acpi_gic_distributor; + typedef struct acpi_gas { uint8 address_space_id; uint8 bit_width; diff --git a/src/system/boot/platform/efi/arch/arm64/arch_acpi.cpp b/src/system/boot/platform/efi/arch/arm64/arch_acpi.cpp index f6ead5dfe9..1791e7fb61 100644 --- a/src/system/boot/platform/efi/arch/arm64/arch_acpi.cpp +++ b/src/system/boot/platform/efi/arch/arm64/arch_acpi.cpp @@ -49,4 +49,35 @@ arch_handle_acpi() dprintf("discovered uart from acpi: base=%lx, irq=%u, clock=%lu\n", uart.regs.start, uart.irq, uart.clock); } + + acpi_madt *madt = (acpi_madt*)acpi_find_table(ACPI_MADT_SIGNATURE); + if (madt != NULL) { + uint64 gicc_base = 0; + uint64 gicd_base = 0; + uint8 version = 0; + + acpi_apic *desc = (acpi_apic*)(madt + 1); + while (desc != (acpi_apic*)((char*)madt + madt->header.length)) { + if (desc->type == ACPI_MADT_GIC_INTERFACE) { + acpi_gic_interface *acpi_gicc = (acpi_gic_interface*)desc; + if (acpi_gicc->cpu_interface_num == 0) + gicc_base = acpi_gicc->base_address; + } else if (desc->type == ACPI_MADT_GIC_DISTRIBUTOR) { + acpi_gic_distributor *acpi_gicd = (acpi_gic_distributor*)desc; + gicd_base = acpi_gicd->base_address; + version = acpi_gicd->gic_version; + } + desc = (acpi_apic*)((char*)desc + desc->length); + } + + if (version == 2 && gicc_base != 0 && gicd_base != 0) { + intc_info &intc = gKernelArgs.arch_args.interrupt_controller; + strcpy(intc.kind, INTC_KIND_GICV2); + intc.regs1.start = gicd_base; + intc.regs2.start = gicc_base; + + dprintf("discovered gic from acpi: version=%d, gicd=%lx, gicc=%lx\n", + version, gicd_base, gicc_base); + } + } }