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