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