Home | History | Annotate | Download | only in AcpiTableDxe
      1 /** @file
      2   ACPI Sdt Protocol Driver
      3 
      4   Copyright (c) 2010, 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 #include "AcpiTable.h"
     16 
     17 /**
     18   Retrieve option term according to AmlByteEncoding and Buffer.
     19 
     20   @param[in]    AmlByteEncoding      AML Byte Encoding.
     21   @param[in]    Buffer               AML buffer.
     22   @param[in]    MaxBufferSize        AML buffer MAX size. The parser can not parse any data exceed this region.
     23   @param[in]    TermIndex            Index of the data to retrieve from the object.
     24   @param[out]   DataType             Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
     25                                      for the specified index.
     26   @param[out]   Data                 Upon return, points to the pointer to the data.
     27   @param[out]   DataSize             Upon return, points to the size of Data.
     28 
     29   @retval       EFI_SUCCESS           Success.
     30   @retval       EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
     31 **/
     32 EFI_STATUS
     33 AmlParseOptionTerm (
     34   IN AML_BYTE_ENCODING   *AmlByteEncoding,
     35   IN UINT8               *Buffer,
     36   IN UINTN               MaxBufferSize,
     37   IN AML_OP_PARSE_INDEX  TermIndex,
     38   OUT EFI_ACPI_DATA_TYPE *DataType,
     39   OUT VOID               **Data,
     40   OUT UINTN              *DataSize
     41   )
     42 {
     43   AML_BYTE_ENCODING   *ChildAmlByteEncoding;
     44   EFI_STATUS          Status;
     45 
     46   if (DataType != NULL) {
     47     *DataType = AmlTypeToAcpiType (AmlByteEncoding->Format[TermIndex - 1]);
     48   }
     49   if (Data != NULL) {
     50     *Data = Buffer;
     51   }
     52   //
     53   // Parse term according to AML type
     54   //
     55   switch (AmlByteEncoding->Format[TermIndex - 1]) {
     56   case AML_UINT8:
     57     *DataSize = sizeof(UINT8);
     58     break;
     59   case AML_UINT16:
     60     *DataSize = sizeof(UINT16);
     61     break;
     62   case AML_UINT32:
     63     *DataSize = sizeof(UINT32);
     64     break;
     65   case AML_UINT64:
     66     *DataSize = sizeof(UINT64);
     67     break;
     68   case AML_STRING:
     69     *DataSize = AsciiStrSize((CHAR8 *)Buffer);
     70     break;
     71   case AML_NAME:
     72     Status = AmlGetNameStringSize (Buffer, DataSize);
     73     if (EFI_ERROR (Status)) {
     74       return EFI_INVALID_PARAMETER;
     75     }
     76     break;
     77   case AML_OBJECT:
     78     ChildAmlByteEncoding = AmlSearchByOpByte (Buffer);
     79     if (ChildAmlByteEncoding == NULL) {
     80       return EFI_INVALID_PARAMETER;
     81     }
     82 
     83     //
     84     // NOTE: We need override DataType here, if there is a case the AML_OBJECT is AML_NAME.
     85     // We need convert type from EFI_ACPI_DATA_TYPE_CHILD to EFI_ACPI_DATA_TYPE_NAME_STRING.
     86     // We should not return CHILD because there is NO OpCode for NameString.
     87     //
     88     if ((ChildAmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
     89       if (DataType != NULL) {
     90         *DataType = AmlTypeToAcpiType (AML_NAME);
     91       }
     92       Status = AmlGetNameStringSize (Buffer, DataSize);
     93       if (EFI_ERROR (Status)) {
     94         return EFI_INVALID_PARAMETER;
     95       }
     96       break;
     97     }
     98 
     99     //
    100     // It is real AML_OBJECT
    101     //
    102     *DataSize = AmlGetObjectSize (
    103                      ChildAmlByteEncoding,
    104                      Buffer,
    105                      MaxBufferSize
    106                      );
    107     if (*DataSize == 0) {
    108       return EFI_INVALID_PARAMETER;
    109     }
    110     break;
    111   case AML_NONE:
    112     //
    113     // No term
    114     //
    115   case AML_OPCODE:
    116   default:
    117     ASSERT (FALSE);
    118     return EFI_INVALID_PARAMETER;
    119   }
    120   if (*DataSize > MaxBufferSize) {
    121     return EFI_INVALID_PARAMETER;
    122   }
    123   return EFI_SUCCESS;
    124 }
    125 
    126 /**
    127   Retrieve information according to AmlByteEncoding and Buffer.
    128 
    129   @param[in]    AmlByteEncoding      AML Byte Encoding.
    130   @param[in]    Buffer               AML buffer.
    131   @param[in]    MaxBufferSize        AML buffer MAX size. The parser can not parse any data exceed this region.
    132   @param[in]    Index                Index of the data to retrieve from the object. In general, indexes read from left-to-right
    133                                      in the ACPI encoding, with index 0 always being the ACPI opcode.
    134   @param[out]   DataType             Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
    135                                      for the specified index.
    136   @param[out]   Data                 Upon return, points to the pointer to the data.
    137   @param[out]   DataSize             Upon return, points to the size of Data.
    138 
    139   @retval       EFI_SUCCESS           Success.
    140   @retval       EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object.
    141 **/
    142 EFI_STATUS
    143 AmlParseOptionCommon (
    144   IN AML_BYTE_ENCODING   *AmlByteEncoding,
    145   IN UINT8               *Buffer,
    146   IN UINTN               MaxBufferSize,
    147   IN AML_OP_PARSE_INDEX  Index,
    148   OUT EFI_ACPI_DATA_TYPE *DataType,
    149   OUT VOID               **Data,
    150   OUT UINTN              *DataSize
    151   )
    152 {
    153   UINT8               *CurrentBuffer;
    154   UINTN               PkgLength;
    155   UINTN               OpLength;
    156   UINTN               PkgOffset;
    157   AML_OP_PARSE_INDEX  TermIndex;
    158   EFI_STATUS          Status;
    159 
    160   ASSERT ((Index <= AmlByteEncoding->MaxIndex) || (Index == AML_OP_PARSE_INDEX_GET_SIZE));
    161 
    162   //
    163   // 0. Check if this is NAME string.
    164   //
    165   if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
    166     //
    167     // Only allow GET_SIZE
    168     //
    169     if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
    170       return EFI_INVALID_PARAMETER;
    171     }
    172     //
    173     // return NameString size
    174     //
    175     Status = AmlGetNameStringSize (Buffer, DataSize);
    176     if (EFI_ERROR (Status)) {
    177       return EFI_INVALID_PARAMETER;
    178     }
    179     if (*DataSize > MaxBufferSize) {
    180       return EFI_INVALID_PARAMETER;
    181     }
    182     return EFI_SUCCESS;
    183   }
    184 
    185   //
    186   // Not NAME string, start parsing
    187   //
    188   CurrentBuffer = Buffer;
    189 
    190   //
    191   // 1. Get OpCode
    192   //
    193   if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
    194     *DataType = EFI_ACPI_DATA_TYPE_OPCODE;
    195     *Data = (VOID *)CurrentBuffer;
    196   }
    197   if (*CurrentBuffer == AML_EXT_OP) {
    198     OpLength = 2;
    199   } else {
    200     OpLength = 1;
    201   }
    202   *DataSize = OpLength;
    203   if (Index == AML_OP_PARSE_INDEX_GET_OPCODE) {
    204     return EFI_SUCCESS;
    205   }
    206   if (OpLength > MaxBufferSize) {
    207     return EFI_INVALID_PARAMETER;
    208   }
    209   CurrentBuffer += OpLength;
    210 
    211   //
    212   // 2. Skip PkgLength field, if have
    213   //
    214   if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
    215     PkgOffset = AmlGetPkgLength(CurrentBuffer, &PkgLength);
    216     //
    217     // Override MaxBufferSize if it is valid PkgLength
    218     //
    219     if (OpLength + PkgLength > MaxBufferSize) {
    220       return EFI_INVALID_PARAMETER;
    221     } else {
    222       MaxBufferSize = OpLength + PkgLength;
    223     }
    224   } else {
    225     PkgOffset = 0;
    226     PkgLength = 0;
    227   }
    228   CurrentBuffer += PkgOffset;
    229 
    230   //
    231   // 3. Get Term one by one.
    232   //
    233   TermIndex = AML_OP_PARSE_INDEX_GET_TERM1;
    234   while ((Index >= TermIndex) && (TermIndex <= AmlByteEncoding->MaxIndex) && ((UINTN)CurrentBuffer < (UINTN)Buffer + MaxBufferSize)) {
    235     Status = AmlParseOptionTerm (
    236                AmlByteEncoding,
    237                CurrentBuffer,
    238                (UINTN)Buffer + MaxBufferSize - (UINTN)CurrentBuffer,
    239                TermIndex,
    240                DataType,
    241                Data,
    242                DataSize
    243                );
    244     if (EFI_ERROR (Status)) {
    245       return EFI_INVALID_PARAMETER;
    246     }
    247 
    248     if (Index == TermIndex) {
    249       //
    250       // Done
    251       //
    252       return EFI_SUCCESS;
    253     }
    254 
    255     //
    256     // Parse next one
    257     //
    258     CurrentBuffer += *DataSize;
    259     TermIndex ++;
    260   }
    261 
    262   //
    263   // Finish all options, but no option found.
    264   //
    265   if ((UINTN)CurrentBuffer > (UINTN)Buffer + MaxBufferSize) {
    266     return EFI_INVALID_PARAMETER;
    267   }
    268   if ((UINTN)CurrentBuffer == (UINTN)Buffer + MaxBufferSize) {
    269     if (Index != AML_OP_PARSE_INDEX_GET_SIZE) {
    270       return EFI_INVALID_PARAMETER;
    271     }
    272   }
    273 
    274   //
    275   // 4. Finish parsing all node, return size
    276   //
    277   ASSERT (Index == AML_OP_PARSE_INDEX_GET_SIZE);
    278   if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
    279     *DataSize = OpLength + PkgLength;
    280   } else {
    281     *DataSize = (UINTN)CurrentBuffer - (UINTN)Buffer;
    282   }
    283 
    284   return EFI_SUCCESS;
    285 }
    286 
    287 /**
    288   Return object size.
    289 
    290   @param[in]    AmlByteEncoding      AML Byte Encoding.
    291   @param[in]    Buffer               AML object buffer.
    292   @param[in]    MaxBufferSize        AML object buffer MAX size. The parser can not parse any data exceed this region.
    293 
    294   @return       Size of the object.
    295 **/
    296 UINTN
    297 AmlGetObjectSize (
    298   IN AML_BYTE_ENCODING   *AmlByteEncoding,
    299   IN UINT8               *Buffer,
    300   IN UINTN               MaxBufferSize
    301   )
    302 {
    303   EFI_STATUS   Status;
    304   UINTN        DataSize;
    305 
    306   Status = AmlParseOptionCommon (
    307                AmlByteEncoding,
    308                Buffer,
    309                MaxBufferSize,
    310                AML_OP_PARSE_INDEX_GET_SIZE,
    311                NULL,
    312                NULL,
    313                &DataSize
    314                );
    315   if (EFI_ERROR (Status)) {
    316     return 0;
    317   } else {
    318     return DataSize;
    319   }
    320 }
    321 
    322 /**
    323   Return object name.
    324 
    325   @param[in]    AmlHandle            AML handle.
    326 
    327   @return       Name of the object.
    328 **/
    329 CHAR8 *
    330 AmlGetObjectName (
    331   IN EFI_AML_HANDLE      *AmlHandle
    332   )
    333 {
    334   AML_BYTE_ENCODING   *AmlByteEncoding;
    335   VOID                *NameString;
    336   UINTN               NameSize;
    337   AML_OP_PARSE_INDEX  TermIndex;
    338   EFI_STATUS          Status;
    339   EFI_ACPI_DATA_TYPE  DataType;
    340 
    341   AmlByteEncoding = AmlHandle->AmlByteEncoding;
    342 
    343   ASSERT ((AmlByteEncoding->Attribute & AML_IN_NAMESPACE) != 0);
    344 
    345   //
    346   // Find out Last Name index, according to OpCode table.
    347   // The last name will be the node name by design.
    348   //
    349   TermIndex = AmlByteEncoding->MaxIndex;
    350   for (TermIndex = AmlByteEncoding->MaxIndex; TermIndex > 0; TermIndex--) {
    351     if (AmlByteEncoding->Format[TermIndex - 1] == AML_NAME) {
    352       break;
    353     }
    354   }
    355   ASSERT (TermIndex != 0);
    356 
    357   //
    358   // Get Name for this node.
    359   //
    360   Status = AmlParseOptionHandleCommon (
    361              AmlHandle,
    362              TermIndex,
    363              &DataType,
    364              &NameString,
    365              &NameSize
    366              );
    367   if (EFI_ERROR (Status)) {
    368     return NULL;
    369   }
    370   ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING);
    371 
    372   return NameString;
    373 }
    374 
    375 /**
    376   Return offset of last option.
    377 
    378   @param[in]    AmlHandle            AML Handle.
    379   @param[out]   Buffer               Upon return, points to the offset after last option.
    380 
    381   @retval       EFI_SUCCESS           Success.
    382   @retval       EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
    383 **/
    384 EFI_STATUS
    385 AmlGetOffsetAfterLastOption (
    386   IN EFI_AML_HANDLE         *AmlHandle,
    387   OUT UINT8                 **Buffer
    388   )
    389 {
    390   EFI_ACPI_DATA_TYPE  DataType;
    391   VOID                *Data;
    392   UINTN               DataSize;
    393   EFI_STATUS          Status;
    394 
    395   Status = AmlParseOptionHandleCommon (
    396              AmlHandle,
    397              AmlHandle->AmlByteEncoding->MaxIndex,
    398              &DataType,
    399              &Data,
    400              &DataSize
    401              );
    402   if (EFI_ERROR (Status)) {
    403     return EFI_INVALID_PARAMETER;
    404   }
    405 
    406   //
    407   // We need to parse the rest buffer after last node.
    408   //
    409   *Buffer = (UINT8 *)((UINTN)Data + DataSize);
    410 
    411   //
    412   // We need skip PkgLength if no Option
    413   //
    414   if (DataType == EFI_ACPI_DATA_TYPE_OPCODE) {
    415     *Buffer += AmlGetPkgLength (*Buffer, &DataSize);
    416   }
    417   return EFI_SUCCESS;
    418 }
    419 
    420 /**
    421   Retrieve information according to AmlHandle
    422 
    423   @param[in]    AmlHandle            AML handle.
    424   @param[in]    Index                Index of the data to retrieve from the object. In general, indexes read from left-to-right
    425                                      in the ACPI encoding, with index 0 always being the ACPI opcode.
    426   @param[out]   DataType             Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists
    427                                      for the specified index.
    428   @param[out]   Data                 Upon return, points to the pointer to the data.
    429   @param[out]   DataSize             Upon return, points to the size of Data.
    430 
    431   @retval       EFI_SUCCESS           Success.
    432   @retval       EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object.
    433 **/
    434 EFI_STATUS
    435 AmlParseOptionHandleCommon (
    436   IN EFI_AML_HANDLE      *AmlHandle,
    437   IN AML_OP_PARSE_INDEX  Index,
    438   OUT EFI_ACPI_DATA_TYPE *DataType,
    439   OUT VOID               **Data,
    440   OUT UINTN              *DataSize
    441   )
    442 {
    443   return AmlParseOptionCommon (
    444            AmlHandle->AmlByteEncoding,
    445            AmlHandle->Buffer,
    446            AmlHandle->Size,
    447            Index,
    448            DataType,
    449            Data,
    450            DataSize
    451            );
    452 }
    453