Home | History | Annotate | Line # | Download | only in service_layers
oswintbl.c revision 1.1.1.12.6.1
      1 /******************************************************************************
      2  *
      3  * Module Name: oswintbl - Windows OSL for obtaining ACPI tables
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2021, 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 "acpi.h"
     45 #include "accommon.h"
     46 #include "acutils.h"
     47 #include <stdio.h>
     48 
     49 #ifdef WIN32
     50 #pragma warning(disable:4115)   /* warning C4115: (caused by rpcasync.h) */
     51 #include <windows.h>
     52 
     53 #elif WIN64
     54 #include <windowsx.h>
     55 #endif
     56 
     57 #define _COMPONENT          ACPI_OS_SERVICES
     58         ACPI_MODULE_NAME    ("oswintbl")
     59 
     60 /* Local prototypes */
     61 
     62 static char *
     63 WindowsFormatException (
     64     LONG                WinStatus);
     65 
     66 /* Globals */
     67 
     68 #define LOCAL_BUFFER_SIZE           64
     69 
     70 static char             KeyBuffer[LOCAL_BUFFER_SIZE];
     71 static char             ErrorBuffer[LOCAL_BUFFER_SIZE];
     72 
     73 /*
     74  * List of table signatures reported by EnumSystemFirmwareTables ()
     75  */
     76 UINT32                  *Gbl_AvailableTableSignatures;
     77 UINT32                  Gbl_TableCount = 0;
     78 UINT32                  Gbl_SsdtInstance = 0;
     79 
     80 BOOLEAN                 Gbl_TableListInitialized = FALSE;
     81 
     82 static ACPI_STATUS
     83 OslTableInitialize (
     84     void);
     85 
     86 
     87 /******************************************************************************
     88  *
     89  * FUNCTION:    WindowsFormatException
     90  *
     91  * PARAMETERS:  WinStatus       - Status from a Windows system call
     92  *
     93  * RETURN:      Formatted (ascii) exception code. Front-end to Windows
     94  *              FormatMessage interface.
     95  *
     96  * DESCRIPTION: Decode a windows exception
     97  *
     98  *****************************************************************************/
     99 
    100 static char *
    101 WindowsFormatException (
    102     LONG                WinStatus)
    103 {
    104 
    105     ErrorBuffer[0] = 0;
    106     FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, WinStatus, 0,
    107         ErrorBuffer, LOCAL_BUFFER_SIZE, NULL);
    108 
    109     return (ErrorBuffer);
    110 }
    111 
    112 
    113 /******************************************************************************
    114  *
    115  * FUNCTION:    AcpiOsGetTableByAddress
    116  *
    117  * PARAMETERS:  Address         - Physical address of the ACPI table
    118  *              Table           - Where a pointer to the table is returned
    119  *
    120  * RETURN:      Status; Table buffer is returned if AE_OK.
    121  *              AE_NOT_FOUND: A valid table was not found at the address
    122  *
    123  * DESCRIPTION: Get an ACPI table via a physical memory address.
    124  *
    125  * NOTE:        Cannot be implemented without a Windows device driver.
    126  *
    127  *****************************************************************************/
    128 
    129 ACPI_STATUS
    130 AcpiOsGetTableByAddress (
    131     ACPI_PHYSICAL_ADDRESS   Address,
    132     ACPI_TABLE_HEADER       **Table)
    133 {
    134 
    135     fprintf (stderr, "Get table by address is not supported on Windows\n");
    136     return (AE_SUPPORT);
    137 }
    138 
    139 
    140 /******************************************************************************
    141  *
    142  * FUNCTION:    AcpiOsGetTableByIndex
    143  *
    144  * PARAMETERS:  Index           - Which table to get
    145  *              Table           - Where a pointer to the table is returned
    146  *              Instance        - Where a pointer to the table instance no. is
    147  *                                returned
    148  *              Address         - Where the table physical address is returned
    149  *
    150  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
    151  *              AE_LIMIT: Index is beyond valid limit
    152  *
    153  * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
    154  *              AE_LIMIT when an invalid index is reached. Index is not
    155  *              necessarily an index into the RSDT/XSDT.
    156  *              SSDT tables are obtained from the Windows registry. All other
    157  *              tables are obtained through GetSystemFirmwareTable ().
    158  *
    159  * NOTE:        Cannot get the physical address from the windows registry;
    160  *              zero is returned instead.
    161  *
    162  *****************************************************************************/
    163 
    164 ACPI_STATUS
    165 AcpiOsGetTableByIndex (
    166     UINT32                  Index,
    167     ACPI_TABLE_HEADER       **Table,
    168     UINT32                  *Instance,
    169     ACPI_PHYSICAL_ADDRESS   *Address)
    170 {
    171     ACPI_STATUS             Status;
    172     char                    *Signature;
    173     UINT32                  CurrentInstance;
    174 
    175 
    176     /* Enumerate all ACPI table signatures on first invocation of this function */
    177 
    178     Status = OslTableInitialize ();
    179     if (ACPI_FAILURE (Status))
    180     {
    181         return (Status);
    182     }
    183 
    184     /* Validate Index */
    185 
    186     if (Index < Gbl_TableCount)
    187     {
    188         Signature = malloc (ACPI_NAMESEG_SIZE + 1);
    189         if (!Signature)
    190         {
    191             return (AE_NO_MEMORY);
    192         }
    193 
    194         Signature = memmove (Signature, &Gbl_AvailableTableSignatures[Index], ACPI_NAMESEG_SIZE);
    195     }
    196     else
    197     {
    198         return (AE_LIMIT);
    199     }
    200 
    201     if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
    202     {
    203         CurrentInstance = Gbl_SsdtInstance;
    204         Gbl_SsdtInstance++;
    205     }
    206     else
    207     {
    208         CurrentInstance = 0;
    209     }
    210 
    211     Status = AcpiOsGetTableByName (Signature, CurrentInstance, Table, Address);
    212     if (ACPI_SUCCESS (Status))
    213     {
    214         *Instance = CurrentInstance;
    215     }
    216     else if (Status == AE_NOT_FOUND &&
    217         ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
    218     {
    219         /* Treat SSDTs that are not found as invalid index. */
    220         Status = AE_LIMIT;
    221     }
    222 
    223     free (Signature);
    224     return (Status);
    225 }
    226 
    227 /******************************************************************************
    228  *
    229  * FUNCTION:    OslTableInitialize
    230  *
    231  * PARAMETERS:  None
    232  *
    233  * RETURN:      Status
    234  *
    235  * DESCRIPTION: Initialize ACPI table data. Enumerate all ACPI table signatures
    236  *              and save them to a global list.
    237  *
    238  *****************************************************************************/
    239 static ACPI_STATUS
    240 OslTableInitialize (
    241     void)
    242 {
    243     UINT32                  ResultSize;
    244     UINT32                  DataSize;
    245 
    246     if (Gbl_TableListInitialized)
    247     {
    248         return (AE_OK);
    249     }
    250 
    251     /*
    252      * ACPI table signatures are always 4 characters. Therefore, the data size
    253      * buffer should be a multiple of 4
    254      */
    255     DataSize = EnumSystemFirmwareTables ('ACPI', NULL, 0);
    256     if (DataSize % ACPI_NAMESEG_SIZE)
    257     {
    258         return (AE_ERROR);
    259     }
    260 
    261     /*
    262      * EnumSystemFirmwareTables () does not report the DSDT or XSDT. Work around this
    263      * by adding these entries manually.
    264      */
    265     Gbl_TableCount = 2 + DataSize / ACPI_NAMESEG_SIZE;
    266     Gbl_AvailableTableSignatures = malloc (Gbl_TableCount * ACPI_NAMESEG_SIZE);
    267     if (!Gbl_AvailableTableSignatures)
    268     {
    269         return (AE_NO_MEMORY);
    270     }
    271 
    272     ResultSize = EnumSystemFirmwareTables ('ACPI', Gbl_AvailableTableSignatures, DataSize);
    273     if (ResultSize > DataSize)
    274     {
    275         return (AE_ERROR);
    276     }
    277 
    278     /* Insert the DSDT and XSDT tables signatures */
    279 
    280     Gbl_AvailableTableSignatures [Gbl_TableCount - 1] = 'TDSD';
    281     Gbl_AvailableTableSignatures [Gbl_TableCount - 2] = 'TDSX';
    282 
    283     Gbl_TableListInitialized = TRUE;
    284     return (AE_OK);
    285 }
    286 
    287 
    288 /******************************************************************************
    289  *
    290  * FUNCTION:    WindowsGetTableFromRegistry
    291  *
    292  * PARAMETERS:  Signature       - ACPI Signature for desired table. Must be
    293  *                                a null terminated 4-character string.
    294  *              Instance        - For SSDTs (0...n). Use 0 otherwise.
    295  *              Table           - Where a pointer to the table is returned
    296  *              Address         - Where the table physical address is returned
    297  *
    298  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
    299  *              AE_LIMIT: Instance is beyond valid limit
    300  *              AE_NOT_FOUND: A table with the signature was not found
    301  *
    302  * DESCRIPTION: Get an ACPI table via a table signature (4 ASCII characters).
    303  *              Returns AE_LIMIT when an invalid instance is reached.
    304  *              Table is obtained from the Windows registry.
    305  *
    306  * NOTE:        Assumes the input signature is uppercase.
    307  *              Cannot get the physical address from the windows registry;
    308  *              zero is returned instead.
    309  *
    310  *****************************************************************************/
    311 
    312 static ACPI_STATUS
    313 WindowsGetTableFromRegistry (
    314     char                    *Signature,
    315     UINT32                  Instance,
    316     ACPI_TABLE_HEADER       **Table,
    317     ACPI_PHYSICAL_ADDRESS   *Address)
    318 {
    319     HKEY                    Handle = NULL;
    320     LONG                    WinStatus;
    321     ULONG                   Type;
    322     ULONG                   NameSize;
    323     ULONG                   DataSize;
    324     HKEY                    SubKey;
    325     ULONG                   i;
    326     ACPI_TABLE_HEADER       *ReturnTable;
    327     ACPI_STATUS             Status = AE_OK;
    328 
    329 
    330     /* Get a handle to the table key */
    331 
    332     while (1)
    333     {
    334         strcpy(KeyBuffer, "HARDWARE\\ACPI\\");
    335         if (AcpiUtSafeStrcat(KeyBuffer, sizeof(KeyBuffer), Signature))
    336         {
    337             return (AE_BUFFER_OVERFLOW);
    338         }
    339 
    340         /*
    341          * Windows stores SSDT at SSDT, SSD1, ..., SSD9, SSDA, ..., SSDS, SSDT,
    342          * SSDU, ..., SSDY. If the first (0th) and the 29th tables have the same
    343          * OEM ID, Table ID and Revision, then the 29th entry will overwrite the
    344          * first entry... Let's hope that we do not have that many entries.
    345          */
    346         if (Instance > 0 && ACPI_COMPARE_NAMESEG(Signature, ACPI_SIG_SSDT))
    347         {
    348             if (Instance < 10)
    349             {
    350                 KeyBuffer[strlen(KeyBuffer) - 1] = '0' + (char)Instance;
    351             }
    352             else if (Instance < 29)
    353             {
    354                 KeyBuffer[strlen(KeyBuffer) - 1] = 'A' + (char)(Instance - 10);
    355             }
    356             else
    357             {
    358                 return (AE_LIMIT);
    359             }
    360         }
    361 
    362         WinStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyBuffer,
    363             0L, KEY_READ, &Handle);
    364 
    365         if (WinStatus != ERROR_SUCCESS)
    366         {
    367             /*
    368              * Somewhere along the way, MS changed the registry entry for
    369              * the FADT from
    370              * HARDWARE/ACPI/FACP  to
    371              * HARDWARE/ACPI/FADT.
    372              *
    373              * This code allows for both.
    374              */
    375             if (ACPI_COMPARE_NAMESEG(Signature, "FACP"))
    376             {
    377                 Signature = "FADT";
    378             }
    379             else if (ACPI_COMPARE_NAMESEG(Signature, "XSDT"))
    380             {
    381                 Signature = "RSDT";
    382             }
    383             else if (ACPI_COMPARE_NAMESEG(Signature, ACPI_SIG_SSDT))
    384             {
    385                 /*
    386                  * SSDT may not be present on older Windows versions, but it is
    387                  * also possible that the index is not found.
    388                  */
    389                 return (AE_NOT_FOUND);
    390             }
    391             else
    392             {
    393                 fprintf(stderr,
    394                     "Could not find %s in registry at %s: %s (WinStatus=0x%X)\n",
    395                     Signature, KeyBuffer, WindowsFormatException(WinStatus), WinStatus);
    396                 return (AE_NOT_FOUND);
    397             }
    398         }
    399         else
    400         {
    401             break;
    402         }
    403     }
    404 
    405     /* Actual data for the table is down a couple levels */
    406 
    407     for (i = 0; ;)
    408     {
    409         WinStatus = RegEnumKey(Handle, i, KeyBuffer, sizeof(KeyBuffer));
    410         i++;
    411         if (WinStatus == ERROR_NO_MORE_ITEMS)
    412         {
    413             break;
    414         }
    415 
    416         WinStatus = RegOpenKey(Handle, KeyBuffer, &SubKey);
    417         if (WinStatus != ERROR_SUCCESS)
    418         {
    419             fprintf(stderr, "Could not open %s entry: %s\n",
    420                 Signature, WindowsFormatException(WinStatus));
    421             Status = AE_ERROR;
    422             goto Cleanup;
    423         }
    424 
    425         RegCloseKey(Handle);
    426         Handle = SubKey;
    427         i = 0;
    428     }
    429 
    430     /* Find the (binary) table entry */
    431 
    432     for (i = 0; ; i++)
    433     {
    434         NameSize = sizeof(KeyBuffer);
    435         WinStatus = RegEnumValue(Handle, i, KeyBuffer, &NameSize, NULL,
    436             &Type, NULL, 0);
    437         if (WinStatus != ERROR_SUCCESS)
    438         {
    439             fprintf(stderr, "Could not get %s registry entry: %s\n",
    440                 Signature, WindowsFormatException(WinStatus));
    441             Status = AE_ERROR;
    442             goto Cleanup;
    443         }
    444 
    445         if (Type == REG_BINARY)
    446         {
    447             break;
    448         }
    449     }
    450 
    451     /* Get the size of the table */
    452 
    453     WinStatus = RegQueryValueEx(Handle, KeyBuffer, NULL, NULL,
    454         NULL, &DataSize);
    455     if (WinStatus != ERROR_SUCCESS)
    456     {
    457         fprintf(stderr, "Could not read the %s table size: %s\n",
    458             Signature, WindowsFormatException(WinStatus));
    459         Status = AE_ERROR;
    460         goto Cleanup;
    461     }
    462 
    463     /* Allocate a new buffer for the table */
    464 
    465     ReturnTable = malloc(DataSize);
    466     if (!ReturnTable)
    467     {
    468         Status = AE_NO_MEMORY;
    469         goto Cleanup;
    470     }
    471 
    472     /* Get the actual table from the registry */
    473 
    474     WinStatus = RegQueryValueEx(Handle, KeyBuffer, NULL, NULL,
    475         (UCHAR *)ReturnTable, &DataSize);
    476 
    477     if (WinStatus != ERROR_SUCCESS)
    478     {
    479         fprintf(stderr, "Could not read %s data: %s\n",
    480             Signature, WindowsFormatException(WinStatus));
    481         free(ReturnTable);
    482         Status = AE_ERROR;
    483         goto Cleanup;
    484     }
    485 
    486     *Table = ReturnTable;
    487     *Address = 0;
    488 
    489 Cleanup:
    490     RegCloseKey(Handle);
    491     return (Status);
    492 }
    493 
    494 
    495 /******************************************************************************
    496  *
    497  * FUNCTION:    AcpiOsGetTableByName
    498  *
    499  * PARAMETERS:  Signature       - ACPI Signature for desired table. Must be
    500  *                                a null terminated 4-character string.
    501  *              Instance        - For SSDTs (0...n). Use 0 otherwise.
    502  *              Table           - Where a pointer to the table is returned
    503  *              Address         - Where the table physical address is returned
    504  *
    505  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
    506  *              AE_LIMIT: Instance is beyond valid limit
    507  *              AE_NOT_FOUND: A table with the signature was not found
    508  *
    509  * DESCRIPTION: Get an ACPI table via a table signature (4 ASCII characters).
    510  *              Returns AE_LIMIT when an invalid instance is reached.
    511  *              Table is obtained from the Windows registry.
    512  *
    513  * NOTE:        Assumes the input signature is uppercase.
    514  *              Cannot get the physical address from the windows registry;
    515  *              zero is returned instead.
    516  *
    517  *****************************************************************************/
    518 
    519 ACPI_STATUS
    520 AcpiOsGetTableByName(
    521     char                    *Signature,
    522     UINT32                  Instance,
    523     ACPI_TABLE_HEADER       **Table,
    524     ACPI_PHYSICAL_ADDRESS   *Address)
    525 {
    526     LONG                    Result;
    527     ACPI_STATUS             Status = AE_OK;
    528     UINT32                  DataSize;
    529     ACPI_TABLE_HEADER       *ReturnTable;
    530     UINT32                  UIntSignature = 0;
    531 
    532 
    533     /* Multiple instances are only supported for SSDT tables. */
    534 
    535     if (Instance > 0 && !ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
    536     {
    537         return (AE_LIMIT);
    538     }
    539 
    540     if (ACPI_COMPARE_NAMESEG (Signature, ACPI_SIG_SSDT))
    541     {
    542         Status = WindowsGetTableFromRegistry ("SSDT", Instance, Table, Address);
    543         return (Status);
    544     }
    545 
    546     /* GetSystemFirmwareTable requires the table signature to be UINT32 */
    547 
    548     UIntSignature = *ACPI_CAST_PTR (UINT32, Signature);
    549     DataSize = GetSystemFirmwareTable('ACPI', UIntSignature, NULL, 0);
    550     if (!DataSize)
    551     {
    552         fprintf(stderr, "The table signature %s does not exist.", Signature);
    553         return (AE_ERROR);
    554     }
    555 
    556     ReturnTable = malloc(DataSize);
    557     if (!ReturnTable)
    558     {
    559         return (AE_NO_MEMORY);
    560     }
    561 
    562     Result = GetSystemFirmwareTable('ACPI', UIntSignature, ReturnTable, DataSize);
    563     if (Result > (LONG) DataSize)
    564     {
    565         /* Clean up */
    566 
    567         fprintf (stderr, "Could not read %s data\n", Signature);
    568         free (ReturnTable);
    569         return (AE_ERROR);
    570     }
    571 
    572     *Table = ReturnTable;
    573     return (Status);
    574 }
    575 
    576 
    577 /* These are here for acpidump only, so we don't need to link oswinxf */
    578 
    579 #ifdef ACPI_DUMP_APP
    580 /******************************************************************************
    581  *
    582  * FUNCTION:    AcpiOsMapMemory
    583  *
    584  * PARAMETERS:  Where               - Physical address of memory to be mapped
    585  *              Length              - How much memory to map
    586  *
    587  * RETURN:      Pointer to mapped memory. Null on error.
    588  *
    589  * DESCRIPTION: Map physical memory into caller's address space
    590  *
    591  *****************************************************************************/
    592 
    593 void *
    594 AcpiOsMapMemory (
    595     ACPI_PHYSICAL_ADDRESS   Where,
    596     ACPI_SIZE               Length)
    597 {
    598 
    599     return (ACPI_TO_POINTER ((ACPI_SIZE) Where));
    600 }
    601 
    602 
    603 /******************************************************************************
    604  *
    605  * FUNCTION:    AcpiOsUnmapMemory
    606  *
    607  * PARAMETERS:  Where               - Logical address of memory to be unmapped
    608  *              Length              - How much memory to unmap
    609  *
    610  * RETURN:      None.
    611  *
    612  * DESCRIPTION: Delete a previously created mapping. Where and Length must
    613  *              correspond to a previous mapping exactly.
    614  *
    615  *****************************************************************************/
    616 
    617 void
    618 AcpiOsUnmapMemory (
    619     void                    *Where,
    620     ACPI_SIZE               Length)
    621 {
    622 
    623     return;
    624 }
    625 #endif
    626