1 /* 2 * 3 * Module Name: osillumostbl - illumos OSL for obtaining ACPI tables 4 * This file is derived from the Intel oslinuxtbl source file. 5 * 6 */ 7 8 /* 9 * Copyright (C) 2000 - 2016, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45 /* 46 * Copyright (c) 2018, Joyent, Inc. 47 */ 48 49 #include <stdarg.h> 50 #include <string.h> 51 #include <stdlib.h> 52 #include <unistd.h> 53 #include <libdevinfo.h> 54 #include "acpidump.h" 55 56 #define _COMPONENT ACPI_OS_SERVICES 57 ACPI_MODULE_NAME("osillumostbl") 58 59 /* List of information about obtained ACPI tables */ 60 61 typedef struct osl_table_info 62 { 63 struct osl_table_info *Next; 64 UINT32 Instance; 65 char Signature[ACPI_NAME_SIZE]; 66 } OSL_TABLE_INFO; 67 68 /* Local prototypes */ 69 static ACPI_STATUS 70 OslTableInitialize(void); 71 static ACPI_STATUS OslTableNameFromFile(char *, char *, UINT32 *); 72 static ACPI_STATUS OslAddTableToList(char *); 73 static ACPI_STATUS OslMapTable(ACPI_SIZE, char *, ACPI_TABLE_HEADER **); 74 static void OslUnmapTable(ACPI_TABLE_HEADER *); 75 static ACPI_STATUS OslLoadRsdp(void); 76 static ACPI_STATUS OslListBiosTables(void); 77 static ACPI_STATUS OslGetBiosTable(char *, UINT32, ACPI_TABLE_HEADER **, 78 ACPI_PHYSICAL_ADDRESS *); 79 static ACPI_STATUS OslGetLastStatus(ACPI_STATUS); 80 81 static int pagesize; 82 83 /* Initialization flags */ 84 UINT8 Gbl_TableListInitialized = FALSE; 85 86 /* Local copies of main ACPI tables */ 87 ACPI_TABLE_RSDP Gbl_Rsdp; 88 ACPI_TABLE_FADT *Gbl_Fadt = NULL; 89 ACPI_TABLE_RSDT *Gbl_Rsdt = NULL; 90 ACPI_TABLE_XSDT *Gbl_Xsdt = NULL; 91 92 /* Table addresses */ 93 ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress = 0; 94 ACPI_PHYSICAL_ADDRESS Gbl_RsdpAddress = 0; 95 96 /* Revision of RSD PTR */ 97 UINT8 Gbl_Revision = 0; 98 99 OSL_TABLE_INFO *Gbl_TableListHead = NULL; 100 UINT32 Gbl_TableCount = 0; 101 102 /* 103 * 104 * FUNCTION: OslGetLastStatus 105 * 106 * PARAMETERS: DefaultStatus - Default error status to return 107 * 108 * RETURN: Status; Converted from errno. 109 * 110 * DESCRIPTION: Get last errno and conver it to ACPI_STATUS. 111 * 112 */ 113 static ACPI_STATUS 114 OslGetLastStatus(ACPI_STATUS DefaultStatus) 115 { 116 switch (errno) { 117 case EACCES: 118 case EPERM: 119 return (AE_ACCESS); 120 121 case ENOENT: 122 return (AE_NOT_FOUND); 123 124 case ENOMEM: 125 return (AE_NO_MEMORY); 126 127 default: 128 return (DefaultStatus); 129 } 130 } 131 132 /* 133 * 134 * FUNCTION: AcpiOsGetTableByAddress 135 * 136 * PARAMETERS: Address - Physical address of the ACPI table 137 * Table - Where a pointer to the table is returned 138 * 139 * RETURN: Status; Table buffer is returned if AE_OK. 140 * AE_NOT_FOUND: A valid table was not found at the address 141 * 142 * DESCRIPTION: Get an ACPI table via a physical memory address. 143 * 144 */ 145 ACPI_STATUS 146 AcpiOsGetTableByAddress(ACPI_PHYSICAL_ADDRESS Address, 147 ACPI_TABLE_HEADER **Table) 148 { 149 UINT32 TableLength; 150 ACPI_TABLE_HEADER *MappedTable; 151 ACPI_TABLE_HEADER *LocalTable = NULL; 152 ACPI_STATUS Status = AE_OK; 153 154 /* 155 * Get main ACPI tables from memory on first invocation of this 156 * function 157 */ 158 Status = OslTableInitialize(); 159 if (ACPI_FAILURE(Status)) { 160 return (Status); 161 } 162 163 /* Map the table and validate it */ 164 165 Status = OslMapTable(Address, NULL, &MappedTable); 166 if (ACPI_FAILURE(Status)) { 167 return (Status); 168 } 169 170 /* Copy table to local buffer and return it */ 171 172 TableLength = ApGetTableLength(MappedTable); 173 if (TableLength == 0) { 174 Status = AE_BAD_HEADER; 175 goto Exit; 176 } 177 178 LocalTable = calloc(1, TableLength); 179 if (!LocalTable) { 180 Status = AE_NO_MEMORY; 181 goto Exit; 182 } 183 184 memcpy(LocalTable, MappedTable, TableLength); 185 186 Exit: 187 OslUnmapTable(MappedTable); 188 *Table = LocalTable; 189 return (Status); 190 } 191 192 /* 193 * 194 * FUNCTION: AcpiOsGetTableByName 195 * 196 * PARAMETERS: Signature - ACPI Signature for desired table. Must be 197 * a null terminated 4-character string. 198 * Instance - Multiple table support for SSDT/UEFI (0...n) 199 * Must be 0 for other tables. 200 * Table - Where a pointer to the table is returned 201 * Address - Where the table physical address is returned 202 * 203 * RETURN: Status; Table buffer and physical address returned if AE_OK. 204 * AE_LIMIT: Instance is beyond valid limit 205 * AE_NOT_FOUND: A table with the signature was not found 206 * 207 * NOTE: Assumes the input signature is uppercase. 208 * 209 */ 210 ACPI_STATUS 211 AcpiOsGetTableByName(char *Signature, UINT32 Instance, 212 ACPI_TABLE_HEADER **Table, ACPI_PHYSICAL_ADDRESS *Address) 213 { 214 ACPI_STATUS Status; 215 216 /* 217 * Get main ACPI tables from memory on first invocation of this 218 * function 219 */ 220 Status = OslTableInitialize(); 221 if (ACPI_FAILURE(Status)) { 222 return (Status); 223 } 224 225 /* attempt to extract it from the RSDT/XSDT */ 226 Status = OslGetBiosTable(Signature, Instance, Table, Address); 227 228 return (Status); 229 } 230 231 /* 232 * 233 * FUNCTION: OslAddTableToList 234 * 235 * PARAMETERS: Signature - Table signature 236 * 237 * RETURN: Status; Successfully added if AE_OK. 238 * AE_NO_MEMORY: Memory allocation error 239 * 240 * DESCRIPTION: Insert a table structure into OSL table list. 241 * 242 */ 243 static ACPI_STATUS 244 OslAddTableToList(char *Signature) 245 { 246 OSL_TABLE_INFO *NewInfo; 247 OSL_TABLE_INFO *Next; 248 UINT32 NextInstance = 0; 249 UINT32 Instance = 0; 250 BOOLEAN Found = FALSE; 251 252 NewInfo = calloc(1, sizeof (OSL_TABLE_INFO)); 253 if (NewInfo == NULL) { 254 return (AE_NO_MEMORY); 255 } 256 257 ACPI_MOVE_NAME(NewInfo->Signature, Signature); 258 259 if (!Gbl_TableListHead) { 260 Gbl_TableListHead = NewInfo; 261 } else { 262 Next = Gbl_TableListHead; 263 264 while (1) { 265 if (ACPI_COMPARE_NAME(Next->Signature, Signature)) { 266 if (Next->Instance == 0) { 267 Found = TRUE; 268 } 269 if (Next->Instance >= NextInstance) { 270 NextInstance = Next->Instance + 1; 271 } 272 } 273 274 if (!Next->Next) { 275 break; 276 } 277 Next = Next->Next; 278 } 279 Next->Next = NewInfo; 280 } 281 282 if (Found) { 283 Instance = NextInstance; 284 } 285 286 NewInfo->Instance = Instance; 287 Gbl_TableCount++; 288 289 return (AE_OK); 290 } 291 292 /* 293 * 294 * FUNCTION: AcpiOsGetTableByIndex 295 * 296 * PARAMETERS: Index - Which table to get 297 * Table - Where a pointer to the table is returned 298 * Instance - Where a pointer to the table instance no. is 299 * returned 300 * Address - Where the table physical address is returned 301 * 302 * RETURN: Status; Table buffer and physical address returned if AE_OK. 303 * AE_LIMIT: Index is beyond valid limit 304 * 305 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns 306 * AE_LIMIT when an invalid index is reached. Index is not 307 * necessarily an index into the RSDT/XSDT. 308 * 309 */ 310 ACPI_STATUS 311 AcpiOsGetTableByIndex(UINT32 Index, ACPI_TABLE_HEADER **Table, 312 UINT32 *Instance, ACPI_PHYSICAL_ADDRESS *Address) 313 { 314 OSL_TABLE_INFO *Info; 315 ACPI_STATUS Status; 316 UINT32 i; 317 318 /* 319 * Get main ACPI tables from memory on first invocation of this 320 * function. 321 */ 322 323 Status = OslTableInitialize(); 324 if (ACPI_FAILURE(Status)) { 325 return (Status); 326 } 327 328 /* Validate Index */ 329 330 if (Index >= Gbl_TableCount) { 331 return (AE_LIMIT); 332 } 333 334 /* Point to the table list entry specified by the Index argument */ 335 336 Info = Gbl_TableListHead; 337 for (i = 0; i < Index; i++) { 338 Info = Info->Next; 339 } 340 341 /* Now we can just get the table via the signature */ 342 343 Status = AcpiOsGetTableByName(Info->Signature, Info->Instance, 344 Table, Address); 345 346 if (ACPI_SUCCESS(Status)) { 347 *Instance = Info->Instance; 348 } 349 return (Status); 350 } 351 352 /* 353 * 354 * FUNCTION: OslLoadRsdp 355 * 356 * PARAMETERS: None 357 * 358 * RETURN: Status 359 * 360 * DESCRIPTION: Scan and load RSDP. 361 * See the find_rsdp() function in usr/src/uts/i86pc/os/fakebop.c, which is how 362 * the kernel finds the RSDP. That algorithm matches AcpiFindRootPointer(). 363 * 364 * If the system is not using BIOS, and ACPI information was passed to the 365 * system from the boot loader, then the RSDP is recorded in the "acpi-root-tab" 366 * property. 367 * 368 * The code here is derived from AcpiFindRootPointer, except that we will 369 * try the "acpi-root-tab" property first. If the property does not exist or 370 * we do not find the root, then we scan the EBDA. Finally, we will search 371 * the BIOS and copy the table if found. 372 */ 373 static ACPI_STATUS 374 OslLoadRsdp(void) 375 { 376 UINT8 *mapp = NULL; 377 ACPI_TABLE_HEADER *tblp; 378 ACPI_SIZE mapsize = sizeof (ACPI_TABLE_RSDP); 379 ACPI_PHYSICAL_ADDRESS physaddr; 380 di_node_t root; 381 int64_t *val64; 382 383 if ((root = di_init("/", DINFOPROP)) != DI_NODE_NIL) { 384 if (di_prop_lookup_int64(DDI_DEV_T_ANY, root, 385 "acpi-root-tab", &val64) == 1) { 386 physaddr = (ACPI_PHYSICAL_ADDRESS)*val64; 387 mapp = AcpiOsMapMemory(physaddr, mapsize); 388 } 389 di_fini(root); 390 } 391 392 if (mapp != NULL) { 393 tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER, 394 AcpiTbScanMemoryForRsdp(mapp, mapsize)); 395 if (tblp != NULL) { 396 physaddr += (ACPI_PHYSICAL_ADDRESS) 397 ACPI_PTR_DIFF(tblp, mapp); 398 Gbl_RsdpAddress = physaddr; 399 memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP)); 400 AcpiOsUnmapMemory(mapp, mapsize); 401 return (AE_OK); 402 } 403 AcpiOsUnmapMemory(mapp, mapsize); 404 } 405 406 /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */ 407 mapp = AcpiOsMapMemory((ACPI_PHYSICAL_ADDRESS)ACPI_EBDA_PTR_LOCATION, 408 ACPI_EBDA_PTR_LENGTH); 409 if (mapp == NULL) 410 goto try_bios; 411 412 ACPI_MOVE_16_TO_32(&physaddr, mapp); 413 414 /* Convert segment part to physical address */ 415 physaddr <<= 4; 416 AcpiOsUnmapMemory(mapp, ACPI_EBDA_PTR_LENGTH); 417 418 /* EBDA present? */ 419 if (physaddr <= 0x400) 420 goto try_bios; 421 422 /* 423 * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of 1K 424 * length) 425 */ 426 mapp = AcpiOsMapMemory(physaddr, ACPI_EBDA_WINDOW_SIZE); 427 if (mapp == NULL) { 428 (void) fprintf(stderr, "EBDA (0x%p) found, but is not " 429 "mappable\n", physaddr); 430 goto try_bios; 431 } 432 433 tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER, 434 AcpiTbScanMemoryForRsdp(mapp, ACPI_EBDA_WINDOW_SIZE)); 435 if (tblp != NULL) { 436 physaddr += (ACPI_PHYSICAL_ADDRESS) ACPI_PTR_DIFF(tblp, mapp); 437 Gbl_RsdpAddress = physaddr; 438 memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP)); 439 AcpiOsUnmapMemory(mapp, ACPI_EBDA_WINDOW_SIZE); 440 441 return (AE_OK); 442 } 443 AcpiOsUnmapMemory(mapp, ACPI_EBDA_WINDOW_SIZE); 444 445 try_bios: 446 /* Try to get RSDP from BIOS memory */ 447 if (Gbl_RsdpBase != NULL) { 448 physaddr = Gbl_RsdpBase; 449 mapsize = sizeof (ACPI_TABLE_RSDP); 450 } else { 451 physaddr = ACPI_HI_RSDP_WINDOW_BASE; 452 mapsize = ACPI_HI_RSDP_WINDOW_SIZE; 453 } 454 455 mapp = AcpiOsMapMemory(physaddr, mapsize); 456 if (mapp == NULL) 457 return (OslGetLastStatus(AE_BAD_ADDRESS)); 458 459 /* Search low memory for the RSDP */ 460 tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER, 461 AcpiTbScanMemoryForRsdp(mapp, mapsize)); 462 if (tblp == NULL) { 463 AcpiOsUnmapMemory(mapp, mapsize); 464 return (AE_NOT_FOUND); 465 } 466 467 physaddr += (ACPI_PHYSICAL_ADDRESS) ACPI_PTR_DIFF(tblp, mapp); 468 Gbl_RsdpAddress = physaddr; 469 memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP)); 470 AcpiOsUnmapMemory(mapp, mapsize); 471 472 return (AE_OK); 473 } 474 475 /* 476 * 477 * FUNCTION: OslCanUseXsdt 478 * 479 * PARAMETERS: None 480 * 481 * RETURN: TRUE if XSDT is allowed to be used. 482 * 483 * DESCRIPTION: This function collects logic that can be used to determine if 484 * XSDT should be used instead of RSDT. 485 * 486 */ 487 static BOOLEAN 488 OslCanUseXsdt(void) 489 { 490 if (Gbl_Revision && !AcpiGbl_DoNotUseXsdt) { 491 return (TRUE); 492 } else { 493 return (FALSE); 494 } 495 } 496 497 /* 498 * 499 * FUNCTION: OslTableInitialize 500 * 501 * PARAMETERS: None 502 * 503 * RETURN: Status 504 * 505 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to 506 * local variables. Main ACPI tables include RSDT, FADT, RSDT, 507 * and/or XSDT. 508 * 509 */ 510 static ACPI_STATUS 511 OslTableInitialize(void) 512 { 513 ACPI_STATUS Status; 514 ACPI_PHYSICAL_ADDRESS Address; 515 516 if (Gbl_TableListInitialized) { 517 return (AE_OK); 518 } 519 520 /* Get RSDP from memory */ 521 522 Status = OslLoadRsdp(); 523 if (ACPI_FAILURE(Status)) { 524 return (Status); 525 } 526 527 /* Get XSDT from memory */ 528 529 if (Gbl_Rsdp.Revision && !Gbl_DoNotDumpXsdt) { 530 if (Gbl_Xsdt) { 531 free(Gbl_Xsdt); 532 Gbl_Xsdt = NULL; 533 } 534 535 Gbl_Revision = 2; 536 Status = OslGetBiosTable(ACPI_SIG_XSDT, 0, 537 ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address); 538 if (ACPI_FAILURE(Status)) { 539 return (Status); 540 } 541 } 542 543 /* Get RSDT from memory */ 544 545 if (Gbl_Rsdp.RsdtPhysicalAddress) { 546 if (Gbl_Rsdt) { 547 free(Gbl_Rsdt); 548 Gbl_Rsdt = NULL; 549 } 550 551 Status = OslGetBiosTable(ACPI_SIG_RSDT, 0, 552 ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address); 553 if (ACPI_FAILURE(Status)) { 554 return (Status); 555 } 556 } 557 558 /* Get FADT from memory */ 559 560 if (Gbl_Fadt) { 561 free(Gbl_Fadt); 562 Gbl_Fadt = NULL; 563 } 564 565 Status = OslGetBiosTable(ACPI_SIG_FADT, 0, 566 ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress); 567 if (ACPI_FAILURE(Status)) { 568 return (Status); 569 } 570 571 /* Add mandatory tables to global table list first */ 572 573 Status = OslAddTableToList(ACPI_RSDP_NAME); 574 if (ACPI_FAILURE(Status)) { 575 return (Status); 576 } 577 578 Status = OslAddTableToList(ACPI_SIG_RSDT); 579 if (ACPI_FAILURE(Status)) { 580 return (Status); 581 } 582 583 if (Gbl_Revision == 2) { 584 Status = OslAddTableToList(ACPI_SIG_XSDT); 585 if (ACPI_FAILURE(Status)) { 586 return (Status); 587 } 588 } 589 590 Status = OslAddTableToList(ACPI_SIG_DSDT); 591 if (ACPI_FAILURE(Status)) { 592 return (Status); 593 } 594 595 Status = OslAddTableToList(ACPI_SIG_FACS); 596 if (ACPI_FAILURE(Status)) { 597 return (Status); 598 } 599 600 /* Add all tables found in the memory */ 601 602 Status = OslListBiosTables(); 603 if (ACPI_FAILURE(Status)) { 604 return (Status); 605 } 606 607 Gbl_TableListInitialized = TRUE; 608 return (AE_OK); 609 } 610 611 612 /* 613 * 614 * FUNCTION: OslListBiosTables 615 * 616 * PARAMETERS: None 617 * 618 * RETURN: Status; Table list is initialized if AE_OK. 619 * 620 * DESCRIPTION: Add ACPI tables to the table list from memory. 621 */ 622 static ACPI_STATUS 623 OslListBiosTables(void) 624 { 625 ACPI_TABLE_HEADER *MappedTable = NULL; 626 UINT8 *TableData; 627 UINT32 NumberOfTables; 628 UINT8 ItemSize; 629 ACPI_PHYSICAL_ADDRESS TableAddress = 0; 630 ACPI_STATUS Status = AE_OK; 631 UINT32 i; 632 633 if (OslCanUseXsdt()) { 634 ItemSize = sizeof (UINT64); 635 TableData = ACPI_CAST8(Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); 636 NumberOfTables = (UINT32) 637 ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 638 / ItemSize); 639 640 } else { 641 /* Use RSDT if XSDT is not available */ 642 ItemSize = sizeof (UINT32); 643 TableData = ACPI_CAST8(Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); 644 NumberOfTables = (UINT32) 645 ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 646 / ItemSize); 647 } 648 649 /* Search RSDT/XSDT for the requested table */ 650 651 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) { 652 if (OslCanUseXsdt()) { 653 TableAddress = 654 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64(TableData)); 655 } else { 656 TableAddress = 657 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32(TableData)); 658 } 659 660 /* Skip NULL entries in RSDT/XSDT */ 661 if (TableAddress == NULL) { 662 continue; 663 } 664 665 Status = OslMapTable(TableAddress, NULL, &MappedTable); 666 if (ACPI_FAILURE(Status)) { 667 return (Status); 668 } 669 670 OslAddTableToList(MappedTable->Signature); 671 OslUnmapTable(MappedTable); 672 } 673 674 return (AE_OK); 675 } 676 677 /* 678 * 679 * FUNCTION: OslGetBiosTable 680 * 681 * PARAMETERS: Signature - ACPI Signature for common table. Must be 682 * a null terminated 4-character string. 683 * Instance - Multiple table support for SSDT/UEFI (0...n) 684 * Must be 0 for other tables. 685 * Table - Where a pointer to the table is returned 686 * Address - Where the table physical address is returned 687 * 688 * RETURN: Status; Table buffer and physical address returned if AE_OK. 689 * AE_LIMIT: Instance is beyond valid limit 690 * AE_NOT_FOUND: A table with the signature was not found 691 * 692 * DESCRIPTION: Get a BIOS provided ACPI table 693 * 694 * NOTE: Assumes the input signature is uppercase. 695 * 696 */ 697 static ACPI_STATUS 698 OslGetBiosTable(char *Signature, UINT32 Instance, ACPI_TABLE_HEADER **Table, 699 ACPI_PHYSICAL_ADDRESS *Address) 700 { 701 ACPI_TABLE_HEADER *LocalTable = NULL; 702 ACPI_TABLE_HEADER *MappedTable = NULL; 703 UINT8 *TableData; 704 UINT8 NumberOfTables; 705 UINT8 ItemSize; 706 UINT32 CurrentInstance = 0; 707 ACPI_PHYSICAL_ADDRESS TableAddress = 0; 708 UINT32 TableLength = 0; 709 ACPI_STATUS Status = AE_OK; 710 UINT32 i; 711 712 /* Handle special tables whose addresses are not in RSDT/XSDT */ 713 714 if (ACPI_COMPARE_NAME(Signature, ACPI_RSDP_NAME) || 715 ACPI_COMPARE_NAME(Signature, ACPI_SIG_RSDT) || 716 ACPI_COMPARE_NAME(Signature, ACPI_SIG_XSDT) || 717 ACPI_COMPARE_NAME(Signature, ACPI_SIG_DSDT) || 718 ACPI_COMPARE_NAME(Signature, ACPI_SIG_FACS)) { 719 if (Instance > 0) { 720 return (AE_LIMIT); 721 } 722 723 /* 724 * Get the appropriate address, either 32-bit or 64-bit. Be very 725 * careful about the FADT length and validate table addresses. 726 * Note: The 64-bit addresses have priority. 727 */ 728 if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_DSDT)) { 729 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) && 730 Gbl_Fadt->XDsdt) { 731 TableAddress = 732 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt; 733 734 } else if (Gbl_Fadt->Header.Length >= 735 MIN_FADT_FOR_DSDT && Gbl_Fadt->Dsdt) { 736 TableAddress = 737 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt; 738 } 739 740 } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_FACS)) { 741 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) && 742 Gbl_Fadt->XFacs) { 743 TableAddress = 744 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs; 745 746 } else if (Gbl_Fadt->Header.Length >= 747 MIN_FADT_FOR_FACS && Gbl_Fadt->Facs) { 748 TableAddress = 749 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs; 750 } 751 752 } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_XSDT)) { 753 if (!Gbl_Revision) { 754 return (AE_BAD_SIGNATURE); 755 } 756 TableAddress = (ACPI_PHYSICAL_ADDRESS) 757 Gbl_Rsdp.XsdtPhysicalAddress; 758 759 } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_RSDT)) { 760 TableAddress = (ACPI_PHYSICAL_ADDRESS) 761 Gbl_Rsdp.RsdtPhysicalAddress; 762 763 } else { 764 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress; 765 Signature = ACPI_SIG_RSDP; 766 } 767 768 /* Now we can get the requested special table */ 769 770 Status = OslMapTable(TableAddress, Signature, &MappedTable); 771 if (ACPI_FAILURE(Status)) { 772 return (Status); 773 } 774 775 TableLength = ApGetTableLength(MappedTable); 776 777 } else { 778 /* Case for a normal ACPI table */ 779 if (OslCanUseXsdt()) { 780 ItemSize = sizeof (UINT64); 781 TableData = ACPI_CAST8(Gbl_Xsdt) + 782 sizeof (ACPI_TABLE_HEADER); 783 NumberOfTables = (UINT8) ((Gbl_Xsdt->Header.Length - 784 sizeof (ACPI_TABLE_HEADER)) 785 / ItemSize); 786 787 } else { 788 /* Use RSDT if XSDT is not available */ 789 ItemSize = sizeof (UINT32); 790 TableData = ACPI_CAST8(Gbl_Rsdt) + 791 sizeof (ACPI_TABLE_HEADER); 792 NumberOfTables = (UINT8) ((Gbl_Rsdt->Header.Length - 793 sizeof (ACPI_TABLE_HEADER)) 794 / ItemSize); 795 } 796 797 /* Search RSDT/XSDT for the requested table */ 798 799 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) { 800 if (OslCanUseXsdt()) { 801 TableAddress = (ACPI_PHYSICAL_ADDRESS) 802 (*ACPI_CAST64(TableData)); 803 } else { 804 TableAddress = (ACPI_PHYSICAL_ADDRESS) 805 (*ACPI_CAST32(TableData)); 806 } 807 808 /* Skip NULL entries in RSDT/XSDT */ 809 810 if (TableAddress == NULL) { 811 continue; 812 } 813 814 Status = OslMapTable(TableAddress, NULL, &MappedTable); 815 if (ACPI_FAILURE(Status)) { 816 return (Status); 817 } 818 TableLength = MappedTable->Length; 819 820 /* Does this table match the requested signature? */ 821 822 if (!ACPI_COMPARE_NAME(MappedTable->Signature, 823 Signature)) { 824 OslUnmapTable(MappedTable); 825 MappedTable = NULL; 826 continue; 827 } 828 829 /* Match table instance (for SSDT/UEFI tables) */ 830 831 if (CurrentInstance != Instance) { 832 OslUnmapTable(MappedTable); 833 MappedTable = NULL; 834 CurrentInstance++; 835 continue; 836 } 837 838 break; 839 } 840 } 841 842 if (MappedTable == NULL) { 843 return (AE_LIMIT); 844 } 845 846 if (TableLength == 0) { 847 Status = AE_BAD_HEADER; 848 goto Exit; 849 } 850 851 /* Copy table to local buffer and return it */ 852 853 LocalTable = calloc(1, TableLength); 854 if (LocalTable == NULL) { 855 Status = AE_NO_MEMORY; 856 goto Exit; 857 } 858 859 memcpy(LocalTable, MappedTable, TableLength); 860 *Address = TableAddress; 861 *Table = LocalTable; 862 863 Exit: 864 OslUnmapTable(MappedTable); 865 return (Status); 866 } 867 868 /* 869 * 870 * FUNCTION: OslMapTable 871 * 872 * PARAMETERS: Address - Address of the table in memory 873 * Signature - Optional ACPI Signature for desired table. 874 * Null terminated 4-character string. 875 * Table - Where a pointer to the mapped table is 876 * returned 877 * 878 * RETURN: Status; Mapped table is returned if AE_OK. 879 * AE_NOT_FOUND: A valid table was not found at the address 880 * 881 * DESCRIPTION: Map entire ACPI table into caller's address space. 882 * 883 */ 884 static ACPI_STATUS 885 OslMapTable(ACPI_SIZE Address, char *Signature, ACPI_TABLE_HEADER **Table) 886 { 887 ACPI_TABLE_HEADER *MappedTable; 888 UINT32 Length; 889 890 if (Address == NULL) { 891 return (AE_BAD_ADDRESS); 892 } 893 894 /* 895 * Map the header so we can get the table length. 896 * Use sizeof (ACPI_TABLE_HEADER) as: 897 * 1. it is bigger than 24 to include RSDP->Length 898 * 2. it is smaller than sizeof (ACPI_TABLE_RSDP) 899 */ 900 MappedTable = AcpiOsMapMemory(Address, sizeof (ACPI_TABLE_HEADER)); 901 if (MappedTable == NULL) { 902 (void) fprintf(stderr, "Could not map table header at " 903 "0x%8.8X%8.8X\n", ACPI_FORMAT_UINT64(Address)); 904 return (OslGetLastStatus(AE_BAD_ADDRESS)); 905 } 906 907 /* If specified, signature must match */ 908 909 if (Signature != NULL) { 910 if (ACPI_VALIDATE_RSDP_SIG(Signature)) { 911 if (!ACPI_VALIDATE_RSDP_SIG(MappedTable->Signature)) { 912 AcpiOsUnmapMemory(MappedTable, 913 sizeof (ACPI_TABLE_HEADER)); 914 return (AE_BAD_SIGNATURE); 915 } 916 } else if (!ACPI_COMPARE_NAME(Signature, 917 MappedTable->Signature)) { 918 AcpiOsUnmapMemory(MappedTable, 919 sizeof (ACPI_TABLE_HEADER)); 920 return (AE_BAD_SIGNATURE); 921 } 922 } 923 924 /* Map the entire table */ 925 926 Length = ApGetTableLength(MappedTable); 927 AcpiOsUnmapMemory(MappedTable, sizeof (ACPI_TABLE_HEADER)); 928 if (Length == 0) { 929 return (AE_BAD_HEADER); 930 } 931 932 MappedTable = AcpiOsMapMemory(Address, Length); 933 if (MappedTable == NULL) { 934 (void) fprintf(stderr, "Could not map table at 0x%8.8X%8.8X " 935 "length %8.8X\n", ACPI_FORMAT_UINT64(Address), Length); 936 return (OslGetLastStatus(AE_INVALID_TABLE_LENGTH)); 937 } 938 939 (void) ApIsValidChecksum(MappedTable); 940 941 *Table = MappedTable; 942 return (AE_OK); 943 } 944 945 946 /* 947 * 948 * FUNCTION: OslUnmapTable 949 * 950 * PARAMETERS: Table - A pointer to the mapped table 951 * 952 * RETURN: None 953 * 954 * DESCRIPTION: Unmap entire ACPI table. 955 * 956 */ 957 static void 958 OslUnmapTable(ACPI_TABLE_HEADER *Table) 959 { 960 if (Table != NULL) { 961 AcpiOsUnmapMemory(Table, ApGetTableLength(Table)); 962 } 963 } 964 965 /* 966 * 967 * FUNCTION: OslTableNameFromFile 968 * 969 * PARAMETERS: Filename - File that contains the desired table 970 * Signature - Pointer to 4-character buffer to store 971 * extracted table signature. 972 * Instance - Pointer to integer to store extracted 973 * table instance number. 974 * 975 * RETURN: Status; Table name is extracted if AE_OK. 976 * 977 * DESCRIPTION: Extract table signature and instance number from a table file 978 * name. 979 * 980 */ 981 static ACPI_STATUS 982 OslTableNameFromFile(char *Filename, char *Signature, UINT32 *Instance) 983 { 984 /* Ignore meaningless files */ 985 986 if (strlen(Filename) < ACPI_NAME_SIZE) { 987 return (AE_BAD_SIGNATURE); 988 } 989 990 /* Extract instance number */ 991 992 if (isdigit((int)Filename[ACPI_NAME_SIZE])) { 993 sscanf(&Filename[ACPI_NAME_SIZE], "%u", Instance); 994 } else if (strlen(Filename) != ACPI_NAME_SIZE) { 995 return (AE_BAD_SIGNATURE); 996 } else { 997 *Instance = 0; 998 } 999 1000 /* Extract signature */ 1001 1002 ACPI_MOVE_NAME(Signature, Filename); 1003 return (AE_OK); 1004 } 1005 1006 void * 1007 AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length) 1008 { 1009 int fd; 1010 void *p; 1011 ulong_t offset; 1012 1013 if ((fd = open("/dev/xsvc", O_RDONLY)) < 0) 1014 return (NULL); 1015 1016 if (pagesize == 0) { 1017 pagesize = getpagesize(); 1018 } 1019 1020 offset = Where % pagesize; 1021 p = mmap(NULL, Length + offset, PROT_READ, MAP_SHARED | MAP_NORESERVE, 1022 fd, Where - offset); 1023 1024 (void) close(fd); 1025 1026 if (p == MAP_FAILED) 1027 return (NULL); 1028 p = (char *)p + offset; 1029 return (p); 1030 } 1031 1032 void 1033 AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Size) 1034 { 1035 ulong_t offset; 1036 void *p; 1037 1038 offset = (ulong_t)LogicalAddress % pagesize; 1039 p = (void *)((char *)LogicalAddress - offset); 1040 1041 (void) munmap(p, Size + offset); 1042 } 1043