1/** 2 * \file 3 * \brief ACPI management 4 */ 5 6/* 7 * Copyright (c) 2007, 2008, 2009, 2010, 2016 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, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdio.h> 16#include <barrelfish/barrelfish.h> 17#include <barrelfish/nameservice_client.h> 18#include <barrelfish_kpi/types.h> 19#include <acpi.h> 20#include <mm/mm.h> 21#include <octopus/getset.h> 22#include <octopus/barrier.h> 23#include <skb/skb.h> 24#include <pci/confspace/pci_confspace.h> 25#include "acpi_shared.h" 26#include "acpi_debug.h" 27 28#ifdef ACPI_HAVE_VTD 29# include "intel_vtd.h" 30#endif 31 32#include <trace/trace.h> 33 34#define PCI_LNK_DEV_STRING "PNP0C0F" 35#define METHOD_NAME__DIS "_DIS" 36 37struct pci_resources { 38 uint8_t minbus, maxbus; 39 lpaddr_t minmem, maxmem; 40 struct pci_address addr; 41}; 42 43struct memrange { 44 lpaddr_t min; 45 lpaddr_t limit; 46}; 47 48#define MAX_RESERVED_MEM_REGIONS 32 49// Hack: reserved memory regions (eg. PCIe config space mapping) 50static struct memrange reserved_memory[MAX_RESERVED_MEM_REGIONS]; 51static int n_reserved_memory_regions; 52 53static ACPI_STATUS pci_resource_walker(ACPI_RESOURCE *resource, void *context) 54{ 55 struct pci_resources *ret = context; 56// uint64_t granularity, min, max, translationoffset, addrlength; 57 lpaddr_t granularity, min, max, translationoffset, addrlength; 58 59 switch (resource->Type) { 60 case ACPI_RESOURCE_TYPE_ADDRESS16: 61 granularity = resource->Data.Address16.Address.Granularity; 62 min = resource->Data.Address16.Address.Minimum; 63 max = resource->Data.Address16.Address.Maximum; 64 translationoffset = resource->Data.Address16.Address.TranslationOffset; 65 addrlength = resource->Data.Address16.Address.AddressLength; 66 break; 67 68 case ACPI_RESOURCE_TYPE_ADDRESS32: 69 granularity = resource->Data.Address32.Address.Granularity; 70 min = resource->Data.Address32.Address.Minimum; 71 max = resource->Data.Address32.Address.Maximum; 72 translationoffset = resource->Data.Address32.Address.TranslationOffset; 73 addrlength = resource->Data.Address32.Address.AddressLength; 74 break; 75 76 case ACPI_RESOURCE_TYPE_ADDRESS64: 77 granularity = resource->Data.Address64.Address.Granularity; 78 min = resource->Data.Address64.Address.Minimum; 79 max = resource->Data.Address64.Address.Maximum; 80 translationoffset = resource->Data.Address64.Address.TranslationOffset; 81 addrlength = resource->Data.Address32.Address.AddressLength; 82 break; 83 84 default: 85 return AE_OK; 86 } 87 88 /* Ignore bogus entries with zero length */ 89 if (addrlength == 0) { 90 ACPI_DEBUG("Warning: ignoring zero-length address resource\n"); 91 return AE_OK; 92 } 93 94 /* TODO: handle non-fixed regions. Does anything other than QEMU do this? */ 95 if (resource->Data.Address.MinAddressFixed != ACPI_ADDRESS_FIXED || 96 resource->Data.Address.MaxAddressFixed != ACPI_ADDRESS_FIXED) { 97 ACPI_DEBUG("Warning: Treating non-fixed address range resource as fixed\n"); 98 } 99 100 switch (resource->Data.Address.ResourceType) { 101 case ACPI_BUS_NUMBER_RANGE: 102 assert(max > 0); 103 assert(ret->maxbus == 0); /* shouldn't have more than one of these */ 104 ret->minbus = min; 105 ret->maxbus = max; 106 break; 107 108 case ACPI_MEMORY_RANGE: 109 ACPI_DEBUG("PCI mem range %lx-%lx granularity 0x%lx translation offset " 110 " 0x%lx length 0x%lx prodcons %u decode %u writeprot %u" 111 " caching %u rangetype %u translation %u\n", min, max, 112 granularity, translationoffset, addrlength, 113 resource->Data.Address.ProducerConsumer, 114 resource->Data.Address.Decode, 115 resource->Data.Address.Info.Mem.WriteProtect, 116 resource->Data.Address.Info.Mem.Caching, 117 resource->Data.Address.Info.Mem.RangeType, 118 resource->Data.Address.Info.Mem.Translation); 119/* 120 // check for overlaps with reserved memory regions 121 for (int i = 0; i < n_reserved_memory_regions; i++) { 122 struct memrange *range = &reserved_memory[i]; 123 if (min < range->limit && max >= range->min) { 124 if (min < range->limit && min >= range->min) { 125 // overlaps with min: take top part 126 min = range->limit; 127 } else if (max - range->limit > range->min - min) { 128 // take top part 129 min = range->limit; 130 } else { 131 // take bottom part 132 max = range->min - 1; 133 } 134 if (min > max) { 135 min = max = 0; 136 } 137 ACPI_DEBUG("mem range overlaps reserved space [%lx,%lx], truncated" 138 " to %lx-%lx\n", range->min, range->limit, min, max); 139 } 140 } 141*/ 142 skb_add_fact("rootbridge_address_window(addr(%u, %u, %u), mem(%"PRIuLPADDR", %"PRIuLPADDR")).", 143 ret->addr.bus, ret->addr.device, ret->addr.function, 144 min, max); 145 if (ret->minmem == ret->maxmem) { 146 /* this is the first region we've seen */ 147 ret->minmem = min; 148 ret->maxmem = max; 149 } else if (min == ret->maxmem + 1) { 150 /* this region extends the existing region */ 151 ret->maxmem = max; 152 } else if (max - min > ret->maxmem - ret->minmem) { 153 /* this region is bigger than the existing region */ 154 ret->minmem = min; 155 ret->maxmem = max; 156 } 157 break; 158 } 159 160 return AE_OK; 161} 162 163#ifdef ACPI_SERVICE_DEBUG 164static ACPI_STATUS resource_printer(ACPI_RESOURCE *res, void *context) 165{ 166 switch(res->Type) { 167 case ACPI_RESOURCE_TYPE_END_TAG: 168 return AE_OK; 169 170 case ACPI_RESOURCE_TYPE_ADDRESS16: 171 printf("addr16\n"); 172 break; 173 case ACPI_RESOURCE_TYPE_ADDRESS32: 174 printf("addr32\n"); 175 break; 176 case ACPI_RESOURCE_TYPE_ADDRESS64: 177 printf("length = %"PRIu32", gran = %"PRIx64", min = %"PRIx64", max = %"PRIx64", transoff " 178 "= %"PRIx64", addrlen = %"PRIx64", index = %hhu, strlen = %hu, string = %s", 179 res->Length, res->Data.Address64.Address.Granularity, 180 res->Data.Address64.Address.Minimum, 181 res->Data.Address64.Address.Maximum, 182 res->Data.Address64.Address.TranslationOffset, 183 res->Data.Address64.Address.AddressLength, 184 res->Data.Address64.ResourceSource.Index, 185 res->Data.Address64.ResourceSource.StringLength, 186 res->Data.Address64.ResourceSource.StringPtr 187 ); 188 break; 189 190 case ACPI_RESOURCE_TYPE_IRQ: 191 { 192 ACPI_RESOURCE_IRQ *irqres = &res->Data.Irq; 193 194 printf("%s, %s triggered, active %s, ", 195 irqres->Sharable ? "shared" : "exclusive", 196 irqres->Triggering ? "edge" : "level", 197 irqres->Polarity ? "low" : "high"); 198 199 if (irqres->InterruptCount > 0) { 200 printf("IRQs:"); 201 for (int i = 0; i < irqres->InterruptCount; i++) { 202 printf(" %d", irqres->Interrupts[i]); 203 } 204 printf(".\n"); 205 } else { 206 printf("no IRQ.\n"); 207 } 208 } 209 break; 210 211 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 212 { 213 ACPI_RESOURCE_EXTENDED_IRQ *irqres = &res->Data.ExtendedIrq; 214 215 printf("%s, %s triggered, active %s, ", 216 irqres->Sharable ? "shared" : "exclusive", 217 irqres->Triggering ? "edge" : "level", 218 irqres->Polarity ? "low" : "high"); 219 220 if (irqres->InterruptCount > 0) { 221 printf("IRQs:"); 222 for (int i = 0; i < irqres->InterruptCount; i++) { 223 printf(" %"PRIu32, irqres->Interrupts[i]); 224 } 225 } else { 226 printf("no IRQ"); 227 } 228 229 ACPI_RESOURCE_SOURCE *src = &irqres->ResourceSource; 230 231 if(src->StringLength > 0) { 232 printf(", resource index %d, source %.*s\n", src->Index, 233 src->StringLength, src->StringPtr); 234 } else { 235 printf(".\n"); 236 } 237 } 238 break; 239 240 default: 241 printf("resource_printer: Unexpected resource type %"PRIu32"\n", res->Type); 242 break; 243 } 244 245 return AE_OK; 246} 247#endif 248 249ACPI_STATUS acpi_eval_integer(ACPI_HANDLE handle, const char *name, ACPI_INTEGER *ret) 250{ 251 assert(ret != NULL); 252 ACPI_STATUS as; 253 char intbuf[sizeof(ACPI_OBJECT)]; 254 ACPI_BUFFER intbufobj = {.Length = sizeof(intbuf), .Pointer = intbuf}; 255 256 as = AcpiEvaluateObjectTyped(handle, (CONST_CAST)name, NULL, &intbufobj, ACPI_TYPE_INTEGER); 257 if (ACPI_SUCCESS(as)) { 258 ACPI_OBJECT *obj = intbufobj.Pointer; 259 *ret = obj->Integer.Value; 260 } 261 262 return as; 263} 264 265static ACPI_STATUS fixed_resource_walker(ACPI_RESOURCE *resource, void *context) 266{ 267 if (resource->Type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { 268 struct memrange range = { 269 .min = resource->Data.FixedMemory32.Address, 270 .limit = resource->Data.FixedMemory32.Address 271 + resource->Data.FixedMemory32.AddressLength 272 }; 273 ACPI_DEBUG("fixed memory resource claimed: 0x%"PRIxLPADDR"-%"PRIxLPADDR"\n", 274 range.min, range.limit); 275 276 /* XXX: TODO: insert something in the SKB */ 277 assert(n_reserved_memory_regions < MAX_RESERVED_MEM_REGIONS); 278 reserved_memory[n_reserved_memory_regions++] = range; 279 skb_add_fact("fixed_memory(%"PRIuLPADDR",%"PRIuLPADDR").", range.min, 280 range.limit); 281 } 282 283 return AE_OK; 284} 285 286static ACPI_STATUS reserve_resources(ACPI_HANDLE handle, UINT32 level, 287 void *context, void **retval) 288{ 289 ACPI_STATUS as; 290 291 /* walk _CRS resources looking for fixed resources */ 292 as = AcpiWalkResources(handle, METHOD_NAME__CRS, fixed_resource_walker, NULL); 293 if (ACPI_FAILURE(as)) { 294 return as; 295 } 296 297 return AE_OK; 298} 299 300/** 301 * \brief Get IRQ routing table by querying _PRT method. 302 * 303 * \param handle Handle to _PRT method. 304 * \param bus Bus number this _PRT method is for. 305 */ 306static void get_irq_routing(ACPI_HANDLE handle, uint8_t bus) 307{ 308 ACPI_STATUS as; 309 char prtbuf[8192]; 310 ACPI_BUFFER bufobj = {.Length = sizeof(prtbuf), .Pointer = prtbuf}; 311 312 char namebuf[256]; 313 ACPI_BUFFER namebufobj = {.Length = sizeof(namebuf), .Pointer = namebuf}; 314 315 as = AcpiGetName(handle, ACPI_FULL_PATHNAME, &namebufobj); 316 if (ACPI_FAILURE(as)) { 317 ACPI_DEBUG("No name found: %s\n", AcpiFormatException(as)); 318 namebuf[0] = 0; 319 } else { 320 assert(namebufobj.Pointer == namebuf); 321 } 322 323 /* do we have an interrupt routing table? */ 324 as = AcpiGetIrqRoutingTable(handle, &bufobj); 325 if (ACPI_FAILURE(as)) { 326 ACPI_DEBUG("No PCI IRQ routing table for (%s) bus %"PRIu8": %s\n", namebuf, bus, AcpiFormatException(as)); 327 return; 328 } 329 330 ACPI_DEBUG("PCI IRQ routing table for (%s) bus %"PRIu8":\n", namebuf, bus); 331 ACPI_PCI_ROUTING_TABLE *prt = bufobj.Pointer; 332 for (; prt->Length; prt = (void *)prt + prt->Length) { 333 uint16_t device = (prt->Address >> 16) & 0xffff; 334 assert((prt->Address & 0xffff) == 0xffff); // any function 335 ACPI_DEBUG(" device %u pin %"PRIu32" %s (index %"PRIu32")\n", 336 device, prt->Pin, *(prt->Source) ? prt->Source : "GSI", 337 prt->SourceIndex); 338 339 if (*prt->Source == 0) { 340 /* this is a global interrupt number */ 341 skb_add_fact("prt(addr(%"PRIu8", %"PRIu16", _), %"PRIu32", gsi(%"PRIu32")).", 342 bus, device, prt->Pin, prt->SourceIndex); 343 continue; 344 } 345 346 ACPI_HANDLE source; 347 as = AcpiGetHandle(handle, prt->Source, &source); 348 if (ACPI_FAILURE(as)) { 349 ACPI_DEBUG(" failed lookup: %s\n", AcpiFormatException(as)); 350 continue; 351 } 352 353 assert(device < PCI_NDEVICES); 354 assert(prt->Pin < PCI_NINTPINS); 355 356 char *esource = calloc(strlen(prt->Source) * 2, 1); 357 for(int i = 0, j = 0; i < strlen(prt->Source) + 1; i++, j++) { 358 esource[j] = prt->Source[i]; 359 if(prt->Source[i] == '\\') { 360 esource[++j] = '\\'; 361 } 362 } 363 skb_add_fact("prt(addr(%"PRIu8", %"PRIu16", _), %"PRIu32", pir(\"%s\")).", 364 bus, device, prt->Pin, esource); 365 366#ifdef ACPI_SERVICE_DEBUG /* debug code to dump resources */ 367 ACPI_DEBUG(" INITIAL: "); 368 as = AcpiWalkResources(source, METHOD_NAME__CRS, 369 resource_printer, NULL); 370 if (ACPI_FAILURE(as)) { 371 ACPI_DEBUG(" failed walking _CRS: %s\n", AcpiFormatException(as)); 372 } 373 374 ACPI_DEBUG(" POSSIBLE: "); 375 as = AcpiWalkResources(source, METHOD_NAME__PRS, 376 resource_printer, NULL); 377 if (ACPI_FAILURE(as)) { 378 ACPI_DEBUG(" failed walking _PRS: %s\n", AcpiFormatException(as)); 379 } 380#endif 381 382 uint8_t data[512]; 383 ACPI_BUFFER buf = { .Length = sizeof(data), .Pointer = &data }; 384 as = AcpiGetPossibleResources(source, &buf); 385 if (ACPI_FAILURE(as)) { 386 ACPI_DEBUG(" failed retrieving _PRS: %s\n", 387 AcpiFormatException(as)); 388 free(esource); 389 continue; 390 } 391 392 for(ACPI_RESOURCE *res = buf.Pointer; 393 (void *)res < buf.Pointer + buf.Length; 394 res = (ACPI_RESOURCE *)(((char *)res) + res->Length)) { 395 396 if(res->Type == ACPI_RESOURCE_TYPE_END_TAG) { 397 break; 398 } 399 400 switch(res->Type) { 401 case ACPI_RESOURCE_TYPE_IRQ: 402 { 403 ACPI_RESOURCE_IRQ *irqres = &res->Data.Irq; 404 //printf("IRQs:"); 405 for (int i = 0; i < irqres->InterruptCount; i++) { 406 skb_add_fact("pir(\"%s\", %u).", 407 esource, irqres->Interrupts[i]); 408 //printf(" %d", irqres->Interrupts[i]); 409 } 410 //printf("\n"); 411 break; 412 } 413 414 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: 415 { 416 ACPI_RESOURCE_EXTENDED_IRQ *irqres = &res->Data.ExtendedIrq; 417 //printf("Extended IRQs:"); 418 for (int i = 0; i < irqres->InterruptCount; i++) { 419 //printf(" %d", irqres->Interrupts[i]); 420 skb_add_fact("pir(\"%s\", %"PRIu32").", 421 esource, irqres->Interrupts[i]); 422 } 423 //printf("\n"); 424 break; 425 } 426 427 default: 428 printf("Unknown resource type: %"PRIu32"\n", res->Type); 429 USER_PANIC("NYI"); 430 break; 431 } 432 } 433 434 errval_t err; 435 err = skb_execute_query("add_pcilnk_controller_by_name(\"%s\", Lbl), " 436 "writeln(Lbl).", esource); 437 if(err_is_fail(err)){ 438 DEBUG_SKB_ERR(err, "add_pcilnk_controller_by_name"); 439 } 440 free(esource); 441 } 442} 443 444errval_t acpi_get_irqtable_device(ACPI_HANDLE parent, 445 acpi_pci_address_t device, ACPI_HANDLE *child, uint8_t bus) 446{ 447 448 *child = NULL; 449 450 if(parent == NULL) { 451 return ACPI_ERR_INVALID_PATH_NAME; 452 } 453 454 // For each children of parent 455 for(;;) { 456 ACPI_STATUS as = 457 AcpiGetNextObject(ACPI_TYPE_DEVICE, parent, *child, child); 458 459 if(as == AE_NOT_FOUND || *child == NULL) { 460 break; //Goto error out 461 } 462 463 if(ACPI_FAILURE(as)) { 464 ACPI_DEBUG("Error looking up ACPI children.\n"); 465 abort(); 466 } 467 468 // look for a _ADR node, which tells us the bridge's configuration space 469 ACPI_INTEGER addr; 470 as = acpi_eval_integer(*child, "_ADR", &addr); 471 if (ACPI_FAILURE(as)) { 472 ACPI_DEBUG("No _ADR method found !?!.\n"); 473 continue; 474 } 475 476 acpi_pci_address_t bridgeaddr; 477 bridgeaddr.bus = 0; 478 bridgeaddr.device = (addr >> 16) & 0xffff; 479 bridgeaddr.function = addr & 0xffff; 480 481 if(device.device == bridgeaddr.device 482 && device.function == bridgeaddr.function) { 483 get_irq_routing(*child, bus); 484 return SYS_ERR_OK; 485 } 486 } 487 488 // Error output 489 char namebuf[128]; 490 ACPI_BUFFER buf = { .Length = sizeof(namebuf), .Pointer = namebuf }; 491 ACPI_STATUS s; 492 s = AcpiGetName(parent, ACPI_FULL_PATHNAME, &buf); 493 assert(ACPI_SUCCESS(s)); 494 // LH: It seems this is not a fatal condition, but I am really not sure. 495 ACPI_DEBUG("acpi_service: No matching child bridge found. Parent '%s'. Child %"PRIu8 496 ", %"PRIu8", %"PRIu8" \n", namebuf, bus, device.device, device.function); 497 return ACPI_ERR_NO_CHILD_BRIDGE; 498} 499 500static ACPI_STATUS add_pci_lnk_device(ACPI_HANDLE handle, UINT32 level, 501 void *context, void **retval) 502{ 503 ACPI_STATUS as; 504 char namebuf[128]; 505 ACPI_BUFFER bufobj = {.Length = sizeof(namebuf), .Pointer = namebuf}; 506 507 /* get the node's name */ 508 as = AcpiGetName(handle, ACPI_FULL_PATHNAME, &bufobj); 509 if (ACPI_FAILURE(as)) { 510 ACPI_DEBUG("Cannot resolve name of PCI Link device\n"); 511 return as; 512 } 513 assert(bufobj.Pointer == namebuf); 514 ACPI_DEBUG("Discovered PCI Link device (%s). Disabling\n", namebuf); 515 as = AcpiEvaluateObject(handle, METHOD_NAME__DIS, NULL, NULL); 516 if (ACPI_FAILURE(as)) { 517 printf("acpi: Warning: Cannot execute _DIS of PCI Link device (%s)\n", namebuf); 518 return AE_OK; 519 } 520 521 return AE_OK; 522} 523 524 525static ACPI_STATUS add_pci_device(ACPI_HANDLE handle, UINT32 level, 526 void *context, void **retval) 527{ 528 ACPI_STATUS as; 529 char namebuf[128]; 530 ACPI_BUFFER bufobj = {.Length = sizeof(namebuf), .Pointer = namebuf}; 531 532 /* get the node's name */ 533 as = AcpiGetName(handle, ACPI_FULL_PATHNAME, &bufobj); 534 if (ACPI_FAILURE(as)) { 535 return as; 536 } 537 assert(bufobj.Pointer == namebuf); 538 539 ACPI_HANDLE handle2; 540 as = AcpiGetHandle(NULL, namebuf, &handle2); 541 ACPI_DEBUG("acpi get handle for %s\n", namebuf); 542 assert(ACPI_SUCCESS(as) && handle == handle2); 543 544 545 /* look for a _ADR node, which tells us the bridge's configuration space */ 546 ACPI_INTEGER addr; 547 as = acpi_eval_integer(handle, "_ADR", &addr); 548 if (ACPI_FAILURE(as)) { 549 if (as != AE_NOT_FOUND) { 550 debug_printf("add_pci_device: cannot evaluate _ADR: status=%x \n", as); 551 } 552 return AE_OK; 553 } 554 555 struct pci_address bridgeaddr; 556 bridgeaddr.bus = 0; 557 bridgeaddr.device = (addr >> 16) & 0xffff; 558 bridgeaddr.function = addr & 0xffff; 559 560 /* look for a _BBN node, which tells us the bus number on a multi-root box */ 561 ACPI_INTEGER busnum; 562 as = acpi_eval_integer(handle, "_BBN", &busnum); 563 if (ACPI_SUCCESS(as)) { 564 bridgeaddr.bus = busnum; 565 } 566 567 /* walk resources looking for the child bus ranges */ 568 struct pci_resources resources; 569 memset(&resources, 0, sizeof(resources)); 570 571 resources.addr = bridgeaddr; 572 573#ifdef ACPI_SERVICE_DEBUG 574 printf("\nstart PRS\n"); 575 as = AcpiWalkResources(handle, METHOD_NAME__PRS, resource_printer, 576 NULL); 577 printf("\nPRS finished\n"); 578 if (ACPI_FAILURE(as)) { 579 printf("\nPRS failed. Status = %"PRIu32"\n", as); 580// return as; 581 } 582#endif 583 as = AcpiWalkResources(handle, METHOD_NAME__CRS, pci_resource_walker, 584 &resources); 585 if (ACPI_FAILURE(as)) { 586 return as; 587 } 588 589 if (resources.maxbus == 0) { 590 ACPI_DEBUG("%s: invalid PCI root at %u:%u:%u? Ignored.\n", 591 namebuf, bridgeaddr.bus, bridgeaddr.device, bridgeaddr.function); 592 return AE_OK; 593 } 594 595 get_irq_routing(handle, bridgeaddr.bus); 596 597 ACPI_DEBUG("%s: root at %u:%u:%u child buses %u-%u memory 0x%lx-%lx\n", 598 namebuf, bridgeaddr.bus, bridgeaddr.device, bridgeaddr.function, 599 resources.minbus, resources.maxbus, resources.minmem, 600 resources.maxmem + 1); 601 602 skb_add_fact("rootbridge(addr(%u,%u,%u),childbus(%u,%u),mem(%" PRIuPTR ",%" PRIuPTR ")).", 603 bridgeaddr.bus, bridgeaddr.device, bridgeaddr.function, 604 resources.minbus, resources.maxbus, resources.minmem, 605 resources.maxmem); 606 607 // octopus record for rootbridge 608 ACPI_DEBUG("acpi_node: %s\n", namebuf); 609 static char* format = "hw.pci.rootbridge. { bus: %lu, device: %lu, function: %lu, maxbus: %lu, acpi_node: '%s' }"; 610 errval_t err = oct_mset(SET_SEQUENTIAL, format, 611 bridgeaddr.bus, bridgeaddr.device, bridgeaddr.function, 612 resources.maxbus, namebuf); 613 if (err_is_fail(err)) { 614 USER_PANIC_ERR(err, "oct_mset failed.\n"); 615 } 616 // end 617 618 // XXX: enable PCIe for bridge programming 619 /* 620 pcie_enable(); 621 pci_add_root(bridgeaddr, resources.maxbus, handle); 622 pcie_disable();*/ 623 624 return AE_OK; 625} 626 627static int acpi_init(void) 628{ 629 AcpiDbgLevel = 0; // ACPI_DEBUG_DEFAULT | ACPI_LV_INFO | ACPI_LV_EXEC; 630 631 // enable workarounds for non-compliant ACPI bytecode 632 AcpiGbl_EnableInterpreterSlack = TRUE; 633 634 ACPI_STATUS as; 635 636 ACPI_DEBUG("Initializing subsystem...\n"); 637 as = AcpiInitializeSubsystem(); 638 if (ACPI_FAILURE(as)) { 639 ACPI_DEBUG("AcpiInitializeSubsystem failed\n"); 640 return as; 641 } 642 643 ACPI_DEBUG("Initializing tables...\n"); 644 as = AcpiInitializeTables(NULL, 0, false); 645 if (ACPI_FAILURE(as)) { 646 ACPI_DEBUG("AcpiInitializeTables failed\n"); 647 return as; 648 } 649 650 ACPI_DEBUG("Loading tables...\n"); 651 as = AcpiLoadTables(); 652 if (ACPI_FAILURE(as)) { 653 ACPI_DEBUG("AcpiLoadTables failed %s\n", AcpiFormatException(as)); 654 return as; 655 } 656 657 ACPI_DEBUG("Scanning interrupt sources...\n"); 658 int r = init_all_interrupt_sources(); 659 assert(r == 0); 660 661#ifdef USE_KALUGA_DVM 662 char* record; 663 errval_t err = oct_barrier_enter("barrier.acpi", &record, 2); 664 assert(err_is_ok(err)); 665#endif 666 667 ACPI_DEBUG("Enabling full ACPI subsystem...\n"); 668 as = AcpiEnableSubsystem(ACPI_FULL_INITIALIZATION); 669 if (ACPI_FAILURE(as)) { 670 ACPI_DEBUG("AcpiEnableSubsystem failed %s\n", AcpiFormatException(as)); 671 return as; 672 } 673 674 675 return acpi_arch_init(); 676} 677 678/** 679 * \brief Sets system into APIC mode. 680 * 681 * Evaluates _PIC method to argument 1 and disables dual-8259As. 682 * This changes the IRQs reported/set with the interrupt routing (PRT) methods. 683 */ 684static ACPI_STATUS set_apic_mode(void) 685{ 686 ACPI_OBJECT arg1; 687 ACPI_OBJECT_LIST args; 688 ACPI_STATUS as; 689 690 // Evaluate _PIC method to argument 1 691 arg1.Type = ACPI_TYPE_INTEGER; 692 arg1.Integer.Value = 1; 693 args.Count = 1; 694 args.Pointer = &arg1; 695 696 as = AcpiEvaluateObject(ACPI_ROOT_OBJECT, "_PIC", &args, NULL); 697 698 // Bail out if this didn't work 699 if(ACPI_FAILURE(as)) { 700 return as; 701 } 702 703 return AE_OK; 704} 705 706static void process_srat(ACPI_TABLE_SRAT *srat) 707{ 708 ACPI_DEBUG("processing system resource affinity table...\n"); 709 710 assert(!strncmp(srat->Header.Signature, "SRAT", ACPI_NAME_SIZE)); 711 assert(srat->TableRevision == 1); 712 713 void *pos = (void *)srat + sizeof(ACPI_TABLE_SRAT); 714 715 // Scan subtables 716 while(pos < (void *)srat + srat->Header.Length) { 717 ACPI_SUBTABLE_HEADER *shead = pos; 718 719 switch(shead->Type) { 720 case ACPI_SRAT_TYPE_CPU_AFFINITY: 721 { 722 ACPI_SRAT_CPU_AFFINITY *a = (ACPI_SRAT_CPU_AFFINITY *)shead; 723 724 assert(a->Header.Length == 16); 725 726 if(a->Flags & ACPI_SRAT_MEM_ENABLED) { 727 uint32_t proximitydomain = (a->ProximityDomainHi[0] << 24) + 728 (a->ProximityDomainHi[1] << 16) + 729 (a->ProximityDomainHi[2] << 8) + 730 a->ProximityDomainLo; 731 732 ACPI_DEBUG("CPU affinity table:\n"); 733 ACPI_DEBUG("Proximity Domain: %"PRIu32"\n", proximitydomain); 734 ACPI_DEBUG("CPU local APIC ID: %d\n", a->ApicId); 735 ACPI_DEBUG("CPU local SAPIC EID: %d\n", a->LocalSapicEid); 736 737 skb_add_fact("cpu_affinity(%d,%d,%"PRIu32").", 738 a->ApicId, a->LocalSapicEid, proximitydomain); 739 } else { 740 ACPI_DEBUG("CPU affinity table disabled!\n"); 741 } 742 } 743 break; 744 745 case ACPI_SRAT_TYPE_MEMORY_AFFINITY: 746 { 747 ACPI_SRAT_MEM_AFFINITY *a = (ACPI_SRAT_MEM_AFFINITY *)shead; 748 749 assert(a->Header.Length == 40); 750 751 if(a->Flags & ACPI_SRAT_MEM_ENABLED) { 752 ACPI_DEBUG("Memory affinity table:\n"); 753 ACPI_DEBUG("Proximity Domain: %"PRIu32"\n", a->ProximityDomain); 754 ACPI_DEBUG("Base address: 0x%"PRIx64"\n", a->BaseAddress); 755 ACPI_DEBUG("Length: 0x%"PRIx64"\n", a->Length); 756 757 bool hotpluggable = false, nonvolatile = false; 758 if(a->Flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) { 759 hotpluggable = true; 760 } 761 if(a->Flags & ACPI_SRAT_MEM_NON_VOLATILE) { 762 nonvolatile = true; 763 } 764 ACPI_DEBUG("Flags:%s%s\n", 765 hotpluggable ? " Hot-pluggable" : "", 766 nonvolatile ? " Non-volatile" : ""); 767 768 skb_add_fact("memory_affinity(%" PRIu64 ", %" PRIu64 ", %"PRIu32").", 769 a->BaseAddress, a->Length, a->ProximityDomain); 770 771 } else { 772 ACPI_DEBUG("Memory affinity table disabled!\n"); 773 } 774 } 775 break; 776 777 case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: 778 ACPI_DEBUG("Ignoring unsupported x2APIC CPU affinity table.\n"); 779 780 break; 781 782 case ACPI_SRAT_TYPE_GICC_AFFINITY: 783 ACPI_DEBUG("Ignoring unsupported GIC CPU affinity table.\n"); 784 785 break; 786 787 default: 788 ACPI_DEBUG("Ignoring unknown SRAT subtable ID %d.\n", shead->Type); 789 break; 790 } 791 pos += shead->Length; 792 } 793 794 ACPI_DEBUG("done processing srat...\n"); 795} 796 797/** 798 * \brief parses the system locality distance table. 799 * 800 * \param slit pointer to the SLIT table in memory 801 * 802 * This optional table provides a matrix that describes the relative distance 803 * (memory latency) between all System Localities, which are also referred to as 804 * Proximity Domains 805 */ 806static void process_slit(ACPI_TABLE_SLIT *slit) 807{ 808 ACPI_DEBUG("processing system locality distance table...\n"); 809 810 assert(!strncmp(slit->Header.Signature, ACPI_SIG_SLIT, ACPI_NAME_SIZE)); 811 assert(slit->Header.Revision == 1); 812 813 UINT64 locality_count = slit->LocalityCount; 814 815 for (UINT64 i = 0; i < locality_count; ++i) { 816 for (UINT64 j = 0; j < locality_count; ++j) { 817 /* 818 * The diagonal elements of the matrix, the relative distances from a 819 * System Locality to itself are normalized to a value of 10. The 820 * relative distances for the non-diagonal elements are scaled to be 821 * relative to 10 822 */ 823 UINT8 entry = slit->Entry[i*locality_count + j]; 824 skb_add_fact("node_distance(%" PRIu64 ", %" PRIu64 ", %"PRIu8").", i, 825 j, entry); 826 assert(j!=i || entry == 10); 827 ACPI_DEBUG("locality: %lu -> %lu = %u\n", i, j, entry); 828 } 829 } 830 831 ACPI_DEBUG("done processing slit\n"); 832} 833 834/** 835 * \brief parses the Memory Topology Table. 836 * 837 * \param slit pointer to the PMTT table in memory 838 * 839 * This optional table provides a matrix that describes the relative distance 840 * (memory latency) between all System Localities, which are also referred to as 841 * Proximity Domains 842 */ 843static void process_pmtt(ACPI_TABLE_PMTT *pmtt) 844{ 845 ACPI_DEBUG("processing Platform Memory Topology Table....\n"); 846 847 assert(!strncmp(pmtt->Header.Signature, ACPI_SIG_PMTT, ACPI_NAME_SIZE)); 848 assert(pmtt->Header.Revision == 1); 849 850 void *pos = (void *)pmtt + sizeof(ACPI_TABLE_PMTT); 851 852 // Scan subtables 853 while(pos < (void *)pmtt + pmtt->Header.Length) { 854 855 ACPI_PMTT_HEADER *shead = pos; 856 switch(shead->Type) { 857 case ACPI_PMTT_TYPE_SOCKET: 858 { 859 ACPI_PMTT_SOCKET *s = (ACPI_PMTT_SOCKET *)shead; 860 debug_printf("ACPI_PMTT_TYPE_SOCKET SocketId=%u\n", s->SocketId); 861 862 } 863 break; 864 case ACPI_PMTT_TYPE_CONTROLLER: 865 { 866 ACPI_PMTT_CONTROLLER *c = (ACPI_PMTT_CONTROLLER *)shead; 867 debug_printf("ACPI_PMTT_TYPE_CONTROLLER DomainCount=%u\n", 868 c->DomainCount); 869 } 870 break; 871 case ACPI_PMTT_TYPE_DIMM: 872 { 873 ACPI_PMTT_PHYSICAL_COMPONENT *d = (ACPI_PMTT_PHYSICAL_COMPONENT *)shead; 874 debug_printf("ACPI_PMTT_PHYSICAL_COMPONENT MemorySize=%u\n", 875 d->MemorySize); 876 } 877 878 break; 879 default: 880 ACPI_DEBUG("WARNING: invalid type %u\n", shead->Type); 881 break; 882 } 883 pos += shead->Length; 884 } 885 886 887 ACPI_DEBUG("done processing pmtt.\n"); 888} 889 890 891int init_acpi(void) 892{ 893 ACPI_STATUS as; 894 895 ACPI_DEBUG("Initialising ACPI...\n"); 896 as = acpi_init(); 897 if (ACPI_FAILURE(as)) { 898 printf("ACPI: acpi_init() failed: %s\n", AcpiFormatException(as)); 899 return 1; 900 } 901 assert(ACPI_SUCCESS(as)); 902 903#if defined(__ARM_ARCH_8A__) 904 // armv8,psci: check if hvc (EL2 call) should be used instead of smc (EL3 call) 905 skb_add_fact("psci_use_hvc(%"PRIu8").", !!(AcpiGbl_FADT.ArmBootFlags & ACPI_FADT_PSCI_USE_HVC)); 906#elif defined(__x86__) 907 // Put system into APIC mode 908 ACPI_DEBUG("Switching to APIC mode...\n"); 909 as = set_apic_mode(); 910 if (ACPI_FAILURE(as)) { 911 printf("ACPI: Warning: Could not set system to APIC mode! " 912 "Continuing anyway... status: %s\n", AcpiFormatException(as)); 913 skb_add_fact("x86_interrupt_model(pic)."); 914 } else { 915 printf("ACPI: Switched to APIC mode.\n"); 916 skb_add_fact("x86_interrupt_model(apic)."); 917 } 918#endif 919 920 /* look for an MCFG table 921 * this tells us where the PCI express memory-mapped configuration area is 922 */ 923 924 /* 925 ACPI_TABLE_HEADER *mcfg_header; 926 as = AcpiGetTable("MCFG", 1, &mcfg_header); 927 if (ACPI_SUCCESS(as) && mcfg_header->Length >= 928 sizeof(ACPI_TABLE_MCFG) + sizeof(ACPI_MCFG_ALLOCATION)) { 929 ACPI_MCFG_ALLOCATION *mcfg = (void *)mcfg_header + sizeof(ACPI_TABLE_MCFG); 930 ACPI_DEBUG("PCIe enhanced configuration region at 0x%lx " 931 "(segment %u, buses %u-%u)\n", mcfg->Address, 932 mcfg->PciSegment, mcfg->StartBusNumber, mcfg->EndBusNumber); 933 934 skb_add_fact("pcie_confspace(%"PRIu64", %"PRIu16", %"PRIu8", %"PRIu8").", 935 mcfg->Address, mcfg->PciSegment, mcfg->StartBusNumber, 936 mcfg->EndBusNumber); 937 938 //XXX: Not needed as long as PCIe walking is disabled 939 r = pcie_confspace_init(mcfg->Address, mcfg->PciSegment, 940 mcfg->StartBusNumber, mcfg->EndBusNumber); 941 if (r == 0) { 942 // XXX: compute physical address region used by conf space 943 struct memrange confspace = { 944 .min = mcfg->Address, 945 .limit = mcfg->Address + 946 ((lpaddr_t)(mcfg->EndBusNumber + 1 - mcfg->StartBusNumber) << 20) 947 }; 948 reserved_memory[n_reserved_memory_regions++] = confspace; 949 } 950 951 } else { 952 ACPI_DEBUG("No MCFG table found -> no PCIe enhanced configuration\n"); 953 }*/ 954 955 // XXX: disable PCIe memory-mapped config space until after we walk and 956 // prescan all the buses. This is necessary on some AMD boxes, because the 957 // ACPI table includes code to read registers in the HyperTransport config, 958 // and this only appears in IO space. 959 // We need a cleaner way of determining when to use PCIe config space! 960 pcie_disable(); 961 962 /* Find and reserve all memory regions claimed by non-PCI devices */ 963 ACPI_DEBUG("Reserving fixed resources\n"); 964 as = AcpiGetDevices("PNP0C02", reserve_resources, NULL, NULL); 965 if (ACPI_FAILURE(as) && as != AE_NOT_FOUND) { 966 printf("WARNING: AcpiGetDevices failed with error %"PRIu32"\n", as); 967 } 968 assert(ACPI_SUCCESS(as) || as == AE_NOT_FOUND); 969 970 // XXX: PCIe walking disabled, as these also show up as PCI buses, 971 // and we don't currently distinguish between them 972 //ACPI_DEBUG("Walking for PCIe buses\n"); 973 //as = AcpiGetDevices(PCI_EXPRESS_ROOT_HID_STRING, add_pci_device, NULL, NULL); 974 //assert(ACPI_SUCCESS(as)); 975 976 ACPI_DEBUG("Walking for PCI buses\n"); 977 as = AcpiGetDevices(PCI_ROOT_HID_STRING, add_pci_device, NULL, NULL); 978 assert(ACPI_SUCCESS(as)); 979 980 ACPI_DEBUG("Walking for PCI Link devices\n"); 981 as = AcpiGetDevices(PCI_LNK_DEV_STRING, add_pci_lnk_device, NULL, NULL); 982 assert(ACPI_SUCCESS(as)); 983 984 //ACPI_DEBUG("Programming PCI BARs and bridge windows\n"); 985 //pci_program_bridges(); 986 //ACPI_DEBUG("PCI programming completed\n"); 987 988 ACPI_TABLE_HEADER *acpi_table_header; 989 990 as = AcpiGetTable(ACPI_SIG_SRAT, 1, &acpi_table_header); 991 ACPI_DEBUG("has SRAT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no"); 992 if(ACPI_SUCCESS(as)) { 993 process_srat((ACPI_TABLE_SRAT *)acpi_table_header); 994 } 995 996 /* 997 * try to parse the SLIT. This is an optional table 998 */ 999 as = AcpiGetTable(ACPI_SIG_SLIT, 1, &acpi_table_header); 1000 ACPI_DEBUG("has SLIT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no"); 1001 if(ACPI_SUCCESS(as)) { 1002 process_slit((ACPI_TABLE_SLIT *)acpi_table_header); 1003 } 1004 1005 /* 1006 * try to parse the PMTT. This is an optional table 1007 */ 1008 as = AcpiGetTable(ACPI_SIG_PMTT, 1, &acpi_table_header); 1009 ACPI_DEBUG("has PMTT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no"); 1010 if(ACPI_SUCCESS(as)) { 1011 process_pmtt((ACPI_TABLE_PMTT *)acpi_table_header); 1012 } 1013 1014 /* 1015 * try to parse the PSDT. This is an optional table 1016 */ 1017 as = AcpiGetTable(ACPI_SIG_PSDT, 1, &acpi_table_header); 1018 ACPI_DEBUG("has PSDT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no"); 1019 1020 /* 1021 * try to parse the RSDT. This is an optional table 1022 */ 1023 as = AcpiGetTable(ACPI_SIG_RSDT, 1, &acpi_table_header); 1024 ACPI_DEBUG("has RSDT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no"); 1025 1026 /* 1027 * try to parse the SSDT. This is an optional table 1028 */ 1029 as = AcpiGetTable(ACPI_SIG_SSDT, 1, &acpi_table_header); 1030 ACPI_DEBUG("has SSDT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no"); 1031 1032 /* 1033 * try to parse the XSDT. This is an optional table 1034 */ 1035 as = AcpiGetTable(ACPI_SIG_XSDT, 1, &acpi_table_header); 1036 ACPI_DEBUG("has XSDT: %s.\n", ACPI_SUCCESS(as) ? "yes" : "no"); 1037 return 0; 1038} 1039