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