1 /****************************************************************************** 2 * 3 * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include "acpidump.h" 45 46 47 #define _COMPONENT ACPI_OS_SERVICES 48 ACPI_MODULE_NAME ("oslinuxtbl") 49 50 51 #ifndef PATH_MAX 52 #define PATH_MAX 256 53 #endif 54 55 56 /* List of information about obtained ACPI tables */ 57 58 typedef struct table_info 59 { 60 struct table_info *Next; 61 UINT32 Instance; 62 char Signature[ACPI_NAME_SIZE]; 63 64 } OSL_TABLE_INFO; 65 66 /* Local prototypes */ 67 68 static ACPI_STATUS 69 OslTableInitialize ( 70 void); 71 72 static ACPI_STATUS 73 OslTableNameFromFile ( 74 char *Filename, 75 char *Signature, 76 UINT32 *Instance); 77 78 static ACPI_STATUS 79 OslAddTableToList ( 80 char *Signature, 81 UINT32 Instance); 82 83 static ACPI_STATUS 84 OslReadTableFromFile ( 85 char *Filename, 86 ACPI_SIZE FileOffset, 87 char *Signature, 88 ACPI_TABLE_HEADER **Table); 89 90 static ACPI_STATUS 91 OslMapTable ( 92 ACPI_SIZE Address, 93 char *Signature, 94 ACPI_TABLE_HEADER **Table); 95 96 static void 97 OslUnmapTable ( 98 ACPI_TABLE_HEADER *Table); 99 100 static ACPI_PHYSICAL_ADDRESS 101 OslFindRsdpViaEfi ( 102 void); 103 104 static ACPI_STATUS 105 OslLoadRsdp ( 106 void); 107 108 static ACPI_STATUS 109 OslListCustomizedTables ( 110 char *Directory); 111 112 static ACPI_STATUS 113 OslGetCustomizedTable ( 114 char *Pathname, 115 char *Signature, 116 UINT32 Instance, 117 ACPI_TABLE_HEADER **Table, 118 ACPI_PHYSICAL_ADDRESS *Address); 119 120 static ACPI_STATUS 121 OslListBiosTables ( 122 void); 123 124 static ACPI_STATUS 125 OslGetBiosTable ( 126 char *Signature, 127 UINT32 Instance, 128 ACPI_TABLE_HEADER **Table, 129 ACPI_PHYSICAL_ADDRESS *Address); 130 131 static ACPI_STATUS 132 OslGetLastStatus ( 133 ACPI_STATUS DefaultStatus); 134 135 136 /* File locations */ 137 138 #define DYNAMIC_TABLE_DIR "/sys/firmware/acpi/tables/dynamic" 139 #define STATIC_TABLE_DIR "/sys/firmware/acpi/tables" 140 #define EFI_SYSTAB "/sys/firmware/efi/systab" 141 142 /* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */ 143 144 UINT8 Gbl_DumpDynamicTables = TRUE; 145 146 /* Initialization flags */ 147 148 UINT8 Gbl_TableListInitialized = FALSE; 149 150 /* Local copies of main ACPI tables */ 151 152 ACPI_TABLE_RSDP Gbl_Rsdp; 153 ACPI_TABLE_FADT *Gbl_Fadt = NULL; 154 ACPI_TABLE_RSDT *Gbl_Rsdt = NULL; 155 ACPI_TABLE_XSDT *Gbl_Xsdt = NULL; 156 157 /* Table addresses */ 158 159 ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress = 0; 160 ACPI_PHYSICAL_ADDRESS Gbl_RsdpAddress = 0; 161 162 /* Revision of RSD PTR */ 163 164 UINT8 Gbl_Revision = 0; 165 166 OSL_TABLE_INFO *Gbl_TableListHead = NULL; 167 UINT32 Gbl_TableCount = 0; 168 169 170 /****************************************************************************** 171 * 172 * FUNCTION: OslGetLastStatus 173 * 174 * PARAMETERS: DefaultStatus - Default error status to return 175 * 176 * RETURN: Status; Converted from errno. 177 * 178 * DESCRIPTION: Get last errno and conver it to ACPI_STATUS. 179 * 180 *****************************************************************************/ 181 182 static ACPI_STATUS 183 OslGetLastStatus ( 184 ACPI_STATUS DefaultStatus) 185 { 186 187 switch (errno) 188 { 189 case EACCES: 190 case EPERM: 191 192 return (AE_ACCESS); 193 194 case ENOENT: 195 196 return (AE_NOT_FOUND); 197 198 case ENOMEM: 199 200 return (AE_NO_MEMORY); 201 202 default: 203 204 return (DefaultStatus); 205 } 206 } 207 208 209 /****************************************************************************** 210 * 211 * FUNCTION: AcpiOsGetTableByAddress 212 * 213 * PARAMETERS: Address - Physical address of the ACPI table 214 * Table - Where a pointer to the table is returned 215 * 216 * RETURN: Status; Table buffer is returned if AE_OK. 217 * AE_NOT_FOUND: A valid table was not found at the address 218 * 219 * DESCRIPTION: Get an ACPI table via a physical memory address. 220 * 221 *****************************************************************************/ 222 223 ACPI_STATUS 224 AcpiOsGetTableByAddress ( 225 ACPI_PHYSICAL_ADDRESS Address, 226 ACPI_TABLE_HEADER **Table) 227 { 228 UINT32 TableLength; 229 ACPI_TABLE_HEADER *MappedTable; 230 ACPI_TABLE_HEADER *LocalTable = NULL; 231 ACPI_STATUS Status = AE_OK; 232 233 234 /* Get main ACPI tables from memory on first invocation of this function */ 235 236 Status = OslTableInitialize (); 237 if (ACPI_FAILURE (Status)) 238 { 239 return (Status); 240 } 241 242 /* Map the table and validate it */ 243 244 Status = OslMapTable (Address, NULL, &MappedTable); 245 if (ACPI_FAILURE (Status)) 246 { 247 return (Status); 248 } 249 250 /* Copy table to local buffer and return it */ 251 252 TableLength = ApGetTableLength (MappedTable); 253 if (TableLength == 0) 254 { 255 Status = AE_BAD_HEADER; 256 goto ErrorExit; 257 } 258 259 LocalTable = calloc (1, TableLength); 260 if (!LocalTable) 261 { 262 Status = AE_NO_MEMORY; 263 goto ErrorExit; 264 } 265 266 ACPI_MEMCPY (LocalTable, MappedTable, TableLength); 267 268 ErrorExit: 269 OslUnmapTable (MappedTable); 270 *Table = LocalTable; 271 return (AE_OK); 272 } 273 274 275 /****************************************************************************** 276 * 277 * FUNCTION: AcpiOsGetTableByName 278 * 279 * PARAMETERS: Signature - ACPI Signature for desired table. Must be 280 * a null terminated 4-character string. 281 * Instance - Multiple table support for SSDT/UEFI (0...n) 282 * Must be 0 for other tables. 283 * Table - Where a pointer to the table is returned 284 * Address - Where the table physical address is returned 285 * 286 * RETURN: Status; Table buffer and physical address returned if AE_OK. 287 * AE_LIMIT: Instance is beyond valid limit 288 * AE_NOT_FOUND: A table with the signature was not found 289 * 290 * NOTE: Assumes the input signature is uppercase. 291 * 292 *****************************************************************************/ 293 294 ACPI_STATUS 295 AcpiOsGetTableByName ( 296 char *Signature, 297 UINT32 Instance, 298 ACPI_TABLE_HEADER **Table, 299 ACPI_PHYSICAL_ADDRESS *Address) 300 { 301 ACPI_STATUS Status; 302 303 304 /* Get main ACPI tables from memory on first invocation of this function */ 305 306 Status = OslTableInitialize (); 307 if (ACPI_FAILURE (Status)) 308 { 309 return (Status); 310 } 311 312 /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */ 313 314 if (!Gbl_DumpCustomizedTables) 315 { 316 /* Attempt to get the table from the memory */ 317 318 Status = OslGetBiosTable (Signature, Instance, Table, Address); 319 } 320 else 321 { 322 /* Attempt to get the table from the static directory */ 323 324 Status = OslGetCustomizedTable (STATIC_TABLE_DIR, Signature, 325 Instance, Table, Address); 326 } 327 328 if (ACPI_FAILURE (Status) && Status == AE_LIMIT) 329 { 330 if (Gbl_DumpDynamicTables) 331 { 332 /* Attempt to get a dynamic table */ 333 334 Status = OslGetCustomizedTable (DYNAMIC_TABLE_DIR, Signature, 335 Instance, Table, Address); 336 } 337 } 338 339 return (Status); 340 } 341 342 343 /****************************************************************************** 344 * 345 * FUNCTION: OslAddTableToList 346 * 347 * PARAMETERS: Signature - Table signature 348 * Instance - Table instance 349 * 350 * RETURN: Status; Successfully added if AE_OK. 351 * AE_NO_MEMORY: Memory allocation error 352 * 353 * DESCRIPTION: Insert a table structure into OSL table list. 354 * 355 *****************************************************************************/ 356 357 static ACPI_STATUS 358 OslAddTableToList ( 359 char *Signature, 360 UINT32 Instance) 361 { 362 OSL_TABLE_INFO *NewInfo; 363 OSL_TABLE_INFO *Next; 364 UINT32 NextInstance = 0; 365 BOOLEAN Found = FALSE; 366 367 368 NewInfo = calloc (1, sizeof (OSL_TABLE_INFO)); 369 if (!NewInfo) 370 { 371 return (AE_NO_MEMORY); 372 } 373 374 ACPI_MOVE_NAME (NewInfo->Signature, Signature); 375 376 if (!Gbl_TableListHead) 377 { 378 Gbl_TableListHead = NewInfo; 379 } 380 else 381 { 382 Next = Gbl_TableListHead; 383 while (1) 384 { 385 if (ACPI_COMPARE_NAME (Next->Signature, Signature)) 386 { 387 if (Next->Instance == Instance) 388 { 389 Found = TRUE; 390 } 391 if (Next->Instance >= NextInstance) 392 { 393 NextInstance = Next->Instance + 1; 394 } 395 } 396 397 if (!Next->Next) 398 { 399 break; 400 } 401 Next = Next->Next; 402 } 403 Next->Next = NewInfo; 404 } 405 406 if (Found) 407 { 408 if (Instance) 409 { 410 fprintf (stderr, 411 "%4.4s: Warning unmatched table instance %d, expected %d\n", 412 Signature, Instance, NextInstance); 413 } 414 Instance = NextInstance; 415 } 416 417 NewInfo->Instance = Instance; 418 Gbl_TableCount++; 419 420 return (AE_OK); 421 } 422 423 424 /****************************************************************************** 425 * 426 * FUNCTION: AcpiOsGetTableByIndex 427 * 428 * PARAMETERS: Index - Which table to get 429 * Table - Where a pointer to the table is returned 430 * Instance - Where a pointer to the table instance no. is 431 * returned 432 * Address - Where the table physical address is returned 433 * 434 * RETURN: Status; Table buffer and physical address returned if AE_OK. 435 * AE_LIMIT: Index is beyond valid limit 436 * 437 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns 438 * AE_LIMIT when an invalid index is reached. Index is not 439 * necessarily an index into the RSDT/XSDT. 440 * 441 *****************************************************************************/ 442 443 ACPI_STATUS 444 AcpiOsGetTableByIndex ( 445 UINT32 Index, 446 ACPI_TABLE_HEADER **Table, 447 UINT32 *Instance, 448 ACPI_PHYSICAL_ADDRESS *Address) 449 { 450 OSL_TABLE_INFO *Info; 451 ACPI_STATUS Status; 452 UINT32 i; 453 454 455 /* Get main ACPI tables from memory on first invocation of this function */ 456 457 Status = OslTableInitialize (); 458 if (ACPI_FAILURE (Status)) 459 { 460 return (Status); 461 } 462 463 /* Validate Index */ 464 465 if (Index >= Gbl_TableCount) 466 { 467 return (AE_LIMIT); 468 } 469 470 /* Point to the table list entry specified by the Index argument */ 471 472 Info = Gbl_TableListHead; 473 for (i = 0; i < Index; i++) 474 { 475 Info = Info->Next; 476 } 477 478 /* Now we can just get the table via the signature */ 479 480 Status = AcpiOsGetTableByName (Info->Signature, Info->Instance, 481 Table, Address); 482 483 if (ACPI_SUCCESS (Status)) 484 { 485 *Instance = Info->Instance; 486 } 487 return (Status); 488 } 489 490 491 /****************************************************************************** 492 * 493 * FUNCTION: OslFindRsdpViaEfi 494 * 495 * PARAMETERS: None 496 * 497 * RETURN: RSDP address if found 498 * 499 * DESCRIPTION: Find RSDP address via EFI. 500 * 501 *****************************************************************************/ 502 503 static ACPI_PHYSICAL_ADDRESS 504 OslFindRsdpViaEfi ( 505 void) 506 { 507 FILE *File; 508 char Buffer[80]; 509 unsigned long Address = 0; 510 511 512 File = fopen (EFI_SYSTAB, "r"); 513 if (File) 514 { 515 while (fgets (Buffer, 80, File)) 516 { 517 if (sscanf (Buffer, "ACPI20=0x%lx", &Address) == 1) 518 { 519 break; 520 } 521 } 522 fclose (File); 523 } 524 525 return ((ACPI_PHYSICAL_ADDRESS) (Address)); 526 } 527 528 529 /****************************************************************************** 530 * 531 * FUNCTION: OslLoadRsdp 532 * 533 * PARAMETERS: None 534 * 535 * RETURN: Status 536 * 537 * DESCRIPTION: Scan and load RSDP. 538 * 539 *****************************************************************************/ 540 541 static ACPI_STATUS 542 OslLoadRsdp ( 543 void) 544 { 545 ACPI_TABLE_HEADER *MappedTable; 546 UINT8 *RsdpAddress; 547 ACPI_PHYSICAL_ADDRESS RsdpBase; 548 ACPI_SIZE RsdpSize; 549 550 551 /* Get RSDP from memory */ 552 553 RsdpSize = sizeof (ACPI_TABLE_RSDP); 554 if (Gbl_RsdpBase) 555 { 556 RsdpBase = Gbl_RsdpBase; 557 } 558 else 559 { 560 RsdpBase = OslFindRsdpViaEfi (); 561 } 562 563 if (!RsdpBase) 564 { 565 RsdpBase = ACPI_HI_RSDP_WINDOW_BASE; 566 RsdpSize = ACPI_HI_RSDP_WINDOW_SIZE; 567 } 568 569 RsdpAddress = AcpiOsMapMemory (RsdpBase, RsdpSize); 570 if (!RsdpAddress) 571 { 572 return (OslGetLastStatus (AE_BAD_ADDRESS)); 573 } 574 575 /* Search low memory for the RSDP */ 576 577 MappedTable = ACPI_CAST_PTR (ACPI_TABLE_HEADER, 578 AcpiTbScanMemoryForRsdp (RsdpAddress, RsdpSize)); 579 if (!MappedTable) 580 { 581 AcpiOsUnmapMemory (RsdpAddress, RsdpSize); 582 return (AE_NOT_FOUND); 583 } 584 585 Gbl_RsdpAddress = RsdpBase + (ACPI_CAST8 (MappedTable) - RsdpAddress); 586 587 ACPI_MEMCPY (&Gbl_Rsdp, MappedTable, sizeof (ACPI_TABLE_RSDP)); 588 AcpiOsUnmapMemory (RsdpAddress, RsdpSize); 589 590 return (AE_OK); 591 } 592 593 594 /****************************************************************************** 595 * 596 * FUNCTION: OslTableInitialize 597 * 598 * PARAMETERS: None 599 * 600 * RETURN: Status 601 * 602 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to 603 * local variables. Main ACPI tables include RSDT, FADT, RSDT, 604 * and/or XSDT. 605 * 606 *****************************************************************************/ 607 608 static ACPI_STATUS 609 OslTableInitialize ( 610 void) 611 { 612 ACPI_STATUS Status; 613 ACPI_PHYSICAL_ADDRESS Address; 614 615 616 if (Gbl_TableListInitialized) 617 { 618 return (AE_OK); 619 } 620 621 /* Get RSDP from memory */ 622 623 Status = OslLoadRsdp (); 624 if (ACPI_FAILURE (Status)) 625 { 626 return (Status); 627 } 628 629 /* Get XSDT from memory */ 630 631 if (Gbl_Rsdp.Revision) 632 { 633 if (Gbl_Xsdt) 634 { 635 free (Gbl_Xsdt); 636 Gbl_Xsdt = NULL; 637 } 638 639 Gbl_Revision = 2; 640 Status = OslGetBiosTable (ACPI_SIG_XSDT, 0, 641 ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address); 642 if (ACPI_FAILURE (Status)) 643 { 644 return (Status); 645 } 646 } 647 648 /* Get RSDT from memory */ 649 650 if (Gbl_Rsdp.RsdtPhysicalAddress) 651 { 652 if (Gbl_Rsdt) 653 { 654 free (Gbl_Rsdt); 655 Gbl_Rsdt = NULL; 656 } 657 658 Status = OslGetBiosTable (ACPI_SIG_RSDT, 0, 659 ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address); 660 if (ACPI_FAILURE (Status)) 661 { 662 return (Status); 663 } 664 } 665 666 /* Get FADT from memory */ 667 668 if (Gbl_Fadt) 669 { 670 free (Gbl_Fadt); 671 Gbl_Fadt = NULL; 672 } 673 674 Status = OslGetBiosTable (ACPI_SIG_FADT, 0, 675 ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress); 676 if (ACPI_FAILURE (Status)) 677 { 678 return (Status); 679 } 680 681 if (!Gbl_DumpCustomizedTables) 682 { 683 /* Add mandatory tables to global table list first */ 684 685 Status = OslAddTableToList (ACPI_RSDP_NAME, 0); 686 if (ACPI_FAILURE (Status)) 687 { 688 return (Status); 689 } 690 691 Status = OslAddTableToList (ACPI_SIG_RSDT, 0); 692 if (ACPI_FAILURE (Status)) 693 { 694 return (Status); 695 } 696 697 if (Gbl_Revision == 2) 698 { 699 Status = OslAddTableToList (ACPI_SIG_XSDT, 0); 700 if (ACPI_FAILURE (Status)) 701 { 702 return (Status); 703 } 704 } 705 706 Status = OslAddTableToList (ACPI_SIG_DSDT, 0); 707 if (ACPI_FAILURE (Status)) 708 { 709 return (Status); 710 } 711 712 Status = OslAddTableToList (ACPI_SIG_FACS, 0); 713 if (ACPI_FAILURE (Status)) 714 { 715 return (Status); 716 } 717 718 /* Add all tables found in the memory */ 719 720 Status = OslListBiosTables (); 721 if (ACPI_FAILURE (Status)) 722 { 723 return (Status); 724 } 725 } 726 else 727 { 728 /* Add all tables found in the static directory */ 729 730 Status = OslListCustomizedTables (STATIC_TABLE_DIR); 731 if (ACPI_FAILURE (Status)) 732 { 733 return (Status); 734 } 735 } 736 737 if (Gbl_DumpDynamicTables) 738 { 739 /* Add all dynamically loaded tables in the dynamic directory */ 740 741 Status = OslListCustomizedTables (DYNAMIC_TABLE_DIR); 742 if (ACPI_FAILURE (Status)) 743 { 744 return (Status); 745 } 746 } 747 748 Gbl_TableListInitialized = TRUE; 749 return (AE_OK); 750 } 751 752 753 /****************************************************************************** 754 * 755 * FUNCTION: OslListBiosTables 756 * 757 * PARAMETERS: None 758 * 759 * RETURN: Status; Table list is initialized if AE_OK. 760 * 761 * DESCRIPTION: Add ACPI tables to the table list from memory. 762 * 763 * NOTE: This works on Linux as table customization does not modify the 764 * addresses stored in RSDP/RSDT/XSDT/FADT. 765 * 766 *****************************************************************************/ 767 768 static ACPI_STATUS 769 OslListBiosTables ( 770 void) 771 { 772 ACPI_TABLE_HEADER *MappedTable = NULL; 773 UINT8 *TableData; 774 UINT8 NumberOfTables; 775 UINT8 ItemSize; 776 ACPI_PHYSICAL_ADDRESS TableAddress = 0; 777 ACPI_STATUS Status = AE_OK; 778 UINT32 i; 779 780 781 if (Gbl_Revision) 782 { 783 ItemSize = sizeof (UINT64); 784 TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); 785 NumberOfTables = 786 (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 787 / ItemSize); 788 } 789 else /* Use RSDT if XSDT is not available */ 790 { 791 ItemSize = sizeof (UINT32); 792 TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); 793 NumberOfTables = 794 (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 795 / ItemSize); 796 } 797 798 /* Search RSDT/XSDT for the requested table */ 799 800 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) 801 { 802 if (Gbl_Revision) 803 { 804 TableAddress = 805 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); 806 } 807 else 808 { 809 TableAddress = 810 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); 811 } 812 813 Status = OslMapTable (TableAddress, NULL, &MappedTable); 814 if (ACPI_FAILURE (Status)) 815 { 816 return (Status); 817 } 818 819 OslAddTableToList (MappedTable->Signature, 0); 820 OslUnmapTable (MappedTable); 821 } 822 823 return (AE_OK); 824 } 825 826 827 /****************************************************************************** 828 * 829 * FUNCTION: OslGetBiosTable 830 * 831 * PARAMETERS: Signature - ACPI Signature for common table. Must be 832 * a null terminated 4-character string. 833 * Instance - Multiple table support for SSDT/UEFI (0...n) 834 * Must be 0 for other tables. 835 * Table - Where a pointer to the table is returned 836 * Address - Where the table physical address is returned 837 * 838 * RETURN: Status; Table buffer and physical address returned if AE_OK. 839 * AE_LIMIT: Instance is beyond valid limit 840 * AE_NOT_FOUND: A table with the signature was not found 841 * 842 * DESCRIPTION: Get a BIOS provided ACPI table 843 * 844 * NOTE: Assumes the input signature is uppercase. 845 * 846 *****************************************************************************/ 847 848 static ACPI_STATUS 849 OslGetBiosTable ( 850 char *Signature, 851 UINT32 Instance, 852 ACPI_TABLE_HEADER **Table, 853 ACPI_PHYSICAL_ADDRESS *Address) 854 { 855 ACPI_TABLE_HEADER *LocalTable = NULL; 856 ACPI_TABLE_HEADER *MappedTable = NULL; 857 UINT8 *TableData; 858 UINT8 NumberOfTables; 859 UINT8 ItemSize; 860 UINT32 CurrentInstance = 0; 861 ACPI_PHYSICAL_ADDRESS TableAddress = 0; 862 UINT32 TableLength = 0; 863 ACPI_STATUS Status = AE_OK; 864 UINT32 i; 865 866 867 /* Handle special tables whose addresses are not in RSDT/XSDT */ 868 869 if (ACPI_COMPARE_NAME (Signature, ACPI_RSDP_NAME) || 870 ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT) || 871 ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT) || 872 ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) || 873 ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) 874 { 875 /* 876 * Get the appropriate address, either 32-bit or 64-bit. Be very 877 * careful about the FADT length and validate table addresses. 878 * Note: The 64-bit addresses have priority. 879 */ 880 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT)) 881 { 882 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) && 883 Gbl_Fadt->XDsdt) 884 { 885 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt; 886 } 887 else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) && 888 Gbl_Fadt->Dsdt) 889 { 890 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt; 891 } 892 } 893 else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) 894 { 895 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) && 896 Gbl_Fadt->XFacs) 897 { 898 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs; 899 } 900 else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) && 901 Gbl_Fadt->Facs) 902 { 903 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs; 904 } 905 } 906 else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT)) 907 { 908 if (!Gbl_Revision) 909 { 910 return (AE_BAD_SIGNATURE); 911 } 912 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.XsdtPhysicalAddress; 913 } 914 else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT)) 915 { 916 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.RsdtPhysicalAddress; 917 } 918 else 919 { 920 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress; 921 Signature = ACPI_SIG_RSDP; 922 } 923 924 /* Now we can get the requested special table */ 925 926 Status = OslMapTable (TableAddress, Signature, &MappedTable); 927 if (ACPI_FAILURE (Status)) 928 { 929 return (Status); 930 } 931 932 TableLength = ApGetTableLength (MappedTable); 933 } 934 else /* Case for a normal ACPI table */ 935 { 936 if (Gbl_Revision) 937 { 938 ItemSize = sizeof (UINT64); 939 TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); 940 NumberOfTables = 941 (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 942 / ItemSize); 943 } 944 else /* Use RSDT if XSDT is not available */ 945 { 946 ItemSize = sizeof (UINT32); 947 TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); 948 NumberOfTables = 949 (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 950 / ItemSize); 951 } 952 953 /* Search RSDT/XSDT for the requested table */ 954 955 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) 956 { 957 if (Gbl_Revision) 958 { 959 TableAddress = 960 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); 961 } 962 else 963 { 964 TableAddress = 965 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); 966 } 967 968 Status = OslMapTable (TableAddress, NULL, &MappedTable); 969 if (ACPI_FAILURE (Status)) 970 { 971 return (Status); 972 } 973 TableLength = MappedTable->Length; 974 975 /* Does this table match the requested signature? */ 976 977 if (!ACPI_COMPARE_NAME (MappedTable->Signature, Signature)) 978 { 979 OslUnmapTable (MappedTable); 980 MappedTable = NULL; 981 continue; 982 } 983 984 /* Match table instance (for SSDT/UEFI tables) */ 985 986 if (CurrentInstance != Instance) 987 { 988 OslUnmapTable (MappedTable); 989 MappedTable = NULL; 990 CurrentInstance++; 991 continue; 992 } 993 994 break; 995 } 996 } 997 998 if (!MappedTable) 999 { 1000 return (AE_LIMIT); 1001 } 1002 1003 if (TableLength == 0) 1004 { 1005 Status = AE_BAD_HEADER; 1006 goto ErrorExit; 1007 } 1008 1009 /* Copy table to local buffer and return it */ 1010 1011 LocalTable = calloc (1, TableLength); 1012 if (!LocalTable) 1013 { 1014 Status = AE_NO_MEMORY; 1015 goto ErrorExit; 1016 } 1017 1018 ACPI_MEMCPY (LocalTable, MappedTable, TableLength); 1019 *Address = TableAddress; 1020 *Table = LocalTable; 1021 1022 ErrorExit: 1023 OslUnmapTable (MappedTable); 1024 return (AE_OK); 1025 } 1026 1027 1028 /****************************************************************************** 1029 * 1030 * FUNCTION: OslListCustomizedTables 1031 * 1032 * PARAMETERS: Directory - Directory that contains the tables 1033 * 1034 * RETURN: Status; Table list is initialized if AE_OK. 1035 * 1036 * DESCRIPTION: Add ACPI tables to the table list from a directory. 1037 * 1038 *****************************************************************************/ 1039 1040 static ACPI_STATUS 1041 OslListCustomizedTables ( 1042 char *Directory) 1043 { 1044 void *TableDir; 1045 UINT32 Instance; 1046 char TempName[ACPI_NAME_SIZE]; 1047 char *Filename; 1048 ACPI_STATUS Status = AE_OK; 1049 1050 1051 /* Open the requested directory */ 1052 1053 TableDir = AcpiOsOpenDirectory (Directory, "*", REQUEST_FILE_ONLY); 1054 if (!TableDir) 1055 { 1056 return (OslGetLastStatus (AE_NOT_FOUND)); 1057 } 1058 1059 /* Examine all entries in this directory */ 1060 1061 while ((Filename = AcpiOsGetNextFilename (TableDir))) 1062 { 1063 /* Extract table name and instance number */ 1064 1065 Status = OslTableNameFromFile (Filename, TempName, &Instance); 1066 1067 /* Ignore meaningless files */ 1068 1069 if (ACPI_FAILURE (Status)) 1070 { 1071 continue; 1072 } 1073 1074 /* Add new info node to global table list */ 1075 1076 Status = OslAddTableToList (TempName, Instance); 1077 if (ACPI_FAILURE (Status)) 1078 { 1079 break; 1080 } 1081 } 1082 1083 AcpiOsCloseDirectory (TableDir); 1084 return (Status); 1085 } 1086 1087 1088 /****************************************************************************** 1089 * 1090 * FUNCTION: OslMapTable 1091 * 1092 * PARAMETERS: Address - Address of the table in memory 1093 * Signature - Optional ACPI Signature for desired table. 1094 * Null terminated 4-character string. 1095 * Table - Where a pointer to the mapped table is 1096 * returned 1097 * 1098 * RETURN: Status; Mapped table is returned if AE_OK. 1099 * AE_NOT_FOUND: A valid table was not found at the address 1100 * 1101 * DESCRIPTION: Map entire ACPI table into caller's address space. 1102 * 1103 *****************************************************************************/ 1104 1105 static ACPI_STATUS 1106 OslMapTable ( 1107 ACPI_SIZE Address, 1108 char *Signature, 1109 ACPI_TABLE_HEADER **Table) 1110 { 1111 ACPI_TABLE_HEADER *MappedTable; 1112 UINT32 Length; 1113 1114 1115 if (!Address) 1116 { 1117 return (AE_BAD_ADDRESS); 1118 } 1119 1120 /* 1121 * Map the header so we can get the table length. 1122 * Use sizeof (ACPI_TABLE_HEADER) as: 1123 * 1. it is bigger than 24 to include RSDP->Length 1124 * 2. it is smaller than sizeof (ACPI_TABLE_RSDP) 1125 */ 1126 MappedTable = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER)); 1127 if (!MappedTable) 1128 { 1129 fprintf (stderr, "Could not map table header at 0x%8.8X%8.8X\n", 1130 ACPI_FORMAT_UINT64 (Address)); 1131 return (OslGetLastStatus (AE_BAD_ADDRESS)); 1132 } 1133 1134 /* If specified, signature must match */ 1135 1136 if (Signature && 1137 !ACPI_COMPARE_NAME (Signature, MappedTable->Signature)) 1138 { 1139 AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); 1140 return (AE_BAD_SIGNATURE); 1141 } 1142 1143 /* Map the entire table */ 1144 1145 Length = ApGetTableLength (MappedTable); 1146 AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); 1147 if (Length == 0) 1148 { 1149 return (AE_BAD_HEADER); 1150 } 1151 1152 MappedTable = AcpiOsMapMemory (Address, Length); 1153 if (!MappedTable) 1154 { 1155 fprintf (stderr, "Could not map table at 0x%8.8X%8.8X length %8.8X\n", 1156 ACPI_FORMAT_UINT64 (Address), Length); 1157 return (OslGetLastStatus (AE_INVALID_TABLE_LENGTH)); 1158 } 1159 1160 (void) ApIsValidChecksum (MappedTable); 1161 1162 *Table = MappedTable; 1163 return (AE_OK); 1164 } 1165 1166 1167 /****************************************************************************** 1168 * 1169 * FUNCTION: OslUnmapTable 1170 * 1171 * PARAMETERS: Table - A pointer to the mapped table 1172 * 1173 * RETURN: None 1174 * 1175 * DESCRIPTION: Unmap entire ACPI table. 1176 * 1177 *****************************************************************************/ 1178 1179 static void 1180 OslUnmapTable ( 1181 ACPI_TABLE_HEADER *Table) 1182 { 1183 if (Table) 1184 { 1185 AcpiOsUnmapMemory (Table, ApGetTableLength (Table)); 1186 } 1187 } 1188 1189 1190 /****************************************************************************** 1191 * 1192 * FUNCTION: OslTableNameFromFile 1193 * 1194 * PARAMETERS: Filename - File that contains the desired table 1195 * Signature - Pointer to 4-character buffer to store 1196 * extracted table signature. 1197 * Instance - Pointer to integer to store extracted 1198 * table instance number. 1199 * 1200 * RETURN: Status; Table name is extracted if AE_OK. 1201 * 1202 * DESCRIPTION: Extract table signature and instance number from a table file 1203 * name. 1204 * 1205 *****************************************************************************/ 1206 1207 static ACPI_STATUS 1208 OslTableNameFromFile ( 1209 char *Filename, 1210 char *Signature, 1211 UINT32 *Instance) 1212 { 1213 1214 /* Ignore meaningless files */ 1215 1216 if (strlen (Filename) < ACPI_NAME_SIZE) 1217 { 1218 return (AE_BAD_SIGNATURE); 1219 } 1220 1221 /* Extract instance number */ 1222 1223 if (isdigit ((int) Filename[ACPI_NAME_SIZE])) 1224 { 1225 sscanf (&Filename[ACPI_NAME_SIZE], "%d", Instance); 1226 } 1227 else if (strlen (Filename) != ACPI_NAME_SIZE) 1228 { 1229 return (AE_BAD_SIGNATURE); 1230 } 1231 else 1232 { 1233 *Instance = 0; 1234 } 1235 1236 /* Extract signature */ 1237 1238 ACPI_MOVE_NAME (Signature, Filename); 1239 return (AE_OK); 1240 } 1241 1242 1243 /****************************************************************************** 1244 * 1245 * FUNCTION: OslReadTableFromFile 1246 * 1247 * PARAMETERS: Filename - File that contains the desired table 1248 * FileOffset - Offset of the table in file 1249 * Signature - Optional ACPI Signature for desired table. 1250 * A null terminated 4-character string. 1251 * Table - Where a pointer to the table is returned 1252 * 1253 * RETURN: Status; Table buffer is returned if AE_OK. 1254 * 1255 * DESCRIPTION: Read a ACPI table from a file. 1256 * 1257 *****************************************************************************/ 1258 1259 static ACPI_STATUS 1260 OslReadTableFromFile ( 1261 char *Filename, 1262 ACPI_SIZE FileOffset, 1263 char *Signature, 1264 ACPI_TABLE_HEADER **Table) 1265 { 1266 FILE *TableFile; 1267 ACPI_TABLE_HEADER Header; 1268 ACPI_TABLE_HEADER *LocalTable = NULL; 1269 UINT32 TableLength; 1270 INT32 Count; 1271 UINT32 Total = 0; 1272 ACPI_STATUS Status = AE_OK; 1273 1274 1275 /* Open the file */ 1276 1277 TableFile = fopen (Filename, "rb"); 1278 if (TableFile == NULL) 1279 { 1280 fprintf (stderr, "Could not open table file: %s\n", Filename); 1281 return (OslGetLastStatus (AE_NOT_FOUND)); 1282 } 1283 1284 fseek (TableFile, FileOffset, SEEK_SET); 1285 1286 /* Read the Table header to get the table length */ 1287 1288 Count = fread (&Header, 1, sizeof (ACPI_TABLE_HEADER), TableFile); 1289 if (Count != sizeof (ACPI_TABLE_HEADER)) 1290 { 1291 fprintf (stderr, "Could not read table header: %s\n", Filename); 1292 Status = AE_BAD_HEADER; 1293 goto ErrorExit; 1294 } 1295 1296 /* If signature is specified, it must match the table */ 1297 1298 if (Signature && 1299 !ACPI_COMPARE_NAME (Signature, Header.Signature)) 1300 { 1301 fprintf (stderr, "Incorrect signature: Expecting %4.4s, found %4.4s\n", 1302 Signature, Header.Signature); 1303 Status = AE_BAD_SIGNATURE; 1304 goto ErrorExit; 1305 } 1306 1307 TableLength = ApGetTableLength (&Header); 1308 if (TableLength == 0) 1309 { 1310 Status = AE_BAD_HEADER; 1311 goto ErrorExit; 1312 } 1313 1314 /* Read the entire table into a local buffer */ 1315 1316 LocalTable = calloc (1, TableLength); 1317 if (!LocalTable) 1318 { 1319 fprintf (stderr, 1320 "%4.4s: Could not allocate buffer for table of length %X\n", 1321 Header.Signature, TableLength); 1322 Status = AE_NO_MEMORY; 1323 goto ErrorExit; 1324 } 1325 1326 fseek (TableFile, FileOffset, SEEK_SET); 1327 1328 while (!feof (TableFile) && Total < TableLength) 1329 { 1330 Count = fread (LocalTable, 1, TableLength-Total, TableFile); 1331 if (Count < 0) 1332 { 1333 fprintf (stderr, "%4.4s: Could not read table content\n", 1334 Header.Signature); 1335 Status = AE_INVALID_TABLE_LENGTH; 1336 goto ErrorExit; 1337 } 1338 1339 Total += Count; 1340 } 1341 1342 /* Validate checksum */ 1343 1344 (void) ApIsValidChecksum (LocalTable); 1345 1346 ErrorExit: 1347 fclose (TableFile); 1348 *Table = LocalTable; 1349 return (Status); 1350 } 1351 1352 1353 /****************************************************************************** 1354 * 1355 * FUNCTION: OslGetCustomizedTable 1356 * 1357 * PARAMETERS: Pathname - Directory to find Linux customized table 1358 * Signature - ACPI Signature for desired table. Must be 1359 * a null terminated 4-character string. 1360 * Instance - Multiple table support for SSDT/UEFI (0...n) 1361 * Must be 0 for other tables. 1362 * Table - Where a pointer to the table is returned 1363 * Address - Where the table physical address is returned 1364 * 1365 * RETURN: Status; Table buffer is returned if AE_OK. 1366 * AE_LIMIT: Instance is beyond valid limit 1367 * AE_NOT_FOUND: A table with the signature was not found 1368 * 1369 * DESCRIPTION: Get an OS customized table. 1370 * 1371 *****************************************************************************/ 1372 1373 static ACPI_STATUS 1374 OslGetCustomizedTable ( 1375 char *Pathname, 1376 char *Signature, 1377 UINT32 Instance, 1378 ACPI_TABLE_HEADER **Table, 1379 ACPI_PHYSICAL_ADDRESS *Address) 1380 { 1381 void *TableDir; 1382 UINT32 CurrentInstance = 0; 1383 char TempName[ACPI_NAME_SIZE]; 1384 char TableFilename[PATH_MAX]; 1385 char *Filename; 1386 ACPI_STATUS Status; 1387 1388 1389 /* Open the directory for customized tables */ 1390 1391 TableDir = AcpiOsOpenDirectory (Pathname, "*", REQUEST_FILE_ONLY); 1392 if (!TableDir) 1393 { 1394 return (OslGetLastStatus (AE_NOT_FOUND)); 1395 } 1396 1397 /* Attempt to find the table in the directory */ 1398 1399 while ((Filename = AcpiOsGetNextFilename (TableDir))) 1400 { 1401 /* Ignore meaningless files */ 1402 1403 if (!ACPI_COMPARE_NAME (Filename, Signature)) 1404 { 1405 continue; 1406 } 1407 1408 /* Extract table name and instance number */ 1409 1410 Status = OslTableNameFromFile (Filename, TempName, &CurrentInstance); 1411 1412 /* Ignore meaningless files */ 1413 1414 if (ACPI_FAILURE (Status) || CurrentInstance != Instance) 1415 { 1416 continue; 1417 } 1418 1419 /* Create the table pathname */ 1420 1421 if (Instance != 0) 1422 { 1423 sprintf (TableFilename, "%s/%4.4s%d", Pathname, TempName, Instance); 1424 } 1425 else 1426 { 1427 sprintf (TableFilename, "%s/%4.4s", Pathname, TempName); 1428 } 1429 break; 1430 } 1431 1432 AcpiOsCloseDirectory (TableDir); 1433 1434 if (!Filename) 1435 { 1436 return (AE_LIMIT); 1437 } 1438 1439 /* There is no physical address saved for customized tables, use zero */ 1440 1441 *Address = 0; 1442 Status = OslReadTableFromFile (TableFilename, 0, NULL, Table); 1443 1444 return (Status); 1445 }