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