1/** 2 * \file 3 * \brief Interrupt management (Local and IOAPICs) and routing 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2011, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <arch/aarch64/hw_records_arch.h> 16#include <stdio.h> 17#include <barrelfish/barrelfish.h> 18#include <barrelfish/cpu_arch.h> 19#include <acpi.h> 20#include <mm/mm.h> 21 22#include <skb/skb.h> 23#include <octopus/getset.h> 24#include <trace/trace.h> 25 26#include "acpi_debug.h" 27#include "acpi_shared.h" 28 29 30int init_all_interrupt_sources(void) 31{ 32 ACPI_STATUS as; 33 ACPI_TABLE_MADT *madt; 34 ACPI_TABLE_HEADER *ath; 35 36 static coreid_t barrelfish_id_counter = 1; 37 38 // Get the ACPI APIC table (the MADT) 39 as = AcpiGetTable("APIC", 1, (ACPI_TABLE_HEADER **)&ath); 40 41 if(ACPI_FAILURE(as)) { 42 ACPI_DEBUG("No MADT found in ACPI! Cannot initialize I/O APICs.\n"); 43 return -1; 44 } 45 else { 46 madt = (ACPI_TABLE_MADT*)ath; 47 } 48 49 ACPI_DEBUG("MADT Revision: %u, Size=%u, OEM=%s\n", madt->Header.Revision, 50 madt->Header.Length, madt->Header.OemId); 51 52 //uint8_t revision = madt->Header.Revision; 53 54 // Walk all subtables (after the main table entries) 55 void *p = (void *)madt + sizeof(ACPI_TABLE_MADT); 56 while(p < (void *)madt + madt->Header.Length) { 57 ACPI_SUBTABLE_HEADER *sh = (ACPI_SUBTABLE_HEADER *)p; 58 59 uint8_t length = sh->Length; 60 61 switch(sh->Type) { 62 case ACPI_MADT_TYPE_LOCAL_APIC: 63 { 64 debug_printf("WARNING LOCAL APIC found on non x86\n"); 65 } 66 break; 67 68 case ACPI_MADT_TYPE_IO_APIC: 69 { 70 debug_printf("WARNING IO APIC found on non x86\n"); 71 } 72 break; 73 74 case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: 75 { 76 debug_printf("WARNING INTERRUPT_OVERRIDE found on non x86\n"); 77 } 78 break; 79 80 case ACPI_MADT_TYPE_LOCAL_APIC_NMI: 81 debug_printf("WARNING LOCAL_APIC_NMI found on non x86\n"); 82 break; 83 case ACPI_MADT_TYPE_GENERIC_INTERRUPT: 84 { 85 ACPI_MADT_GENERIC_INTERRUPT *gi = (ACPI_MADT_GENERIC_INTERRUPT *)sh; 86 87 /* 88 * ACPI Spec 6.1 - 5.2.12.14 GIC CPU Interface (GICC) Structure 89 * 90 * CPU Interface Number 91 * GIC's CPU Interface Number. In GICv1/v2 implementations, this 92 * value matches the bit index of the associated processor in the GIC 93 * distributor's GICD_ITARGETSR register. 94 * For GICv3/4 implementations this field must be provided by the 95 * platform, if compatibility mode is supported. 96 * If it is not supported by the implementation, then this field must be 97 * zero 98 * 99 * UID 100 * The OS associates this GICC Structure with a processor device 101 * object in the namespace when the _UID child object of the 102 * processor device evaluates to a numeric value that matches the 103 * numeric value in this field. 104 * 105 * Parking Address 106 * The 64-bit physical address of the processor's Parking Protocol 107 * mailbox 108 * 109 * ParkingVersion 110 * Version of the ARM-Processor Parking Protocol implemented. See 111 * http://uefi.org/acpi. The document link is listed under 112 * "Multiprocessor Startup for ARM Platforms" 113 * For systems that support PSCI exclusively and do not support the 114 * parking protocol, this field must be set to 0 115 * 116 * BaseAddress 117 * On GICv1/v2 systems and GICv3/4 systems in GICv2 compatibility 118 * mode, this field holds the 64-bit physical address at which the 119 * processor can access this GIC CPU Interface. If provided here, the 120 * "Local Interrupt Controller Address" field in the MADT must be 121 * ignored by the OSPM. 122 * 123 * GICV 124 * Address of the GIC virtual CPU interface registers. If the platform 125 * is not presenting a GICv2 with virtualization extensions this field 126 * can be 0. 127 * 128 * GICH 129 * Address of the GIC virtual interface control block registers. If the 130 * platform is not presenting a GICv2 with virtualization extensions 131 * this field can be 0. 132 * 133 * On systems supporting GICv3 and above, this field holds the 64-bit 134 * physical address of the associated Redistributor. If all of the GIC 135 * Redistributors are in the always-on power domain, GICR structures 136 * should be used to describe the Redistributors instead, and this field 137 * must be set to 0. 138 * 139 * MPIDR 140 * This fields follows the MPIDR formatting of ARM architecture. 141 * If the implements ARMv7 architecure then the format must be: 142 * Bits [63:24] Must be zero 143 * Bits [23:16] Aff2 : Match Aff2 of target processor MPIDR 144 * Bits [15:8] Aff1 : Match Aff1 of target processor MPIDR 145 * Bits [7:0] Aff0 : Match Aff0 of target processor MPIDR 146 * 147 * For platforms implementing ARMv8 the format must be: 148 * Bits [63:40] Must be zero 149 * Bits [39:32] Aff3 : Match Aff3 of target processor MPIDR 150 * Bits [31:24] Must be zero 151 * Bits [23:16] Aff2 : Match Aff2 of target processor MPIDR 152 * Bits [15:8] Aff1 : Match Aff1 of target processor MPIDR 153 * Bits [7:0] Aff0 : Match Aff0 of target processor MPIDR 154 */ 155 156/* 157 printf("Found GENERIC_INTERRUPT: BaseAddress=0x%016" 158 PRIx64 159 ", ParkingVersion=0x%" PRIu32 160 ", ParkedAddress=0x%016" PRIx64 161 ", GicvBaseAddress=0x%016" PRIx64 162 ", GichBaseAddress=0x%016" PRIx64 163 ", GicrBaseAddress=0x%016" PRIx64 164 ", CpuInterfaceNumber=%" PRIu32 ", Uid=%" PRIu32 165 ", ArmMpidr =%" PRIu64 "\n", 166 gi->BaseAddress, gi->ParkingVersion, gi->ParkedAddress, gi->GicvBaseAddress, gi->GichBaseAddress, 167 gi->GicrBaseAddress, gi->CpuInterfaceNumber, gi->Uid, gi->ArmMpidr); 168 169 */ 170 171 coreid_t barrelfish_id; 172 if (my_hw_id == gi->Uid) { 173 barrelfish_id = 0; // BSP core is 0 174 } 175 else { 176 barrelfish_id = barrelfish_id_counter++; 177 } 178 179 /* TODO: figure out which facts you need */ 180 skb_add_fact("generic_interrupt(%"PRIu64",%"PRIu64",%"PRIu64",%"PRIu64",%d,%d).", 181 gi->BaseAddress, gi->GicvBaseAddress, gi->GichBaseAddress, 182 gi->ParkedAddress, gi->CpuInterfaceNumber, gi->Uid); 183 184 if (gi->ParkingVersion) { 185 /* parking */ 186 skb_add_fact("boot_driver_entry(%"PRIu64",%s).", gi->ArmMpidr, 187 "armBootParking"); 188 } else { 189 /* psci */ 190 skb_add_fact("boot_driver_entry(%"PRIu64",%s).", gi->ArmMpidr, 191 "armBootPSCI"); 192 } 193 194 errval_t err = oct_set(HW_PROCESSOR_ARMV8_RECORD_FORMAT, 195 barrelfish_id, 196 gi->Flags & ACPI_MADT_ENABLED, 197 barrelfish_id, 198 gi->ArmMpidr, 199 CURRENT_CPU_TYPE, 200 gi->CpuInterfaceNumber, 201 gi->Uid, 202 gi->Flags, 203 gi->ParkingVersion, 204 gi->PerformanceInterrupt, 205 gi->ParkedAddress, 206 gi->BaseAddress, 207 gi->GicvBaseAddress, 208 gi->GichBaseAddress, 209 gi->VgicInterrupt, 210 gi->GicrBaseAddress, 211 gi->ArmMpidr); 212 if (err_is_fail(err)) { 213 USER_PANIC_ERR(err, "failed to set record"); 214 } 215 } 216 break; 217 case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: 218 { 219 ACPI_MADT_GENERIC_DISTRIBUTOR *gd = (ACPI_MADT_GENERIC_DISTRIBUTOR *)sh; 220 debug_printf("Found GENERIC DISTRIBUTOR: BaseAddress=0x%016" 221 PRIx64 ", GicId=%" PRIu32 ", Version=%" PRIu8 222 ", GlobalIrqBase=%" PRIu32 "\n", gd->BaseAddress, 223 gd->GicId , gd->Version, gd->GlobalIrqBase); 224 skb_add_fact("generic_distributor(%"PRIu64",%d,%d,%d).", 225 gd->BaseAddress, gd->GicId, gd->GlobalIrqBase, gd->Version); 226 } 227 228 229 230 break; 231 case ACPI_MADT_TYPE_GENERIC_MSI_FRAME: 232 { 233 ACPI_MADT_GENERIC_MSI_FRAME *msi = (ACPI_MADT_GENERIC_MSI_FRAME *)sh; 234 ACPI_DEBUG("Found local APIC GENERIC MSI FRAME: BaseAddress=0x%016" 235 PRIx64 ", MsiFrameId=%" PRIu32 "\n", msi->BaseAddress, 236 msi->MsiFrameId); 237 skb_add_fact("generic_msi_frame(%"PRIu64",%d,%d,%d,%d).", 238 msi->BaseAddress, msi->MsiFrameId, msi->SpiBase, 239 msi->SpiBase, msi->Flags); 240 } 241 break; 242 case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR: 243 { 244 ACPI_MADT_GENERIC_REDISTRIBUTOR *grd = (ACPI_MADT_GENERIC_REDISTRIBUTOR *)sh; 245 debug_printf("Found GENERIC REDISTRIBUTOR: BaseAddress=0x%016" 246 PRIx64 ", Length=%" PRIu32 "\n", grd->BaseAddress, 247 grd->Length); 248 skb_add_fact("generic_redistributor(%"PRIu64",%d).", 249 grd->BaseAddress, grd->Length); 250 } 251 break; 252 case ACPI_MADT_TYPE_GENERIC_TRANSLATOR: 253 { 254 ACPI_MADT_GENERIC_TRANSLATOR *gt = (ACPI_MADT_GENERIC_TRANSLATOR *)sh; 255 ACPI_DEBUG("Found local APIC GENERIC TRANSLATOR: TranslationId=%" 256 PRIu32 ", BaseAddress=0x%016" PRIx64 "\n", gt->TranslationId, 257 gt->BaseAddress); 258 skb_add_fact("generic_translator(%"PRIu64",%d).", 259 gt->BaseAddress, gt->TranslationId); 260 } 261 break; 262 default: 263 ACPI_DEBUG("Unknown subtable type %d\n", sh->Type); 264 break; 265 } 266 assert(length); 267 p += length; 268 } 269 270 271#if 0 272 /* XXX: Quirk hack for QEMU 273 * There is no override for the timer interrupt, although it appears as IRQ2. 274 */ 275 if (strncmp(madt->Header.OemId, "QEMU", 4) == 0 276 && interrupt_overrides[0] == 0) { 277 278 } 279#endif 280 281 ACPI_DEBUG("DONE: MADT Element %p / %p\n", p, (void *)madt + madt->Header.Length); 282 283 return 0; 284} 285 286errval_t enable_and_route_interrupt(int gsi, coreid_t dest, int vector) 287{ 288 USER_PANIC("NYI!"); 289 return SYS_ERR_OK; 290} 291 292 293errval_t acpi_interrupts_arch_setup(void) 294{ 295 return SYS_ERR_OK; 296} 297