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