1/** 2 * \file acpi_parse_madt.c 3 * \brief 4 */ 5 6 7/* 8 * Copyright (c) 2017 ETH Zurich. 9 * All rights reserved. 10 * 11 * This file is distributed under the terms in the attached LICENSE file. 12 * If you do not find this file, copies can be found by writing to: 13 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 14 */ 15 16#include <barrelfish/barrelfish.h> 17 18#include <arch/aarch64/hw_records_arch.h> 19#include <arch/x86_64/hw_records_arch.h> 20 21#include <skb/skb.h> 22#include <octopus/getset.h> 23#include <trace/trace.h> 24 25 26#include "acpi_debug.h" 27#include "acpi_shared.h" 28 29static coreid_t barrelfish_id_counter = 1; 30 31 32/* 33 * local_apic(proc_id:8, apicid:8, flags:32); 34 * io_apic(apic_id:8, pbaseaddress:32, globalirqbase:32) 35 * interrupt_override(bus:8, sourceirq:8, globalirq:32, intiflags:16) 36 * nmi_source(intiflags:16, globalirq:32) 37 * local_apic_nmi(proc_id:8, intiflags:16, lint:8) 38 * local_apic_overritde(address:64) 39 * io_sapic(id:8, globalirqbase:32, address:64) 40 * local_sapic(proc_id:8, id:8, eid:8, lapicflags:32, uid:32, uidstring:x) 41 * interrupt_source(intiflags:16, type:8, id:8, eid:8, iosapicvector:8, globalirq:32, flags:32) 42 * local_x2apic(localapicid:32, laicflags:32,uid:32) 43 * local_x2apic_nmi(intiflags:16, uid:32, lint:8) 44 * generic_interrupt( 45 CpuInterfaceNumber:32; Uid:32, Flags:32, ParkingVersion:32, 46 PerformanceInterrupt:32, ParkedAddress:64, BaseAddress:64, 47 GicvBaseAddress:64, GichBaseAddress:64, VgicInterrupt:32, GicrBaseAddress:64, 48 ArmMpidr:64, EfficiencyClass:8) 49 * generic_distributor(gicid:32, baseaddr:64, globalirqbase:32, version:8) 50 * generic_msi_frame(msiframeid:32, baseaddr:64, flags:32, spicount:16, spibase:16) 51 * generic_redistributor(baseaddr: 64, length:32) 52 * generic_translator(translationid:32, baseaddr:64) 53 */ 54 55#define SKB_SCHEMA_LOCAL_APIC \ 56 "local_apic(%" PRIu8 ", %" PRIu8 ", %" PRIu32 ")." 57#define SKB_SCHEMA_IO_APIC \ 58 "io_apic(%" PRIu8 ", %" PRIu32 ", %" PRIu32 ")." 59#define SKB_SCHEMA_INTERRUPT_OVERRIDE \ 60 "interrupt_override(%" PRIu8 ", %" PRIu8 ", %" PRIu32 ", %" PRIu16 ")." 61#define SKB_SCHEMA_NMI_SOURCE \ 62 "nmi_source(%" PRIu16 ", %" PRIu32 ")." 63#define SKB_SCHEMA_LOCAL_APIC_NMI \ 64 "local_apic_nmi(%" PRIu8 ", %" PRIu16 ", %" PRIu8 ")." 65#define SKB_SCHEMA_LOCAL_APIC_OVERRIDE \ 66 "local_apic_override(%" PRIu64 ")." 67#define SKB_SCHEMA_IO_SAPIC \ 68 "io_sapic(%" PRIu8 ", %" PRIu32 ", %" PRIu64 ")." 69#define SKB_SCHEMA_LOCAL_SAPIC \ 70 "local_sapic(%" PRIu8 ", %" PRIu8 ", %" PRIu8", %" PRIu32 ", %" PRIu32 ", %s)." 71#define SKB_SCHEMA_INTERRUPT_SOURCE \ 72 "interrupt_source(%" PRIu16 ", %" PRIu8 ", %" PRIu8", %" PRIu8 ", %" PRIu32 ", %" PRIu32 ")." 73#define SKB_SCHEMA_LOCAL_X2APIC \ 74 "local_x2apic(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")." 75#define SKB_SCHEMA_LOCAL_X2APIC_NMI \ 76 "local_x2apic_nmi(%" PRIu16 ", %" PRIu32 ", %" PRIu8 ")." 77#define SKB_SCHEMA_GENERIC_INTERRUPT \ 78 "generic_interrupt(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", %" \ 79 PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu32 ", %" \ 80 PRIu64 ", %" PRIu64 ", %" PRIu8 ")." 81#define SKB_SCHEMA_GENERIC_DISTRIBUTOR \ 82 "generic_distributor(%" PRIu32 ", %" PRIu64 ", %" PRIu32 ", %" PRIu8 ")." 83#define SKB_SCHEMA_GENERIC_MSI_FRAME \ 84 "generic_msi_frame(%" PRIu32 ", %" PRIu64 ", %" PRIu32 ", %" PRIu16 ", %" PRIu16 ")." 85#define SKB_SCHEMA_GENERIC_REDISTRIBUTOR \ 86 "generic_redistributor(%" PRIu64 ", %" PRIu32 ")." 87#define SKB_SCHEMA_GENERIC_TRANSLATOR \ 88 "generic_translator(%" PRIu32 ", %" PRIu64 ")." 89 90 91 92 93static errval_t parse_entry_local_apic(ACPI_MADT_LOCAL_APIC *s) 94{ 95 errval_t err; 96 97 APCI_DEBUG(SKB_SCHEMA_LOCAL_APIC, s->ProcessorId, s->Id, s->LapicFlags); 98 99 ACPI_DEBUG("Found local APIC: CPU = %d, ID = %d, usable = %d\n", 100 s->ProcessorId, s->Id, 101 s->LapicFlags & ACPI_MADT_ENABLED); 102 103 trace_event(TRACE_SUBSYS_ACPI, TRACE_EVENT_ACPI_APIC_ADDED, s->ProcessorId); 104 105 err = skb_add_fact(SKB_SCHEMA_LOCAL_APIC, s->ProcessorId, s->Id, s->LapicFlags); 106 if (err_is_fail(err)) { 107 return err; 108 } 109 110 coreid_t barrelfish_id; 111 if (my_hw_id == s->Id) { 112 barrelfish_id = 0; // BSP core is 0 113 } else { 114 barrelfish_id = barrelfish_id_counter++; 115 } 116 117 /* compatibility */ 118 skb_add_fact("apic(%d,%d,%"PRIu32").", s->ProcessorId, s->Id, 119 s->LapicFlags & ACPI_MADT_ENABLED); 120 121 return oct_set(HW_PROCESSOR_X86_RECORD_FORMAT, barrelfish_id, 122 s->LapicFlags & ACPI_MADT_ENABLED, barrelfish_id, 123 s->Id, CPU_X86_64, s->ProcessorId, s->Id); 124} 125 126static errval_t parse_entry_io_apic(ACPI_MADT_IO_APIC *s) 127{ 128 errval_t err; 129 130 ACPI_DEBUG(SKB_SCHEMA_IO_APIC, s->Id, s->Address, s->GlobalIrqBase); 131 skb_add_fact(SKB_SCHEMA_IO_APIC, s->Id, s->Address, s->GlobalIrqBase); 132 133 ACPI_DEBUG("Found I/O APIC: ID = %d, mem base = 0x%"PRIx32", " 134 "INTI base = %"PRIu32"\n", s->Id, s->Address, s->GlobalIrqBase); 135 136 skb_add_fact("ioapic(%d,%"PRIu32",%"PRIu32").", s->Id, s->Address, s->GlobalIrqBase); 137 skb_add_fact("memory_region(%"PRIu32",%u,%zu, %u,%u).", 138 s->Address, 139 BASE_PAGE_BITS, //as used elswhere in acpi.c 140 ((size_t)1) << BASE_PAGE_BITS, //as used elswhere in acpi.c 141 RegionType_IOAPIC, 142 0); 143 144 char ioapic_lbl[255]; 145 char query_buf[1024]; 146 147 snprintf(query_buf,1024, "add_ioapic_controller(Lbl, %d, %d).", 148 s->Id, s->GlobalIrqBase); 149 err = skb_execute(query_buf); 150 if(err_is_fail(err)){ 151 DEBUG_SKB_ERR(err,"add_ioapic_controller"); 152 } 153 skb_read_output_at(strchr(skb_get_output(),'\n'),"%s",ioapic_lbl); 154 ACPI_DEBUG("Added ioapic ctrl, lbl=%s\n",ioapic_lbl); 155 156 err = init_one_ioapic(s, ioapic_lbl); 157 if(err_is_fail(err)) { 158 DEBUG_ERR(err, "Unable to initialize I/O APIC (ID = %d)", 159 s->Id); 160 abort(); 161 } 162 163 return SYS_ERR_OK; 164} 165 166static errval_t parse_entry_interrupt_override(ACPI_MADT_INTERRUPT_OVERRIDE *s) 167{ 168 ACPI_DEBUG(SKB_SCHEMA_INTERRUPT_OVERRIDE, s->Bus, s->SourceIrq, s->GlobalIrq, 169 s->IntiFlags); 170 171 skb_add_fact(SKB_SCHEMA_INTERRUPT_OVERRIDE, s->Bus, s->SourceIrq, s->GlobalIrq, 172 s->IntiFlags); 173 174 ACPI_DEBUG("Found interrupt override: bus = %d, bus_irq = %d, " 175 "GSI = %"PRIu32", flags = %x\n", s->Bus, s->SourceIrq, 176 s->GlobalIrq, s->IntiFlags); 177 178 // ACPI spec says these are only for ISA interrupts 179 assert(s->SourceIrq < N_ISA_INTERRUPTS); 180 181 interrupt_overrides[s->SourceIrq] = s->GlobalIrq; 182 183 if (s->IntiFlags == 0) { 184 break; 185 } 186 187 lpc_ioapic_redir_tbl_t entry = ioapic_redir_tmpl_isa; 188 struct ioapic *a = find_ioapic(s->GlobalIrq); 189 if (a == NULL) { 190 ACPI_DEBUG("Warning: unknown IOAPIC for GSI %"PRIu32", ignored" 191 " interrupt override flags.\n", s->GlobalIrq); 192 break; 193 } 194 195 // Set polarity 196 assert((s->IntiFlags & ACPI_MADT_POLARITY_MASK) 197 != ACPI_MADT_POLARITY_RESERVED); 198 199 switch(s->IntiFlags & ACPI_MADT_POLARITY_MASK) { 200 case ACPI_MADT_POLARITY_ACTIVE_HIGH: 201 entry.polarity = lpc_ioapic_active_high; 202 break; 203 204 case ACPI_MADT_POLARITY_ACTIVE_LOW: 205 entry.polarity = lpc_ioapic_active_low; 206 break; 207 } 208 209 // Set trigger mode 210 assert((s->IntiFlags & ACPI_MADT_TRIGGER_MASK) 211 != ACPI_MADT_TRIGGER_RESERVED); 212 213 switch(s->IntiFlags & ACPI_MADT_TRIGGER_MASK) { 214 case ACPI_MADT_TRIGGER_EDGE: 215 entry.trigger = lpc_ioapic_edge; 216 break; 217 218 case ACPI_MADT_TRIGGER_LEVEL: 219 // XXX: should be lpc_ioapic_level 220 entry.trigger = lpc_ioapic_edge; 221 break; 222 } 223 224 ioapic_setup_inti(a, s->GlobalIrq - a->irqbase, entry); 225 226 return SYS_ERR_OK; 227} 228 229static errval_t parse_entry_nmi_source(ACPI_MADT_NMI_SOURCE *e) 230{ 231 ACPI_DEBUG(SKB_SCHEMA_NMI_SOURCE, e->IntiFlags, e->GlobalIrq); 232 233 return skb_add_fact(SKB_SCHEMA_NMI_SOURCE, e->IntiFlags, e->GlobalIrq);; 234} 235 236static errval_t parse_entry_local_apic_nmi(ACPI_MADT_LOCAL_APIC_NMI *s) 237{ 238 ACPI_DEBUG(SKB_SCHEMA_LOCAL_APIC_NMI, s->ProcessorId, s->IntiFlags, s->Lint); 239 240 /* compatibility entry */ 241 skb_add_fact("apic_nmi(%d,%d,%d).",s->ProcessorId, s->IntiFlags, s->Lint); 242 243 return skb_add_fact(SKB_SCHEMA_LOCAL_APIC_NMI, s->ProcessorId, s->IntiFlags, 244 s->Lint); 245} 246 247static errval_t parse_entry_local_apic_override(ACPI_MADT_LOCAL_APIC_OVERRIDE *e) 248{ 249 ACPI_DEBUG(SKB_SCHEMA_LOCAL_APIC_OVERRIDE, e->Address); 250 251 return skb_add_fact(SKB_SCHEMA_LOCAL_APIC_OVERRIDE, e->Address); 252} 253 254static errval_t parse_entry_io_sapic(ACPI_MADT_IO_SAPIC *e) 255{ 256 ACPI_DEBUG(SKB_SCHEMA_IO_SAPIC, e->Id, e->GlobalIrqBase, e->Address); 257 258 return skb_add_fact(SKB_SCHEMA_IO_SAPIC, e->Id, e->GlobalIrqBase, e->Address); 259} 260 261static errval_t parse_entry_local_sapic(ACPI_MADT_LOCAL_SAPIC *e) 262{ 263 ACPI_DEBUG(SKB_SCHEMA_LOCAL_SAPIC, e->ProcessorId, e->Id, e->Eid, e->LapicFlags, 264 e->Uid, e->UidString); 265 266 return skb_add_facts(SKB_SCHEMA_LOCAL_SAPIC, e->ProcessorId, e->Id, e->Eid, 267 e->LapicFlags, e->Uid, e->UidString);; 268} 269 270static errval_t parse_entry_interrupt_source(ACPI_MADT_INTERRUPT_SOURCE *e) 271{ 272 ACPI_DEBUG(SKB_SCHEMA_INTERRUPT_SOURCE, e->IntiFlags, e->Type, e->Id, e->Eid, 273 e->IoSapicVector, e->GlobalIrq, e->Flags); 274 275 return skb_add_facts(SKB_SCHEMA_INTERRUPT_SOURCE, e->IntiFlags, e->Type, e->Id, 276 e->Eid, e->IoSapicVector, e->GlobalIrq, e->Flags); 277} 278 279static errval_t parse_entry_local_x2apic(ACPI_MADT_LOCAL_X2APIC *e) 280{ 281 ACPI_DEBUG(SKB_SCHEMA_LOCAL_X2APIC, e->LocalApicId, e->LapicFlags, e->Uid); 282 283 return skb_add_facts(SKB_SCHEMA_LOCAL_X2APIC, e->LocalApicId, e->LapicFlags, e->Uid); 284} 285 286static errval_t parse_entry_local_x2apic_nmi(ACPI_MADT_LOCAL_X2APIC_NMI *e) 287{ 288 ACPI_DEBUG(SKB_SCHEMA_LOCAL_X2APIC_NMI, e->Uid, e->Lint); 289 290 return skb_add_facts(SKB_SCHEMA_LOCAL_X2APIC_NMI, e->Uid, e->Lint); 291} 292 293static errval_t parse_entry_generic_interrupt(ACPI_MADT_GENERIC_INTERRUPT *s) 294{ 295 errval_t err; 296 297 ACPI_DEBUG(SKB_SCHEMA_GENERIC_INTERRUPT, s->CpuInterfaceNumber, s->Uid, s->Flags, 298 s->ParkingVersion, s->PerformanceInterrupt, s->ParkedAddress, 299 s->BaseAddress, s->GicvBaseAddress, s->GichBaseAddress, 300 s->VgicInterrupt, s->GicrBaseAddress, s->ArmMpidr, s->EfficiencyClass); 301 302 err = skb_add_facts(SKB_SCHEMA_GENERIC_INTERRUPT, s->CpuInterfaceNumber, 303 s->Uid, s->Flags, s->ParkingVersion, s->PerformanceInterrupt, 304 s->ParkedAddress, s->BaseAddress, s->GicvBaseAddress, 305 s->GichBaseAddress, s->VgicInterrupt, s->GicrBaseAddress, 306 s->ArmMpidr, s->EfficiencyClass); 307 if (err_is_fail(err)) { 308 return err; 309 } 310 311 /* figure out the barrelfish ID */ 312 coreid_t barrelfish_id; 313 if (my_hw_id == s->Uid) { 314 barrelfish_id = 0; // BSP core is 0 315 } else { 316 barrelfish_id = barrelfish_id_counter++; 317 } 318 319 /* figure out the boot protocol */ 320 if (s->ParkingVersion) { 321 /* parking */ 322 err = skb_add_fact("boot_driver_entry(%"PRIu64",%s).", s->ArmMpidr, 323 "armBootParking"); 324 } else { 325 /* psci */ 326 err = skb_add_fact("boot_driver_entry(%"PRIu64",%s).", s->ArmMpidr, 327 "armBootPSCI"); 328 } 329 330 if (err_is_fail(err)) { 331 DEBUG_ERR(err, "failed to add the boot protocol, continuing anyway\n"); 332 } 333 334 /* setting the octopus record */ 335 return oct_set(HW_PROCESSOR_ARMV8_RECORD_FORMAT, barrelfish_id, 336 s->Flags & ACPI_MADT_ENABLED, barrelfish_id, s->ArmMpidr, 337 CPU_ARM8, s->CpuInterfaceNumber, s->Uid, s->Flags, s->ParkingVersion, 338 s->PerformanceInterrupt, s->ParkedAddress, s->BaseAddress, 339 s->GicvBaseAddress, s->GichBaseAddress, s->VgicInterrupt, 340 s->GicrBaseAddress, s->ArmMpidr); 341} 342 343static errval_t parse_entry_generic_distributor(ACPI_MADT_GENERIC_DISTRIBUTOR *s) 344{ 345 ACPI_DEBUG(SKB_SCHEMA_GENERIC_DISTRIBUTOR, s->GicId, s->BaseAddress, 346 s->GlobalIrqBase, s->Version); 347 348 return skb_add_facts(SKB_SCHEMA_GENERIC_DISTRIBUTOR, s->GicId, s->BaseAddress, 349 s->GlobalIrqBase, s->Version); 350} 351 352static errval_t parse_entry_generic_msi_frame(ACPI_MADT_GENERIC_MSI_FRAME *s) 353{ 354 ACPI_DEBUG(SKB_SCHEMA_GENERIC_REDISTRIBUTOR, s->MsiFrameId, s->BaseAddress, 355 s->Flags, s->SpiCount, s->SpiBase); 356 357 return skb_add_facts(SKB_SCHEMA_GENERIC_REDISTRIBUTOR, s->MsiFrameId, 358 s->BaseAddress, s->Flags, s->SpiCount, s->SpiBase); 359} 360 361static errval_t parse_entry_generic_redistributor(ACPI_MADT_GENERIC_REDISTRIBUTOR *s) 362{ 363 ACPI_DEBUG(SKB_SCHEMA_GENERIC_REDISTRIBUTOR, s->BaseAddress, s->Length); 364 365 return skb_add_fact(SKB_SCHEMA_GENERIC_REDISTRIBUTOR, s->BaseAddress, s->Length); 366} 367 368static errval_t parse_entry_generic_translator(ACPI_MADT_GENERIC_TRANSLATOR *s) 369{ 370 ACPI_DEBUG(SKB_SCHEMA_GENERIC_TRANSLATOR, s->TranslationId, s->BaseAddress); 371 372 return skb_add_fact(SKB_SCHEMA_GENERIC_TRANSLATOR, s->TranslationId, 373 s->BaseAddress); 374} 375 376 377 378errval_t acpi_parse_madt(void) 379{ 380 errval_t err; 381 382 ACPI_STATUS as; 383 ACPI_TABLE_MADT *madt; 384 ACPI_TABLE_HEADER *ath; 385 386 // Get the ACPI APIC table (the MADT) 387 as = AcpiGetTable("APIC", 1, (ACPI_TABLE_HEADER **)&ath); 388 389 if(ACPI_FAILURE(as)) { 390 ACPI_DEBUG("No MADT found in ACPI! Cannot initialize I/O APICs.\n"); 391 return -1; // TODO: error value 392 } 393 else { 394 madt = (ACPI_TABLE_MADT*)ath; 395 } 396 397 398 ACPI_DEBUG("MADT Revision: %u, Size=%u, OEM=%s\n", madt->Header.Revision, 399 madt->Header.Length, madt->Header.OemId); 400 401 void *p = (void *)madt + sizeof(ACPI_TABLE_MADT); 402 void *table_end = (void *)madt + madt->Header.Length; 403 404 while(p < table_end) { 405 ACPI_SUBTABLE_HEADER *sh = (ACPI_SUBTABLE_HEADER *)p; 406 407 switch(sh->Type) { 408 case ACPI_MADT_TYPE_LOCAL_APIC : 409 err = parse_entry_local_apic((ACPI_MADT_LOCAL_APIC *)sh); 410 break; 411 case ACPI_MADT_TYPE_IO_APIC : 412 err = parse_entry_io_apic((ACPI_MADT_IO_APIC *)sh); 413 break; 414 case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE : 415 err = parse_entry_interrupt_override((ACPI_MADT_INTERRUPT_OVERRIDE *)sh); 416 break; 417 case ACPI_MADT_TYPE_NMI_SOURCE : 418 err = parse_entry_nmi_source((ACPI_MADT_NMI_SOURCE *)sh); 419 break; 420 case ACPI_MADT_TYPE_LOCAL_APIC_NMI : 421 err = parse_entry_local_apic_nmi((ACPI_MADT_LOCAL_APIC_NMI *)sh); 422 break; 423 case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE : 424 err = parse_entry_local_apic_override((ACPI_MADT_LOCAL_APIC_OVERRIDE *)sh); 425 break; 426 case ACPI_MADT_TYPE_IO_SAPIC : 427 err = parse_entry_io_sapic((ACPI_MADT_IO_SAPIC *)sh); 428 break; 429 case ACPI_MADT_TYPE_LOCAL_SAPIC : 430 err = parse_entry_local_sapic((ACPI_MADT_LOCAL_SAPIC *)sh); 431 break; 432 case ACPI_MADT_TYPE_INTERRUPT_SOURCE : 433 err = parse_entry_interrupt_source((ACPI_MADT_INTERRUPT_SOURCE *)sh); 434 break; 435 case ACPI_MADT_TYPE_LOCAL_X2APIC : 436 err = parse_entry_local_x2apic((ACPI_MADT_LOCAL_X2APIC *)sh); 437 break; 438 case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI : 439 err = parse_entry_local_x2apic_nmi((ACPI_MADT_LOCAL_X2APIC_NMI *)sh); 440 break; 441 case ACPI_MADT_TYPE_GENERIC_INTERRUPT : 442 err = parse_entry_generic_interrupt((ACPI_MADT_GENERIC_INTERRUPT *)sh); 443 break; 444 case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR : 445 err = parse_entry_generic_distributor((ACPI_MADT_GENERIC_DISTRIBUTOR *)sh); 446 break; 447 case ACPI_MADT_TYPE_GENERIC_MSI_FRAME : 448 err = parse_entry_generic_msi_frame((ACPI_MADT_GENERIC_MSI_FRAME *)sh); 449 break; 450 case ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR : 451 err = parse_entry_generic_redistributor((ACPI_MADT_GENERIC_REDISTRIBUTOR *)sh); 452 break; 453 case ACPI_MADT_TYPE_GENERIC_TRANSLATOR : 454 err = parse_entry_generic_translator((ACPI_MADT_GENERIC_TRANSLATOR *)sh); 455 break; 456 default: 457 /* reserved */ 458 err = SYS_ERR_OK; 459 } 460 461 if (err_is_fail(err)) { 462 DEBUG_ERR(err, "failed to parse the entry. continuing\n"); 463 } 464 465 assert(sh->Length); 466 p += sh->Length; 467 } 468 469 return SYS_ERR_OK; 470} 471