Home | History | Annotate | Download | only in AcpiTableDxe
      1 /** @file
      2   ACPI Sdt Protocol Driver
      3 
      4   Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved. <BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 //
     16 // Includes
     17 //
     18 #include "AcpiTable.h"
     19 
     20 GLOBAL_REMOVE_IF_UNREFERENCED
     21 EFI_ACPI_SDT_PROTOCOL  mAcpiSdtProtocolTemplate = {
     22   EFI_ACPI_TABLE_VERSION_NONE,
     23   GetAcpiTable2,
     24   RegisterNotify,
     25   Open,
     26   OpenSdt,
     27   Close,
     28   GetChild,
     29   GetOption,
     30   SetOption,
     31   FindPath
     32 };
     33 
     34 /**
     35   This function returns ACPI Table instance.
     36 
     37   @return AcpiTableInstance
     38 **/
     39 EFI_ACPI_TABLE_INSTANCE *
     40 SdtGetAcpiTableInstance (
     41   VOID
     42   )
     43 {
     44   return mPrivateData;
     45 }
     46 
     47 /**
     48   This function finds the table specified by the buffer.
     49 
     50   @param[in]  Buffer      Table buffer to find.
     51 
     52   @return ACPI table list.
     53 **/
     54 EFI_ACPI_TABLE_LIST *
     55 FindTableByBuffer (
     56   IN VOID  *Buffer
     57   )
     58 {
     59   EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;
     60   LIST_ENTRY                *CurrentLink;
     61   EFI_ACPI_TABLE_LIST       *CurrentTableList;
     62   LIST_ENTRY                *StartLink;
     63 
     64   //
     65   // Get the instance of the ACPI Table
     66   //
     67   AcpiTableInstance = SdtGetAcpiTableInstance ();
     68 
     69   //
     70   // Find the notify
     71   //
     72   StartLink   = &AcpiTableInstance->TableList;
     73   CurrentLink = StartLink->ForwardLink;
     74 
     75   while (CurrentLink != StartLink) {
     76     CurrentTableList = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);
     77     if (((UINTN)CurrentTableList->PageAddress <= (UINTN)Buffer) &&
     78         ((UINTN)CurrentTableList->PageAddress + EFI_PAGES_TO_SIZE(CurrentTableList->NumberOfPages) > (UINTN)Buffer)) {
     79       //
     80       // Good! Found Table.
     81       //
     82       return CurrentTableList;
     83     }
     84 
     85     CurrentLink = CurrentLink->ForwardLink;
     86   }
     87 
     88   return NULL;
     89 }
     90 
     91 /**
     92   This function updates AML table checksum.
     93   It will search the ACPI table installed by ACPI_TABLE protocol.
     94 
     95   @param[in]  Buffer        A piece of AML code buffer pointer.
     96 
     97   @retval EFI_SUCCESS       The table holds the AML buffer is found, and checksum is updated.
     98   @retval EFI_NOT_FOUND     The table holds the AML buffer is not found.
     99 **/
    100 EFI_STATUS
    101 SdtUpdateAmlChecksum (
    102   IN VOID  *Buffer
    103   )
    104 {
    105   EFI_ACPI_TABLE_LIST       *CurrentTableList;
    106 
    107   CurrentTableList = FindTableByBuffer (Buffer);
    108   if (CurrentTableList == NULL) {
    109     return EFI_NOT_FOUND;
    110   }
    111 
    112   AcpiPlatformChecksum (
    113     (VOID *)CurrentTableList->Table,
    114     CurrentTableList->Table->Length,
    115     OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER, Checksum)
    116     );
    117   return EFI_SUCCESS;
    118 }
    119 
    120 /**
    121   This function finds MAX AML buffer size.
    122   It will search the ACPI table installed by ACPI_TABLE protocol.
    123 
    124   @param[in]  Buffer        A piece of AML code buffer pointer.
    125   @param[out] MaxSize       On return it holds the MAX size of buffer.
    126 
    127   @retval EFI_SUCCESS       The table holds the AML buffer is found, and MAX size if returned.
    128   @retval EFI_NOT_FOUND     The table holds the AML buffer is not found.
    129 **/
    130 EFI_STATUS
    131 SdtGetMaxAmlBufferSize (
    132   IN  VOID  *Buffer,
    133   OUT UINTN *MaxSize
    134   )
    135 {
    136   EFI_ACPI_TABLE_LIST       *CurrentTableList;
    137 
    138   CurrentTableList = FindTableByBuffer (Buffer);
    139   if (CurrentTableList == NULL) {
    140     return EFI_NOT_FOUND;
    141   }
    142 
    143   *MaxSize = (UINTN)CurrentTableList->Table + CurrentTableList->Table->Length - (UINTN)Buffer;
    144   return EFI_SUCCESS;
    145 }
    146 
    147 /**
    148   This function invokes ACPI notification.
    149 
    150   @param[in]  AcpiTableInstance          Instance to AcpiTable
    151   @param[in]  Version                    Version(s) to set.
    152   @param[in]  Handle                     Handle of the table.
    153 **/
    154 VOID
    155 SdtNotifyAcpiList (
    156   IN EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance,
    157   IN EFI_ACPI_TABLE_VERSION    Version,
    158   IN UINTN                     Handle
    159   )
    160 {
    161   EFI_ACPI_NOTIFY_LIST      *CurrentNotifyList;
    162   LIST_ENTRY                *CurrentLink;
    163   LIST_ENTRY                *StartLink;
    164   EFI_ACPI_TABLE_LIST       *Table;
    165   EFI_STATUS                Status;
    166 
    167   //
    168   // We should not use Table buffer, because it is user input buffer.
    169   //
    170   Status = FindTableByHandle (
    171              Handle,
    172              &AcpiTableInstance->TableList,
    173              &Table
    174              );
    175   ASSERT_EFI_ERROR (Status);
    176 
    177   //
    178   // Find the notify
    179   //
    180   StartLink   = &AcpiTableInstance->NotifyList;
    181   CurrentLink = StartLink->ForwardLink;
    182 
    183   while (CurrentLink != StartLink) {
    184     CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);
    185 
    186     //
    187     // Inovke notification
    188     //
    189     CurrentNotifyList->Notification ((EFI_ACPI_SDT_HEADER *)Table->Table, Version, Handle);
    190 
    191     CurrentLink = CurrentLink->ForwardLink;
    192   }
    193 
    194   return ;
    195 }
    196 
    197 /**
    198   Returns a requested ACPI table.
    199 
    200   The GetAcpiTable() function returns a pointer to a buffer containing the ACPI table associated
    201   with the Index that was input. The following structures are not considered elements in the list of
    202   ACPI tables:
    203   - Root System Description Pointer (RSD_PTR)
    204   - Root System Description Table (RSDT)
    205   - Extended System Description Table (XSDT)
    206   Version is updated with a bit map containing all the versions of ACPI of which the table is a
    207   member. For tables installed via the EFI_ACPI_TABLE_PROTOCOL.InstallAcpiTable() interface,
    208   the function returns the value of EFI_ACPI_STD_PROTOCOL.AcpiVersion.
    209 
    210   @param[in]    Index       The zero-based index of the table to retrieve.
    211   @param[out]   Table       Pointer for returning the table buffer.
    212   @param[out]   Version     On return, updated with the ACPI versions to which this table belongs. Type
    213                             EFI_ACPI_TABLE_VERSION is defined in "Related Definitions" in the
    214                             EFI_ACPI_SDT_PROTOCOL.
    215   @param[out]   TableKey    On return, points to the table key for the specified ACPI system definition table.
    216                             This is identical to the table key used in the EFI_ACPI_TABLE_PROTOCOL.
    217                             The TableKey can be passed to EFI_ACPI_TABLE_PROTOCOL.UninstallAcpiTable()
    218                             to uninstall the table.
    219   @retval EFI_SUCCESS       The function completed successfully.
    220   @retval EFI_NOT_FOUND     The requested index is too large and a table was not found.
    221 **/
    222 EFI_STATUS
    223 EFIAPI
    224 GetAcpiTable2 (
    225   IN  UINTN                               Index,
    226   OUT EFI_ACPI_SDT_HEADER                 **Table,
    227   OUT EFI_ACPI_TABLE_VERSION              *Version,
    228   OUT UINTN                               *TableKey
    229   )
    230 {
    231   EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;
    232   UINTN                     TableIndex;
    233   LIST_ENTRY                *CurrentLink;
    234   LIST_ENTRY                *StartLink;
    235   EFI_ACPI_TABLE_LIST       *CurrentTable;
    236 
    237   ASSERT (Table != NULL);
    238   ASSERT (Version != NULL);
    239   ASSERT (TableKey != NULL);
    240 
    241   //
    242   // Get the instance of the ACPI Table
    243   //
    244   AcpiTableInstance = SdtGetAcpiTableInstance ();
    245 
    246   //
    247   // Find the table
    248   //
    249   StartLink   = &AcpiTableInstance->TableList;
    250   CurrentLink = StartLink->ForwardLink;
    251   TableIndex = 0;
    252 
    253   while (CurrentLink != StartLink) {
    254     if (TableIndex == Index) {
    255       break;
    256     }
    257     //
    258     // Next one
    259     //
    260     CurrentLink = CurrentLink->ForwardLink;
    261     TableIndex ++;
    262   }
    263 
    264   if ((TableIndex != Index) || (CurrentLink == StartLink)) {
    265     return EFI_NOT_FOUND;
    266   }
    267 
    268   //
    269   // Get handle and version
    270   //
    271   CurrentTable  = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);
    272   *TableKey     = CurrentTable->Handle;
    273   *Version      = CurrentTable->Version;
    274   *Table        = (EFI_ACPI_SDT_HEADER *)CurrentTable->Table;
    275 
    276   return EFI_SUCCESS;
    277 }
    278 
    279 /**
    280   Register a callback when an ACPI table is installed.
    281 
    282   This function registers a function which will be called whenever a new ACPI table is installed.
    283 
    284   @param[in]  Notification               Points to the callback function to be registered
    285 **/
    286 VOID
    287 SdtRegisterNotify (
    288   IN EFI_ACPI_NOTIFICATION_FN   Notification
    289   )
    290 {
    291   EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;
    292   EFI_ACPI_NOTIFY_LIST      *CurrentNotifyList;
    293 
    294   //
    295   // Get the instance of the ACPI Table
    296   //
    297   AcpiTableInstance = SdtGetAcpiTableInstance ();
    298 
    299   //
    300   // Create a new list entry
    301   //
    302   CurrentNotifyList = AllocatePool (sizeof (EFI_ACPI_NOTIFY_LIST));
    303   ASSERT (CurrentNotifyList != NULL);
    304 
    305   //
    306   // Initialize the table contents
    307   //
    308   CurrentNotifyList->Signature    = EFI_ACPI_NOTIFY_LIST_SIGNATURE;
    309   CurrentNotifyList->Notification = Notification;
    310 
    311   //
    312   // Add the table to the current list of tables
    313   //
    314   InsertTailList (&AcpiTableInstance->NotifyList, &CurrentNotifyList->Link);
    315 
    316   return ;
    317 }
    318 
    319 /**
    320   Unregister a callback when an ACPI table is installed.
    321 
    322   This function unregisters a function which will be called whenever a new ACPI table is installed.
    323 
    324   @param[in]  Notification               Points to the callback function to be unregistered.
    325 
    326   @retval EFI_SUCCESS           Callback successfully unregistered.
    327   @retval EFI_INVALID_PARAMETER Notification does not match a known registration function.
    328 **/
    329 EFI_STATUS
    330 SdtUnregisterNotify (
    331   IN EFI_ACPI_NOTIFICATION_FN   Notification
    332   )
    333 {
    334   EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;
    335   EFI_ACPI_NOTIFY_LIST      *CurrentNotifyList;
    336   LIST_ENTRY                *CurrentLink;
    337   LIST_ENTRY                *StartLink;
    338 
    339   //
    340   // Get the instance of the ACPI Table
    341   //
    342   AcpiTableInstance = SdtGetAcpiTableInstance ();
    343 
    344   //
    345   // Find the notify
    346   //
    347   StartLink   = &AcpiTableInstance->NotifyList;
    348   CurrentLink = StartLink->ForwardLink;
    349 
    350   while (CurrentLink != StartLink) {
    351     CurrentNotifyList = EFI_ACPI_NOTIFY_LIST_FROM_LINK (CurrentLink);
    352     if (CurrentNotifyList->Notification == Notification) {
    353       //
    354       // Good! Found notification.
    355       //
    356       // Remove it from list and free the node.
    357       //
    358       RemoveEntryList (&(CurrentNotifyList->Link));
    359       FreePool (CurrentNotifyList);
    360       return EFI_SUCCESS;
    361     }
    362 
    363     CurrentLink = CurrentLink->ForwardLink;
    364   }
    365 
    366   //
    367   // Not found!
    368   //
    369   return EFI_INVALID_PARAMETER;
    370 }
    371 
    372 /**
    373   Register or unregister a callback when an ACPI table is installed.
    374 
    375   This function registers or unregisters a function which will be called whenever a new ACPI table is
    376   installed.
    377 
    378   @param[in]    Register        If TRUE, then the specified function will be registered. If FALSE, then the specified
    379                                 function will be unregistered.
    380   @param[in]    Notification    Points to the callback function to be registered or unregistered.
    381 
    382   @retval EFI_SUCCESS           Callback successfully registered or unregistered.
    383   @retval EFI_INVALID_PARAMETER Notification is NULL
    384   @retval EFI_INVALID_PARAMETER Register is FALSE and Notification does not match a known registration function.
    385 **/
    386 EFI_STATUS
    387 EFIAPI
    388 RegisterNotify (
    389   IN BOOLEAN                    Register,
    390   IN EFI_ACPI_NOTIFICATION_FN   Notification
    391   )
    392 {
    393   //
    394   // Check for invalid input parameters
    395   //
    396   if (Notification == NULL) {
    397     return EFI_INVALID_PARAMETER;
    398   }
    399 
    400   if (Register) {
    401     //
    402     // Register a new notify
    403     //
    404     SdtRegisterNotify (Notification);
    405     return EFI_SUCCESS;
    406   } else {
    407     //
    408     // Unregister an old notify
    409     //
    410     return SdtUnregisterNotify (Notification);
    411   }
    412 }
    413 
    414 /**
    415   Create a handle for the first ACPI opcode in an ACPI system description table.
    416 
    417   @param[in]    TableKey    The table key for the ACPI table, as returned by GetTable().
    418   @param[out]   Handle      On return, points to the newly created ACPI handle.
    419 
    420   @retval EFI_SUCCESS       Handle created successfully.
    421   @retval EFI_NOT_FOUND     TableKey does not refer to a valid ACPI table.
    422 **/
    423 EFI_STATUS
    424 SdtOpenSdtTable (
    425   IN    UINTN           TableKey,
    426   OUT   EFI_ACPI_HANDLE *Handle
    427   )
    428 {
    429   EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance;
    430   EFI_STATUS                Status;
    431   EFI_ACPI_TABLE_LIST       *Table;
    432   EFI_AML_HANDLE            *AmlHandle;
    433 
    434   //
    435   // Get the instance of the ACPI Table
    436   //
    437   AcpiTableInstance = SdtGetAcpiTableInstance ();
    438 
    439   //
    440   // Find the table
    441   //
    442   Status = FindTableByHandle (
    443              TableKey,
    444              &AcpiTableInstance->TableList,
    445              &Table
    446              );
    447   if (EFI_ERROR (Status)) {
    448     return EFI_NOT_FOUND;
    449   }
    450 
    451   AmlHandle = AllocatePool (sizeof(*AmlHandle));
    452   ASSERT (AmlHandle != NULL);
    453   AmlHandle->Signature       = EFI_AML_ROOT_HANDLE_SIGNATURE;
    454   AmlHandle->Buffer          = (VOID *)((UINTN)Table->Table + sizeof(EFI_ACPI_SDT_HEADER));
    455   AmlHandle->Size            = Table->Table->Length - sizeof(EFI_ACPI_SDT_HEADER);
    456   AmlHandle->AmlByteEncoding = NULL;
    457   AmlHandle->Modified        = FALSE;
    458 
    459   //
    460   // return the ACPI handle
    461   //
    462   *Handle = (EFI_ACPI_HANDLE)AmlHandle;
    463 
    464   return EFI_SUCCESS;
    465 }
    466 
    467 /**
    468   Create a handle for the first ACPI opcode in an ACPI system description table.
    469 
    470   @param[in]    TableKey    The table key for the ACPI table, as returned by GetTable().
    471   @param[out]   Handle      On return, points to the newly created ACPI handle.
    472 
    473   @retval EFI_SUCCESS       Handle created successfully.
    474   @retval EFI_NOT_FOUND     TableKey does not refer to a valid ACPI table.
    475 **/
    476 EFI_STATUS
    477 EFIAPI
    478 OpenSdt (
    479   IN    UINTN           TableKey,
    480   OUT   EFI_ACPI_HANDLE *Handle
    481   )
    482 {
    483   if (Handle == NULL) {
    484     return EFI_INVALID_PARAMETER;
    485   }
    486 
    487   return SdtOpenSdtTable (TableKey, Handle);
    488 }
    489 
    490 /**
    491   Create a handle from an ACPI opcode
    492 
    493   @param[in]  Buffer                 Points to the ACPI opcode.
    494   @param[in]  BufferSize             Max buffer size.
    495   @param[out] Handle                 Upon return, holds the handle.
    496 
    497   @retval   EFI_SUCCESS             Success
    498   @retval   EFI_INVALID_PARAMETER   Buffer is NULL or Handle is NULL or Buffer points to an
    499                                     invalid opcode.
    500 
    501 **/
    502 EFI_STATUS
    503 SdtOpenEx (
    504   IN    VOID            *Buffer,
    505   IN    UINTN           BufferSize,
    506   OUT   EFI_ACPI_HANDLE *Handle
    507   )
    508 {
    509   AML_BYTE_ENCODING   *AmlByteEncoding;
    510   EFI_AML_HANDLE      *AmlHandle;
    511 
    512   AmlByteEncoding = AmlSearchByOpByte (Buffer);
    513   if (AmlByteEncoding == NULL) {
    514     return EFI_INVALID_PARAMETER;
    515   }
    516 
    517   //
    518   // Do not open NameString as handle
    519   //
    520   if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
    521     return EFI_INVALID_PARAMETER;
    522   }
    523 
    524   //
    525   // Good, find it
    526   //
    527   AmlHandle = AllocatePool (sizeof(*AmlHandle));
    528   ASSERT (AmlHandle != NULL);
    529 
    530   AmlHandle->Signature       = EFI_AML_HANDLE_SIGNATURE;
    531   AmlHandle->Buffer          = Buffer;
    532   AmlHandle->AmlByteEncoding = AmlByteEncoding;
    533   AmlHandle->Modified        = FALSE;
    534 
    535   AmlHandle->Size = AmlGetObjectSize (AmlByteEncoding, Buffer, BufferSize);
    536   if (AmlHandle->Size == 0) {
    537     FreePool (AmlHandle);
    538     return EFI_INVALID_PARAMETER;
    539   }
    540 
    541   *Handle = (EFI_ACPI_HANDLE)AmlHandle;
    542 
    543   return EFI_SUCCESS;
    544 }
    545 
    546 /**
    547   Create a handle from an ACPI opcode
    548 
    549   @param[in]  Buffer                 Points to the ACPI opcode.
    550   @param[out] Handle                 Upon return, holds the handle.
    551 
    552   @retval   EFI_SUCCESS             Success
    553   @retval   EFI_INVALID_PARAMETER   Buffer is NULL or Handle is NULL or Buffer points to an
    554                                     invalid opcode.
    555 
    556 **/
    557 EFI_STATUS
    558 EFIAPI
    559 Open (
    560   IN    VOID            *Buffer,
    561   OUT   EFI_ACPI_HANDLE *Handle
    562   )
    563 {
    564   EFI_STATUS          Status;
    565   UINTN               MaxSize;
    566 
    567   MaxSize = 0;
    568 
    569   //
    570   // Check for invalid input parameters
    571   //
    572   if (Buffer == NULL || Handle == NULL) {
    573     return EFI_INVALID_PARAMETER;
    574   }
    575 
    576   Status = SdtGetMaxAmlBufferSize (Buffer, &MaxSize);
    577   if (EFI_ERROR (Status)) {
    578     return EFI_INVALID_PARAMETER;
    579   }
    580 
    581   return SdtOpenEx (Buffer, MaxSize, Handle);
    582 }
    583 
    584 /**
    585   Close an ACPI handle.
    586 
    587   @param[in] Handle Returns the handle.
    588 
    589   @retval EFI_SUCCESS           Success
    590   @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
    591 **/
    592 EFI_STATUS
    593 EFIAPI
    594 Close (
    595   IN EFI_ACPI_HANDLE Handle
    596   )
    597 {
    598   EFI_AML_HANDLE      *AmlHandle;
    599   EFI_STATUS          Status;
    600 
    601   //
    602   // Check for invalid input parameters
    603   //
    604   if (Handle == NULL) {
    605     return EFI_INVALID_PARAMETER;
    606   }
    607 
    608   AmlHandle = (EFI_AML_HANDLE *)Handle;
    609   if ((AmlHandle->Signature != EFI_AML_ROOT_HANDLE_SIGNATURE) &&
    610       (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {
    611     return EFI_INVALID_PARAMETER;
    612   }
    613 
    614   //
    615   // Update Checksum only if modified
    616   //
    617   if (AmlHandle->Modified) {
    618     Status = SdtUpdateAmlChecksum (AmlHandle->Buffer);
    619     if (EFI_ERROR (Status)) {
    620       return EFI_INVALID_PARAMETER;
    621     }
    622   }
    623 
    624   FreePool (AmlHandle);
    625 
    626   return EFI_SUCCESS;
    627 }
    628 
    629 /**
    630   Retrieve information about an ACPI object.
    631 
    632   @param[in]    Handle      ACPI object handle.
    633   @param[in]    Index       Index of the data to retrieve from the object. In general, indexes read from left-to-right
    634                             in the ACPI encoding, with index 0 always being the ACPI opcode.
    635   @param[out]   DataType    Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
    636                             for the specified index.
    637   @param[out]   Data        Upon return, points to the pointer to the data.
    638   @param[out]   DataSize    Upon return, points to the size of Data.
    639 
    640   @retval       EFI_SUCCESS           Success.
    641   @retval       EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
    642 **/
    643 EFI_STATUS
    644 EFIAPI
    645 GetOption (
    646   IN        EFI_ACPI_HANDLE     Handle,
    647   IN        UINTN               Index,
    648   OUT       EFI_ACPI_DATA_TYPE  *DataType,
    649   OUT CONST VOID                **Data,
    650   OUT       UINTN               *DataSize
    651   )
    652 {
    653   EFI_AML_HANDLE      *AmlHandle;
    654   AML_BYTE_ENCODING   *AmlByteEncoding;
    655   EFI_STATUS          Status;
    656 
    657   ASSERT (DataType != NULL);
    658   ASSERT (Data != NULL);
    659   ASSERT (DataSize != NULL);
    660 
    661   //
    662   // Check for invalid input parameters
    663   //
    664   if (Handle == NULL) {
    665     return EFI_INVALID_PARAMETER;
    666   }
    667 
    668   AmlHandle = (EFI_AML_HANDLE *)Handle;
    669   //
    670   // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle
    671   //
    672   if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {
    673     return EFI_INVALID_PARAMETER;
    674   }
    675 
    676   AmlByteEncoding = AmlHandle->AmlByteEncoding;
    677   if (Index > AmlByteEncoding->MaxIndex) {
    678     *DataType = EFI_ACPI_DATA_TYPE_NONE;
    679     return EFI_SUCCESS;
    680   }
    681 
    682   //
    683   // Parse option
    684   //
    685   Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, DataType, (VOID **)Data, DataSize);
    686   if (EFI_ERROR (Status)) {
    687     return EFI_INVALID_PARAMETER;
    688   }
    689 
    690   return EFI_SUCCESS;
    691 }
    692 
    693 /**
    694   Change information about an ACPI object.
    695 
    696   @param[in]  Handle    ACPI object handle.
    697   @param[in]  Index     Index of the data to retrieve from the object. In general, indexes read from left-to-right
    698                         in the ACPI encoding, with index 0 always being the ACPI opcode.
    699   @param[in]  Data      Points to the data.
    700   @param[in]  DataSize  The size of the Data.
    701 
    702   @retval EFI_SUCCESS           Success
    703   @retval EFI_INVALID_PARAMETER Handle is NULL or does not refer to a valid ACPI object.
    704   @retval EFI_BAD_BUFFER_SIZE   Data cannot be accommodated in the space occupied by
    705                                 the option.
    706 
    707 **/
    708 EFI_STATUS
    709 EFIAPI
    710 SetOption (
    711   IN        EFI_ACPI_HANDLE Handle,
    712   IN        UINTN           Index,
    713   IN CONST  VOID            *Data,
    714   IN        UINTN           DataSize
    715   )
    716 {
    717   EFI_AML_HANDLE      *AmlHandle;
    718   AML_BYTE_ENCODING   *AmlByteEncoding;
    719   EFI_STATUS          Status;
    720   EFI_ACPI_DATA_TYPE  DataType;
    721   VOID                *OrgData;
    722   UINTN               OrgDataSize;
    723 
    724   ASSERT (Data != NULL);
    725 
    726   //
    727   // Check for invalid input parameters
    728   //
    729   if (Handle == NULL) {
    730     return EFI_INVALID_PARAMETER;
    731   }
    732 
    733   AmlHandle = (EFI_AML_HANDLE *)Handle;
    734   //
    735   // Do not check EFI_AML_ROOT_HANDLE_SIGNATURE because there is no option for Root handle
    736   //
    737   if (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE) {
    738     return EFI_INVALID_PARAMETER;
    739   }
    740   AmlByteEncoding = AmlHandle->AmlByteEncoding;
    741 
    742   if (Index > AmlByteEncoding->MaxIndex) {
    743     return EFI_INVALID_PARAMETER;
    744   }
    745 
    746   //
    747   // Parse option
    748   //
    749   Status = AmlParseOptionHandleCommon (AmlHandle, (AML_OP_PARSE_INDEX)Index, &DataType, &OrgData, &OrgDataSize);
    750   if (EFI_ERROR (Status)) {
    751     return EFI_INVALID_PARAMETER;
    752   }
    753   if (DataType == EFI_ACPI_DATA_TYPE_NONE) {
    754     return EFI_INVALID_PARAMETER;
    755   }
    756 
    757   if (DataSize > OrgDataSize) {
    758     return EFI_BAD_BUFFER_SIZE;
    759   }
    760 
    761   //
    762   // Update
    763   //
    764   CopyMem (OrgData, Data, DataSize);
    765   AmlHandle->Modified = TRUE;
    766 
    767   return EFI_SUCCESS;
    768 }
    769 
    770 /**
    771   Return the child ACPI objects.
    772 
    773   @param[in]        ParentHandle    Parent handle.
    774   @param[in, out]   Handle          On entry, points to the previously returned handle or NULL to start with the first
    775                                     handle. On return, points to the next returned ACPI handle or NULL if there are no
    776                                     child objects.
    777 
    778   @retval EFI_SUCCESS               Success
    779   @retval EFI_INVALID_PARAMETER     ParentHandle is NULL or does not refer to a valid ACPI object.
    780 **/
    781 EFI_STATUS
    782 EFIAPI
    783 GetChild (
    784   IN EFI_ACPI_HANDLE        ParentHandle,
    785   IN OUT EFI_ACPI_HANDLE    *Handle
    786   )
    787 {
    788   EFI_AML_HANDLE      *AmlParentHandle;
    789   EFI_AML_HANDLE      *AmlHandle;
    790   VOID                *Buffer;
    791   EFI_STATUS          Status;
    792 
    793   ASSERT (Handle != NULL);
    794 
    795   //
    796   // Check for invalid input parameters
    797   //
    798   if (ParentHandle == NULL) {
    799     return EFI_INVALID_PARAMETER;
    800   }
    801 
    802   AmlHandle       = *Handle;
    803   if ((AmlHandle != NULL) && (AmlHandle->Signature != EFI_AML_HANDLE_SIGNATURE)) {
    804     return EFI_INVALID_PARAMETER;
    805   }
    806 
    807   AmlParentHandle = (EFI_AML_HANDLE *)ParentHandle;
    808   if (AmlParentHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {
    809     //
    810     // Root handle
    811     //
    812     Status = AmlGetChildFromRoot (AmlParentHandle, AmlHandle, &Buffer);
    813   } else if (AmlParentHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {
    814     //
    815     // Non-root handle
    816     //
    817     Status = AmlGetChildFromNonRoot (AmlParentHandle, AmlHandle, &Buffer);
    818   } else {
    819     //
    820     // Invalid
    821     //
    822     return EFI_INVALID_PARAMETER;
    823   }
    824 
    825   if (EFI_ERROR (Status)) {
    826     return EFI_INVALID_PARAMETER;
    827   }
    828   if (Buffer == NULL) {
    829     *Handle = NULL;
    830     return EFI_SUCCESS;
    831   }
    832   return SdtOpenEx (Buffer, (UINTN)AmlParentHandle->Buffer + AmlParentHandle->Size - (UINTN)Buffer, Handle);
    833 }
    834 
    835 /**
    836   Returns the handle of the ACPI object representing the specified ACPI path
    837 
    838   @param[in]    HandleIn    Points to the handle of the object representing the starting point for the path search.
    839   @param[in]    AmlPath     Points to the AML path.
    840   @param[out]   HandleOut   On return, points to the ACPI object which represents AcpiPath, relative to
    841                             HandleIn.
    842 
    843   @retval EFI_SUCCESS           Success
    844   @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
    845 **/
    846 EFI_STATUS
    847 SdtFindPathFromNonRoot (
    848   IN    EFI_ACPI_HANDLE HandleIn,
    849   IN    UINT8           *AmlPath,
    850   OUT   EFI_ACPI_HANDLE *HandleOut
    851   )
    852 {
    853   EFI_AML_HANDLE      *AmlHandle;
    854   VOID                *Buffer;
    855   EFI_STATUS          Status;
    856 
    857   Buffer = NULL;
    858   AmlHandle = (EFI_AML_HANDLE *)HandleIn;
    859 
    860   //
    861   // For non-root handle, we need search from THIS node instead of ROOT.
    862   //
    863   Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, FALSE);
    864   if (EFI_ERROR (Status)) {
    865     return EFI_INVALID_PARAMETER;
    866   }
    867   if (Buffer == NULL) {
    868     *HandleOut = NULL;
    869     return EFI_SUCCESS;
    870   }
    871   return SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);
    872 }
    873 
    874 /**
    875   Duplicate AML handle.
    876 
    877   @param[in]    AmlHandle   Handle to be duplicated.
    878 
    879   @return Duplicated AML handle.
    880 **/
    881 EFI_AML_HANDLE *
    882 SdtDuplicateHandle (
    883   IN EFI_AML_HANDLE      *AmlHandle
    884   )
    885 {
    886   EFI_AML_HANDLE  *DstAmlHandle;
    887 
    888   DstAmlHandle = AllocatePool (sizeof(*DstAmlHandle));
    889   ASSERT (DstAmlHandle != NULL);
    890   CopyMem (DstAmlHandle, (VOID *)AmlHandle, sizeof(*DstAmlHandle));
    891 
    892   return DstAmlHandle;
    893 }
    894 
    895 /**
    896   Returns the handle of the ACPI object representing the specified ACPI path
    897 
    898   @param[in]    HandleIn    Points to the handle of the object representing the starting point for the path search.
    899   @param[in]    AmlPath     Points to the AML path.
    900   @param[out]   HandleOut   On return, points to the ACPI object which represents AcpiPath, relative to
    901                             HandleIn.
    902 
    903   @retval EFI_SUCCESS           Success
    904   @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
    905 **/
    906 EFI_STATUS
    907 SdtFindPathFromRoot (
    908   IN    EFI_ACPI_HANDLE HandleIn,
    909   IN    UINT8           *AmlPath,
    910   OUT   EFI_ACPI_HANDLE *HandleOut
    911   )
    912 {
    913   EFI_ACPI_HANDLE     ChildHandle;
    914   EFI_AML_HANDLE      *AmlHandle;
    915   EFI_STATUS          Status;
    916   VOID                *Buffer;
    917 
    918   Buffer = NULL;
    919   AmlHandle = (EFI_AML_HANDLE *)HandleIn;
    920 
    921   //
    922   // Handle case that AcpiPath is Root
    923   //
    924   if (AmlIsRootPath (AmlPath)) {
    925     //
    926     // Duplicate RootHandle
    927     //
    928     *HandleOut = (EFI_ACPI_HANDLE)SdtDuplicateHandle (AmlHandle);
    929     return EFI_SUCCESS;
    930   }
    931 
    932   //
    933   // Let children find it.
    934   //
    935   ChildHandle = NULL;
    936   while (TRUE) {
    937     Status = GetChild (HandleIn, &ChildHandle);
    938     if (EFI_ERROR (Status)) {
    939       return EFI_INVALID_PARAMETER;
    940     }
    941 
    942     if (ChildHandle == NULL) {
    943       //
    944       // Not found
    945       //
    946       *HandleOut = NULL;
    947       return EFI_SUCCESS;
    948     }
    949 
    950     //
    951     // More child
    952     //
    953     AmlHandle = (EFI_AML_HANDLE *)ChildHandle;
    954     Status = AmlFindPath (AmlHandle, AmlPath, &Buffer, TRUE);
    955     if (EFI_ERROR (Status)) {
    956       return EFI_INVALID_PARAMETER;
    957     }
    958 
    959     if (Buffer != NULL) {
    960       //
    961       // Great! Find it, open
    962       //
    963       Status = SdtOpenEx (Buffer, (UINTN)AmlHandle->Buffer + AmlHandle->Size - (UINTN)Buffer, HandleOut);
    964       if (!EFI_ERROR (Status))  {
    965         return EFI_SUCCESS;
    966       }
    967       //
    968       // Not success, try next one
    969       //
    970     }
    971   }
    972 
    973   //
    974   // Should not run here
    975   //
    976 }
    977 
    978 /**
    979   Returns the handle of the ACPI object representing the specified ACPI path
    980 
    981   @param[in]    HandleIn    Points to the handle of the object representing the starting point for the path search.
    982   @param[in]    AcpiPath    Points to the ACPI path, which conforms to the ACPI encoded path format.
    983   @param[out]   HandleOut   On return, points to the ACPI object which represents AcpiPath, relative to
    984                             HandleIn.
    985 
    986   @retval EFI_SUCCESS           Success
    987   @retval EFI_INVALID_PARAMETER HandleIn is NULL or does not refer to a valid ACPI object.
    988 **/
    989 EFI_STATUS
    990 EFIAPI
    991 FindPath (
    992   IN    EFI_ACPI_HANDLE HandleIn,
    993   IN    VOID            *AcpiPath,
    994   OUT   EFI_ACPI_HANDLE *HandleOut
    995   )
    996 {
    997   EFI_AML_HANDLE      *AmlHandle;
    998   EFI_STATUS          Status;
    999   UINT8               *AmlPath;
   1000 
   1001   //
   1002   // Check for invalid input parameters
   1003   //
   1004   if (HandleIn == NULL) {
   1005     return EFI_INVALID_PARAMETER;
   1006   }
   1007 
   1008   AmlHandle = (EFI_AML_HANDLE *)HandleIn;
   1009 
   1010   //
   1011   // Convert ASL path to AML path
   1012   //
   1013   AmlPath = AmlNameFromAslName (AcpiPath);
   1014   if (AmlPath == NULL) {
   1015     return EFI_INVALID_PARAMETER;
   1016   }
   1017 
   1018   DEBUG_CODE_BEGIN ();
   1019   DEBUG ((EFI_D_ERROR, "AcpiSdt: FindPath - "));
   1020   AmlPrintNameString (AmlPath);
   1021   DEBUG ((EFI_D_ERROR, "\n"));
   1022   DEBUG_CODE_END ();
   1023 
   1024   if (AmlHandle->Signature == EFI_AML_ROOT_HANDLE_SIGNATURE) {
   1025     //
   1026     // Root Handle
   1027     //
   1028     Status = SdtFindPathFromRoot (HandleIn, AmlPath, HandleOut);
   1029   } else if (AmlHandle->Signature == EFI_AML_HANDLE_SIGNATURE) {
   1030     //
   1031     // Non-Root handle
   1032     //
   1033     Status = SdtFindPathFromNonRoot (HandleIn, AmlPath, HandleOut);
   1034   } else {
   1035     Status = EFI_INVALID_PARAMETER;
   1036   }
   1037 
   1038   FreePool (AmlPath);
   1039 
   1040   return Status;
   1041 }
   1042 
   1043 /**
   1044   This function initializes AcpiSdt protocol in ACPI table instance.
   1045 
   1046   @param[in]  AcpiTableInstance       Instance to construct
   1047 **/
   1048 VOID
   1049 SdtAcpiTableAcpiSdtConstructor (
   1050   IN EFI_ACPI_TABLE_INSTANCE   *AcpiTableInstance
   1051   )
   1052 {
   1053 
   1054   InitializeListHead (&AcpiTableInstance->NotifyList);
   1055   CopyMem (&AcpiTableInstance->AcpiSdtProtocol, &mAcpiSdtProtocolTemplate, sizeof(mAcpiSdtProtocolTemplate));
   1056   AcpiTableInstance->AcpiSdtProtocol.AcpiVersion = (EFI_ACPI_TABLE_VERSION)PcdGet32 (PcdAcpiExposedTableVersions);
   1057 
   1058   return ;
   1059 }
   1060