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 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 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 Exit; 257 } 258 259 LocalTable = calloc (1, TableLength); 260 if (!LocalTable) 261 { 262 Status = AE_NO_MEMORY; 263 goto Exit; 264 } 265 266 ACPI_MEMCPY (LocalTable, MappedTable, TableLength); 267 268 Exit: 269 OslUnmapTable (MappedTable); 270 *Table = LocalTable; 271 return (Status); 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: OslCanUseXsdt 597 * 598 * PARAMETERS: None 599 * 600 * RETURN: TRUE if XSDT is allowed to be used. 601 * 602 * DESCRIPTION: This function collects logic that can be used to determine if 603 * XSDT should be used instead of RSDT. 604 * 605 *****************************************************************************/ 606 607 static BOOLEAN 608 OslCanUseXsdt ( 609 void) 610 { 611 if (Gbl_Revision && !AcpiGbl_DoNotUseXsdt) 612 { 613 return (TRUE); 614 } 615 else 616 { 617 return (FALSE); 618 } 619 } 620 621 622 /****************************************************************************** 623 * 624 * FUNCTION: OslTableInitialize 625 * 626 * PARAMETERS: None 627 * 628 * RETURN: Status 629 * 630 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to 631 * local variables. Main ACPI tables include RSDT, FADT, RSDT, 632 * and/or XSDT. 633 * 634 *****************************************************************************/ 635 636 static ACPI_STATUS 637 OslTableInitialize ( 638 void) 639 { 640 ACPI_STATUS Status; 641 ACPI_PHYSICAL_ADDRESS Address; 642 643 644 if (Gbl_TableListInitialized) 645 { 646 return (AE_OK); 647 } 648 649 /* Get RSDP from memory */ 650 651 Status = OslLoadRsdp (); 652 if (ACPI_FAILURE (Status)) 653 { 654 return (Status); 655 } 656 657 /* Get XSDT from memory */ 658 659 if (Gbl_Rsdp.Revision && !Gbl_DoNotDumpXsdt) 660 { 661 if (Gbl_Xsdt) 662 { 663 free (Gbl_Xsdt); 664 Gbl_Xsdt = NULL; 665 } 666 667 Gbl_Revision = 2; 668 Status = OslGetBiosTable (ACPI_SIG_XSDT, 0, 669 ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address); 670 if (ACPI_FAILURE (Status)) 671 { 672 return (Status); 673 } 674 } 675 676 /* Get RSDT from memory */ 677 678 if (Gbl_Rsdp.RsdtPhysicalAddress) 679 { 680 if (Gbl_Rsdt) 681 { 682 free (Gbl_Rsdt); 683 Gbl_Rsdt = NULL; 684 } 685 686 Status = OslGetBiosTable (ACPI_SIG_RSDT, 0, 687 ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address); 688 if (ACPI_FAILURE (Status)) 689 { 690 return (Status); 691 } 692 } 693 694 /* Get FADT from memory */ 695 696 if (Gbl_Fadt) 697 { 698 free (Gbl_Fadt); 699 Gbl_Fadt = NULL; 700 } 701 702 Status = OslGetBiosTable (ACPI_SIG_FADT, 0, 703 ACPI_CAST_PTR (ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress); 704 if (ACPI_FAILURE (Status)) 705 { 706 return (Status); 707 } 708 709 if (!Gbl_DumpCustomizedTables) 710 { 711 /* Add mandatory tables to global table list first */ 712 713 Status = OslAddTableToList (ACPI_RSDP_NAME, 0); 714 if (ACPI_FAILURE (Status)) 715 { 716 return (Status); 717 } 718 719 Status = OslAddTableToList (ACPI_SIG_RSDT, 0); 720 if (ACPI_FAILURE (Status)) 721 { 722 return (Status); 723 } 724 725 if (Gbl_Revision == 2) 726 { 727 Status = OslAddTableToList (ACPI_SIG_XSDT, 0); 728 if (ACPI_FAILURE (Status)) 729 { 730 return (Status); 731 } 732 } 733 734 Status = OslAddTableToList (ACPI_SIG_DSDT, 0); 735 if (ACPI_FAILURE (Status)) 736 { 737 return (Status); 738 } 739 740 Status = OslAddTableToList (ACPI_SIG_FACS, 0); 741 if (ACPI_FAILURE (Status)) 742 { 743 return (Status); 744 } 745 746 /* Add all tables found in the memory */ 747 748 Status = OslListBiosTables (); 749 if (ACPI_FAILURE (Status)) 750 { 751 return (Status); 752 } 753 } 754 else 755 { 756 /* Add all tables found in the static directory */ 757 758 Status = OslListCustomizedTables (STATIC_TABLE_DIR); 759 if (ACPI_FAILURE (Status)) 760 { 761 return (Status); 762 } 763 } 764 765 if (Gbl_DumpDynamicTables) 766 { 767 /* Add all dynamically loaded tables in the dynamic directory */ 768 769 Status = OslListCustomizedTables (DYNAMIC_TABLE_DIR); 770 if (ACPI_FAILURE (Status)) 771 { 772 return (Status); 773 } 774 } 775 776 Gbl_TableListInitialized = TRUE; 777 return (AE_OK); 778 } 779 780 781 /****************************************************************************** 782 * 783 * FUNCTION: OslListBiosTables 784 * 785 * PARAMETERS: None 786 * 787 * RETURN: Status; Table list is initialized if AE_OK. 788 * 789 * DESCRIPTION: Add ACPI tables to the table list from memory. 790 * 791 * NOTE: This works on Linux as table customization does not modify the 792 * addresses stored in RSDP/RSDT/XSDT/FADT. 793 * 794 *****************************************************************************/ 795 796 static ACPI_STATUS 797 OslListBiosTables ( 798 void) 799 { 800 ACPI_TABLE_HEADER *MappedTable = NULL; 801 UINT8 *TableData; 802 UINT8 NumberOfTables; 803 UINT8 ItemSize; 804 ACPI_PHYSICAL_ADDRESS TableAddress = 0; 805 ACPI_STATUS Status = AE_OK; 806 UINT32 i; 807 808 809 if (OslCanUseXsdt ()) 810 { 811 ItemSize = sizeof (UINT64); 812 TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); 813 NumberOfTables = 814 (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 815 / ItemSize); 816 } 817 else /* Use RSDT if XSDT is not available */ 818 { 819 ItemSize = sizeof (UINT32); 820 TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); 821 NumberOfTables = 822 (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 823 / ItemSize); 824 } 825 826 /* Search RSDT/XSDT for the requested table */ 827 828 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) 829 { 830 if (OslCanUseXsdt ()) 831 { 832 TableAddress = 833 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); 834 } 835 else 836 { 837 TableAddress = 838 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); 839 } 840 841 /* Skip NULL entries in RSDT/XSDT */ 842 843 if (!TableAddress) 844 { 845 continue; 846 } 847 848 Status = OslMapTable (TableAddress, NULL, &MappedTable); 849 if (ACPI_FAILURE (Status)) 850 { 851 return (Status); 852 } 853 854 OslAddTableToList (MappedTable->Signature, 0); 855 OslUnmapTable (MappedTable); 856 } 857 858 return (AE_OK); 859 } 860 861 862 /****************************************************************************** 863 * 864 * FUNCTION: OslGetBiosTable 865 * 866 * PARAMETERS: Signature - ACPI Signature for common table. Must be 867 * a null terminated 4-character string. 868 * Instance - Multiple table support for SSDT/UEFI (0...n) 869 * Must be 0 for other tables. 870 * Table - Where a pointer to the table is returned 871 * Address - Where the table physical address is returned 872 * 873 * RETURN: Status; Table buffer and physical address returned if AE_OK. 874 * AE_LIMIT: Instance is beyond valid limit 875 * AE_NOT_FOUND: A table with the signature was not found 876 * 877 * DESCRIPTION: Get a BIOS provided ACPI table 878 * 879 * NOTE: Assumes the input signature is uppercase. 880 * 881 *****************************************************************************/ 882 883 static ACPI_STATUS 884 OslGetBiosTable ( 885 char *Signature, 886 UINT32 Instance, 887 ACPI_TABLE_HEADER **Table, 888 ACPI_PHYSICAL_ADDRESS *Address) 889 { 890 ACPI_TABLE_HEADER *LocalTable = NULL; 891 ACPI_TABLE_HEADER *MappedTable = NULL; 892 UINT8 *TableData; 893 UINT8 NumberOfTables; 894 UINT8 ItemSize; 895 UINT32 CurrentInstance = 0; 896 ACPI_PHYSICAL_ADDRESS TableAddress = 0; 897 UINT32 TableLength = 0; 898 ACPI_STATUS Status = AE_OK; 899 UINT32 i; 900 901 902 /* Handle special tables whose addresses are not in RSDT/XSDT */ 903 904 if (ACPI_COMPARE_NAME (Signature, ACPI_RSDP_NAME) || 905 ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT) || 906 ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT) || 907 ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT) || 908 ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) 909 { 910 /* 911 * Get the appropriate address, either 32-bit or 64-bit. Be very 912 * careful about the FADT length and validate table addresses. 913 * Note: The 64-bit addresses have priority. 914 */ 915 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_DSDT)) 916 { 917 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) && 918 Gbl_Fadt->XDsdt) 919 { 920 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt; 921 } 922 else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_DSDT) && 923 Gbl_Fadt->Dsdt) 924 { 925 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt; 926 } 927 } 928 else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) 929 { 930 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) && 931 Gbl_Fadt->XFacs) 932 { 933 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs; 934 } 935 else if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_FACS) && 936 Gbl_Fadt->Facs) 937 { 938 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs; 939 } 940 } 941 else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_XSDT)) 942 { 943 if (!Gbl_Revision) 944 { 945 return (AE_BAD_SIGNATURE); 946 } 947 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.XsdtPhysicalAddress; 948 } 949 else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_RSDT)) 950 { 951 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_Rsdp.RsdtPhysicalAddress; 952 } 953 else 954 { 955 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress; 956 Signature = ACPI_SIG_RSDP; 957 } 958 959 /* Now we can get the requested special table */ 960 961 Status = OslMapTable (TableAddress, Signature, &MappedTable); 962 if (ACPI_FAILURE (Status)) 963 { 964 return (Status); 965 } 966 967 TableLength = ApGetTableLength (MappedTable); 968 } 969 else /* Case for a normal ACPI table */ 970 { 971 if (OslCanUseXsdt ()) 972 { 973 ItemSize = sizeof (UINT64); 974 TableData = ACPI_CAST8 (Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER); 975 NumberOfTables = 976 (UINT8) ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 977 / ItemSize); 978 } 979 else /* Use RSDT if XSDT is not available */ 980 { 981 ItemSize = sizeof (UINT32); 982 TableData = ACPI_CAST8 (Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER); 983 NumberOfTables = 984 (UINT8) ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER)) 985 / ItemSize); 986 } 987 988 /* Search RSDT/XSDT for the requested table */ 989 990 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) 991 { 992 if (OslCanUseXsdt ()) 993 { 994 TableAddress = 995 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64 (TableData)); 996 } 997 else 998 { 999 TableAddress = 1000 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32 (TableData)); 1001 } 1002 1003 /* Skip NULL entries in RSDT/XSDT */ 1004 1005 if (!TableAddress) 1006 { 1007 continue; 1008 } 1009 1010 Status = OslMapTable (TableAddress, NULL, &MappedTable); 1011 if (ACPI_FAILURE (Status)) 1012 { 1013 return (Status); 1014 } 1015 TableLength = MappedTable->Length; 1016 1017 /* Does this table match the requested signature? */ 1018 1019 if (!ACPI_COMPARE_NAME (MappedTable->Signature, Signature)) 1020 { 1021 OslUnmapTable (MappedTable); 1022 MappedTable = NULL; 1023 continue; 1024 } 1025 1026 /* Match table instance (for SSDT/UEFI tables) */ 1027 1028 if (CurrentInstance != Instance) 1029 { 1030 OslUnmapTable (MappedTable); 1031 MappedTable = NULL; 1032 CurrentInstance++; 1033 continue; 1034 } 1035 1036 break; 1037 } 1038 } 1039 1040 if (!MappedTable) 1041 { 1042 return (AE_LIMIT); 1043 } 1044 1045 if (TableLength == 0) 1046 { 1047 Status = AE_BAD_HEADER; 1048 goto Exit; 1049 } 1050 1051 /* Copy table to local buffer and return it */ 1052 1053 LocalTable = calloc (1, TableLength); 1054 if (!LocalTable) 1055 { 1056 Status = AE_NO_MEMORY; 1057 goto Exit; 1058 } 1059 1060 ACPI_MEMCPY (LocalTable, MappedTable, TableLength); 1061 *Address = TableAddress; 1062 *Table = LocalTable; 1063 1064 Exit: 1065 OslUnmapTable (MappedTable); 1066 return (Status); 1067 } 1068 1069 1070 /****************************************************************************** 1071 * 1072 * FUNCTION: OslListCustomizedTables 1073 * 1074 * PARAMETERS: Directory - Directory that contains the tables 1075 * 1076 * RETURN: Status; Table list is initialized if AE_OK. 1077 * 1078 * DESCRIPTION: Add ACPI tables to the table list from a directory. 1079 * 1080 *****************************************************************************/ 1081 1082 static ACPI_STATUS 1083 OslListCustomizedTables ( 1084 char *Directory) 1085 { 1086 void *TableDir; 1087 UINT32 Instance; 1088 char TempName[ACPI_NAME_SIZE]; 1089 char *Filename; 1090 ACPI_STATUS Status = AE_OK; 1091 1092 1093 /* Open the requested directory */ 1094 1095 TableDir = AcpiOsOpenDirectory (Directory, "*", REQUEST_FILE_ONLY); 1096 if (!TableDir) 1097 { 1098 return (OslGetLastStatus (AE_NOT_FOUND)); 1099 } 1100 1101 /* Examine all entries in this directory */ 1102 1103 while ((Filename = AcpiOsGetNextFilename (TableDir))) 1104 { 1105 /* Extract table name and instance number */ 1106 1107 Status = OslTableNameFromFile (Filename, TempName, &Instance); 1108 1109 /* Ignore meaningless files */ 1110 1111 if (ACPI_FAILURE (Status)) 1112 { 1113 continue; 1114 } 1115 1116 /* Add new info node to global table list */ 1117 1118 Status = OslAddTableToList (TempName, Instance); 1119 if (ACPI_FAILURE (Status)) 1120 { 1121 break; 1122 } 1123 } 1124 1125 AcpiOsCloseDirectory (TableDir); 1126 return (Status); 1127 } 1128 1129 1130 /****************************************************************************** 1131 * 1132 * FUNCTION: OslMapTable 1133 * 1134 * PARAMETERS: Address - Address of the table in memory 1135 * Signature - Optional ACPI Signature for desired table. 1136 * Null terminated 4-character string. 1137 * Table - Where a pointer to the mapped table is 1138 * returned 1139 * 1140 * RETURN: Status; Mapped table is returned if AE_OK. 1141 * AE_NOT_FOUND: A valid table was not found at the address 1142 * 1143 * DESCRIPTION: Map entire ACPI table into caller's address space. 1144 * 1145 *****************************************************************************/ 1146 1147 static ACPI_STATUS 1148 OslMapTable ( 1149 ACPI_SIZE Address, 1150 char *Signature, 1151 ACPI_TABLE_HEADER **Table) 1152 { 1153 ACPI_TABLE_HEADER *MappedTable; 1154 UINT32 Length; 1155 1156 1157 if (!Address) 1158 { 1159 return (AE_BAD_ADDRESS); 1160 } 1161 1162 /* 1163 * Map the header so we can get the table length. 1164 * Use sizeof (ACPI_TABLE_HEADER) as: 1165 * 1. it is bigger than 24 to include RSDP->Length 1166 * 2. it is smaller than sizeof (ACPI_TABLE_RSDP) 1167 */ 1168 MappedTable = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER)); 1169 if (!MappedTable) 1170 { 1171 fprintf (stderr, "Could not map table header at 0x%8.8X%8.8X\n", 1172 ACPI_FORMAT_UINT64 (Address)); 1173 return (OslGetLastStatus (AE_BAD_ADDRESS)); 1174 } 1175 1176 /* If specified, signature must match */ 1177 1178 if (Signature) 1179 { 1180 if (ACPI_VALIDATE_RSDP_SIG (Signature)) 1181 { 1182 if (!ACPI_VALIDATE_RSDP_SIG (MappedTable->Signature)) 1183 { 1184 AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); 1185 return (AE_BAD_SIGNATURE); 1186 } 1187 } 1188 else if (!ACPI_COMPARE_NAME (Signature, MappedTable->Signature)) 1189 { 1190 AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); 1191 return (AE_BAD_SIGNATURE); 1192 } 1193 } 1194 1195 /* Map the entire table */ 1196 1197 Length = ApGetTableLength (MappedTable); 1198 AcpiOsUnmapMemory (MappedTable, sizeof (ACPI_TABLE_HEADER)); 1199 if (Length == 0) 1200 { 1201 return (AE_BAD_HEADER); 1202 } 1203 1204 MappedTable = AcpiOsMapMemory (Address, Length); 1205 if (!MappedTable) 1206 { 1207 fprintf (stderr, "Could not map table at 0x%8.8X%8.8X length %8.8X\n", 1208 ACPI_FORMAT_UINT64 (Address), Length); 1209 return (OslGetLastStatus (AE_INVALID_TABLE_LENGTH)); 1210 } 1211 1212 (void) ApIsValidChecksum (MappedTable); 1213 1214 *Table = MappedTable; 1215 return (AE_OK); 1216 } 1217 1218 1219 /****************************************************************************** 1220 * 1221 * FUNCTION: OslUnmapTable 1222 * 1223 * PARAMETERS: Table - A pointer to the mapped table 1224 * 1225 * RETURN: None 1226 * 1227 * DESCRIPTION: Unmap entire ACPI table. 1228 * 1229 *****************************************************************************/ 1230 1231 static void 1232 OslUnmapTable ( 1233 ACPI_TABLE_HEADER *Table) 1234 { 1235 if (Table) 1236 { 1237 AcpiOsUnmapMemory (Table, ApGetTableLength (Table)); 1238 } 1239 } 1240 1241 1242 /****************************************************************************** 1243 * 1244 * FUNCTION: OslTableNameFromFile 1245 * 1246 * PARAMETERS: Filename - File that contains the desired table 1247 * Signature - Pointer to 4-character buffer to store 1248 * extracted table signature. 1249 * Instance - Pointer to integer to store extracted 1250 * table instance number. 1251 * 1252 * RETURN: Status; Table name is extracted if AE_OK. 1253 * 1254 * DESCRIPTION: Extract table signature and instance number from a table file 1255 * name. 1256 * 1257 *****************************************************************************/ 1258 1259 static ACPI_STATUS 1260 OslTableNameFromFile ( 1261 char *Filename, 1262 char *Signature, 1263 UINT32 *Instance) 1264 { 1265 1266 /* Ignore meaningless files */ 1267 1268 if (strlen (Filename) < ACPI_NAME_SIZE) 1269 { 1270 return (AE_BAD_SIGNATURE); 1271 } 1272 1273 /* Extract instance number */ 1274 1275 if (isdigit ((int) Filename[ACPI_NAME_SIZE])) 1276 { 1277 sscanf (&Filename[ACPI_NAME_SIZE], "%d", Instance); 1278 } 1279 else if (strlen (Filename) != ACPI_NAME_SIZE) 1280 { 1281 return (AE_BAD_SIGNATURE); 1282 } 1283 else 1284 { 1285 *Instance = 0; 1286 } 1287 1288 /* Extract signature */ 1289 1290 ACPI_MOVE_NAME (Signature, Filename); 1291 return (AE_OK); 1292 } 1293 1294 1295 /****************************************************************************** 1296 * 1297 * FUNCTION: OslReadTableFromFile 1298 * 1299 * PARAMETERS: Filename - File that contains the desired table 1300 * FileOffset - Offset of the table in file 1301 * Signature - Optional ACPI Signature for desired table. 1302 * A null terminated 4-character string. 1303 * Table - Where a pointer to the table is returned 1304 * 1305 * RETURN: Status; Table buffer is returned if AE_OK. 1306 * 1307 * DESCRIPTION: Read a ACPI table from a file. 1308 * 1309 *****************************************************************************/ 1310 1311 static ACPI_STATUS 1312 OslReadTableFromFile ( 1313 char *Filename, 1314 ACPI_SIZE FileOffset, 1315 char *Signature, 1316 ACPI_TABLE_HEADER **Table) 1317 { 1318 FILE *TableFile; 1319 ACPI_TABLE_HEADER Header; 1320 ACPI_TABLE_HEADER *LocalTable = NULL; 1321 UINT32 TableLength; 1322 INT32 Count; 1323 ACPI_STATUS Status = AE_OK; 1324 1325 1326 /* Open the file */ 1327 1328 TableFile = fopen (Filename, "rb"); 1329 if (TableFile == NULL) 1330 { 1331 fprintf (stderr, "Could not open table file: %s\n", Filename); 1332 return (OslGetLastStatus (AE_NOT_FOUND)); 1333 } 1334 1335 fseek (TableFile, FileOffset, SEEK_SET); 1336 1337 /* Read the Table header to get the table length */ 1338 1339 Count = fread (&Header, 1, sizeof (ACPI_TABLE_HEADER), TableFile); 1340 if (Count != sizeof (ACPI_TABLE_HEADER)) 1341 { 1342 fprintf (stderr, "Could not read table header: %s\n", Filename); 1343 Status = AE_BAD_HEADER; 1344 goto Exit; 1345 } 1346 1347 /* If signature is specified, it must match the table */ 1348 1349 if (Signature) 1350 { 1351 if (ACPI_VALIDATE_RSDP_SIG (Signature)) 1352 { 1353 if (!ACPI_VALIDATE_RSDP_SIG (Header.Signature)) { 1354 fprintf (stderr, "Incorrect RSDP signature: found %8.8s\n", 1355 Header.Signature); 1356 Status = AE_BAD_SIGNATURE; 1357 goto Exit; 1358 } 1359 } 1360 else if (!ACPI_COMPARE_NAME (Signature, Header.Signature)) 1361 { 1362 fprintf (stderr, "Incorrect signature: Expecting %4.4s, found %4.4s\n", 1363 Signature, Header.Signature); 1364 Status = AE_BAD_SIGNATURE; 1365 goto Exit; 1366 } 1367 } 1368 1369 TableLength = ApGetTableLength (&Header); 1370 if (TableLength == 0) 1371 { 1372 Status = AE_BAD_HEADER; 1373 goto Exit; 1374 } 1375 1376 /* Read the entire table into a local buffer */ 1377 1378 LocalTable = calloc (1, TableLength); 1379 if (!LocalTable) 1380 { 1381 fprintf (stderr, 1382 "%4.4s: Could not allocate buffer for table of length %X\n", 1383 Header.Signature, TableLength); 1384 Status = AE_NO_MEMORY; 1385 goto Exit; 1386 } 1387 1388 fseek (TableFile, FileOffset, SEEK_SET); 1389 1390 Count = fread (LocalTable, 1, TableLength, TableFile); 1391 if (Count != TableLength) 1392 { 1393 fprintf (stderr, "%4.4s: Could not read table content\n", 1394 Header.Signature); 1395 Status = AE_INVALID_TABLE_LENGTH; 1396 goto Exit; 1397 } 1398 1399 /* Validate checksum */ 1400 1401 (void) ApIsValidChecksum (LocalTable); 1402 1403 Exit: 1404 fclose (TableFile); 1405 *Table = LocalTable; 1406 return (Status); 1407 } 1408 1409 1410 /****************************************************************************** 1411 * 1412 * FUNCTION: OslGetCustomizedTable 1413 * 1414 * PARAMETERS: Pathname - Directory to find Linux customized table 1415 * Signature - ACPI Signature for desired table. Must be 1416 * a null terminated 4-character string. 1417 * Instance - Multiple table support for SSDT/UEFI (0...n) 1418 * Must be 0 for other tables. 1419 * Table - Where a pointer to the table is returned 1420 * Address - Where the table physical address is returned 1421 * 1422 * RETURN: Status; Table buffer is returned if AE_OK. 1423 * AE_LIMIT: Instance is beyond valid limit 1424 * AE_NOT_FOUND: A table with the signature was not found 1425 * 1426 * DESCRIPTION: Get an OS customized table. 1427 * 1428 *****************************************************************************/ 1429 1430 static ACPI_STATUS 1431 OslGetCustomizedTable ( 1432 char *Pathname, 1433 char *Signature, 1434 UINT32 Instance, 1435 ACPI_TABLE_HEADER **Table, 1436 ACPI_PHYSICAL_ADDRESS *Address) 1437 { 1438 void *TableDir; 1439 UINT32 CurrentInstance = 0; 1440 char TempName[ACPI_NAME_SIZE]; 1441 char TableFilename[PATH_MAX]; 1442 char *Filename; 1443 ACPI_STATUS Status; 1444 1445 1446 /* Open the directory for customized tables */ 1447 1448 TableDir = AcpiOsOpenDirectory (Pathname, "*", REQUEST_FILE_ONLY); 1449 if (!TableDir) 1450 { 1451 return (OslGetLastStatus (AE_NOT_FOUND)); 1452 } 1453 1454 /* Attempt to find the table in the directory */ 1455 1456 while ((Filename = AcpiOsGetNextFilename (TableDir))) 1457 { 1458 /* Ignore meaningless files */ 1459 1460 if (!ACPI_COMPARE_NAME (Filename, Signature)) 1461 { 1462 continue; 1463 } 1464 1465 /* Extract table name and instance number */ 1466 1467 Status = OslTableNameFromFile (Filename, TempName, &CurrentInstance); 1468 1469 /* Ignore meaningless files */ 1470 1471 if (ACPI_FAILURE (Status) || CurrentInstance != Instance) 1472 { 1473 continue; 1474 } 1475 1476 /* Create the table pathname */ 1477 1478 if (Instance != 0) 1479 { 1480 sprintf (TableFilename, "%s/%4.4s%d", Pathname, TempName, Instance); 1481 } 1482 else 1483 { 1484 sprintf (TableFilename, "%s/%4.4s", Pathname, TempName); 1485 } 1486 break; 1487 } 1488 1489 AcpiOsCloseDirectory (TableDir); 1490 1491 if (!Filename) 1492 { 1493 return (AE_LIMIT); 1494 } 1495 1496 /* There is no physical address saved for customized tables, use zero */ 1497 1498 *Address = 0; 1499 Status = OslReadTableFromFile (TableFilename, 0, NULL, Table); 1500 1501 return (Status); 1502 } 1503