| /** @file | |
| ACPI Sdt Protocol Driver | |
| Copyright (c) 2010, Intel Corporation. All rights reserved. <BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "AcpiTable.h" | |
| /** | |
| Retrieve option term according to AmlByteEncoding and Buffer. | |
| @param[in] AmlByteEncoding AML Byte Encoding. | |
| @param[in] Buffer AML buffer. | |
| @param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region. | |
| @param[in] TermIndex Index of the data to retrieve from the object. | |
| @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists | |
| for the specified index. | |
| @param[out] Data Upon return, points to the pointer to the data. | |
| @param[out] DataSize Upon return, points to the size of Data. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| AmlParseOptionTerm ( | |
| IN AML_BYTE_ENCODING *AmlByteEncoding, | |
| IN UINT8 *Buffer, | |
| IN UINTN MaxBufferSize, | |
| IN AML_OP_PARSE_INDEX TermIndex, | |
| OUT EFI_ACPI_DATA_TYPE *DataType, | |
| OUT VOID **Data, | |
| OUT UINTN *DataSize | |
| ) | |
| { | |
| AML_BYTE_ENCODING *ChildAmlByteEncoding; | |
| EFI_STATUS Status; | |
| if (DataType != NULL) { | |
| *DataType = AmlTypeToAcpiType (AmlByteEncoding->Format[TermIndex - 1]); | |
| } | |
| if (Data != NULL) { | |
| *Data = Buffer; | |
| } | |
| // | |
| // Parse term according to AML type | |
| // | |
| switch (AmlByteEncoding->Format[TermIndex - 1]) { | |
| case AML_UINT8: | |
| *DataSize = sizeof(UINT8); | |
| break; | |
| case AML_UINT16: | |
| *DataSize = sizeof(UINT16); | |
| break; | |
| case AML_UINT32: | |
| *DataSize = sizeof(UINT32); | |
| break; | |
| case AML_UINT64: | |
| *DataSize = sizeof(UINT64); | |
| break; | |
| case AML_STRING: | |
| *DataSize = AsciiStrSize((CHAR8 *)Buffer); | |
| break; | |
| case AML_NAME: | |
| Status = AmlGetNameStringSize (Buffer, DataSize); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| break; | |
| case AML_OBJECT: | |
| ChildAmlByteEncoding = AmlSearchByOpByte (Buffer); | |
| if (ChildAmlByteEncoding == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // NOTE: We need override DataType here, if there is a case the AML_OBJECT is AML_NAME. | |
| // We need convert type from EFI_ACPI_DATA_TYPE_CHILD to EFI_ACPI_DATA_TYPE_NAME_STRING. | |
| // We should not return CHILD because there is NO OpCode for NameString. | |
| // | |
| if ((ChildAmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) { | |
| if (DataType != NULL) { | |
| *DataType = AmlTypeToAcpiType (AML_NAME); | |
| } | |
| Status = AmlGetNameStringSize (Buffer, DataSize); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| break; | |
| } | |
| // | |
| // It is real AML_OBJECT | |
| // | |
| *DataSize = AmlGetObjectSize ( | |
| ChildAmlByteEncoding, | |
| Buffer, | |
| MaxBufferSize | |
| ); | |
| if (*DataSize == 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| break; | |
| case AML_NONE: | |
| // | |
| // No term | |
| // | |
| case AML_OPCODE: | |
| default: | |
| ASSERT (FALSE); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (*DataSize > MaxBufferSize) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Retrieve information according to AmlByteEncoding and Buffer. | |
| @param[in] AmlByteEncoding AML Byte Encoding. | |
| @param[in] Buffer AML buffer. | |
| @param[in] MaxBufferSize AML buffer MAX size. The parser can not parse any data exceed this region. | |
| @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right | |
| in the ACPI encoding, with index 0 always being the ACPI opcode. | |
| @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists | |
| for the specified index. | |
| @param[out] Data Upon return, points to the pointer to the data. | |
| @param[out] DataSize Upon return, points to the size of Data. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER Buffer does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| AmlParseOptionCommon ( | |
| IN AML_BYTE_ENCODING *AmlByteEncoding, | |
| IN UINT8 *Buffer, | |
| IN UINTN MaxBufferSize, | |
| IN AML_OP_PARSE_INDEX Index, | |
| OUT EFI_ACPI_DATA_TYPE *DataType, | |
| OUT VOID **Data, | |
| OUT UINTN *DataSize | |
| ) | |
| { | |
| UINT8 *CurrentBuffer; | |
| UINTN PkgLength; | |
| UINTN OpLength; | |
| UINTN PkgOffset; | |
| AML_OP_PARSE_INDEX TermIndex; | |
| EFI_STATUS Status; | |
| ASSERT ((Index <= AmlByteEncoding->MaxIndex) || (Index == AML_OP_PARSE_INDEX_GET_SIZE)); | |
| // | |
| // 0. Check if this is NAME string. | |
| // | |
| if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) { | |
| // | |
| // Only allow GET_SIZE | |
| // | |
| if (Index != AML_OP_PARSE_INDEX_GET_SIZE) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // return NameString size | |
| // | |
| Status = AmlGetNameStringSize (Buffer, DataSize); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (*DataSize > MaxBufferSize) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Not NAME string, start parsing | |
| // | |
| CurrentBuffer = Buffer; | |
| // | |
| // 1. Get OpCode | |
| // | |
| if (Index != AML_OP_PARSE_INDEX_GET_SIZE) { | |
| *DataType = EFI_ACPI_DATA_TYPE_OPCODE; | |
| *Data = (VOID *)CurrentBuffer; | |
| } | |
| if (*CurrentBuffer == AML_EXT_OP) { | |
| OpLength = 2; | |
| } else { | |
| OpLength = 1; | |
| } | |
| *DataSize = OpLength; | |
| if (Index == AML_OP_PARSE_INDEX_GET_OPCODE) { | |
| return EFI_SUCCESS; | |
| } | |
| if (OpLength > MaxBufferSize) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| CurrentBuffer += OpLength; | |
| // | |
| // 2. Skip PkgLength field, if have | |
| // | |
| if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) { | |
| PkgOffset = AmlGetPkgLength(CurrentBuffer, &PkgLength); | |
| // | |
| // Override MaxBufferSize if it is valid PkgLength | |
| // | |
| if (OpLength + PkgLength > MaxBufferSize) { | |
| return EFI_INVALID_PARAMETER; | |
| } else { | |
| MaxBufferSize = OpLength + PkgLength; | |
| } | |
| } else { | |
| PkgOffset = 0; | |
| PkgLength = 0; | |
| } | |
| CurrentBuffer += PkgOffset; | |
| // | |
| // 3. Get Term one by one. | |
| // | |
| TermIndex = AML_OP_PARSE_INDEX_GET_TERM1; | |
| while ((Index >= TermIndex) && (TermIndex <= AmlByteEncoding->MaxIndex) && ((UINTN)CurrentBuffer < (UINTN)Buffer + MaxBufferSize)) { | |
| Status = AmlParseOptionTerm ( | |
| AmlByteEncoding, | |
| CurrentBuffer, | |
| (UINTN)Buffer + MaxBufferSize - (UINTN)CurrentBuffer, | |
| TermIndex, | |
| DataType, | |
| Data, | |
| DataSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (Index == TermIndex) { | |
| // | |
| // Done | |
| // | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| // Parse next one | |
| // | |
| CurrentBuffer += *DataSize; | |
| TermIndex ++; | |
| } | |
| // | |
| // Finish all options, but no option found. | |
| // | |
| if ((UINTN)CurrentBuffer > (UINTN)Buffer + MaxBufferSize) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if ((UINTN)CurrentBuffer == (UINTN)Buffer + MaxBufferSize) { | |
| if (Index != AML_OP_PARSE_INDEX_GET_SIZE) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| } | |
| // | |
| // 4. Finish parsing all node, return size | |
| // | |
| ASSERT (Index == AML_OP_PARSE_INDEX_GET_SIZE); | |
| if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) { | |
| *DataSize = OpLength + PkgLength; | |
| } else { | |
| *DataSize = (UINTN)CurrentBuffer - (UINTN)Buffer; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Return object size. | |
| @param[in] AmlByteEncoding AML Byte Encoding. | |
| @param[in] Buffer AML object buffer. | |
| @param[in] MaxBufferSize AML object buffer MAX size. The parser can not parse any data exceed this region. | |
| @return Size of the object. | |
| **/ | |
| UINTN | |
| AmlGetObjectSize ( | |
| IN AML_BYTE_ENCODING *AmlByteEncoding, | |
| IN UINT8 *Buffer, | |
| IN UINTN MaxBufferSize | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINTN DataSize; | |
| Status = AmlParseOptionCommon ( | |
| AmlByteEncoding, | |
| Buffer, | |
| MaxBufferSize, | |
| AML_OP_PARSE_INDEX_GET_SIZE, | |
| NULL, | |
| NULL, | |
| &DataSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return 0; | |
| } else { | |
| return DataSize; | |
| } | |
| } | |
| /** | |
| Return object name. | |
| @param[in] AmlHandle AML handle. | |
| @return Name of the object. | |
| **/ | |
| CHAR8 * | |
| AmlGetObjectName ( | |
| IN EFI_AML_HANDLE *AmlHandle | |
| ) | |
| { | |
| AML_BYTE_ENCODING *AmlByteEncoding; | |
| VOID *NameString; | |
| UINTN NameSize; | |
| AML_OP_PARSE_INDEX TermIndex; | |
| EFI_STATUS Status; | |
| EFI_ACPI_DATA_TYPE DataType; | |
| AmlByteEncoding = AmlHandle->AmlByteEncoding; | |
| ASSERT ((AmlByteEncoding->Attribute & AML_IN_NAMESPACE) != 0); | |
| // | |
| // Find out Last Name index, according to OpCode table. | |
| // The last name will be the node name by design. | |
| // | |
| TermIndex = AmlByteEncoding->MaxIndex; | |
| for (TermIndex = AmlByteEncoding->MaxIndex; TermIndex > 0; TermIndex--) { | |
| if (AmlByteEncoding->Format[TermIndex - 1] == AML_NAME) { | |
| break; | |
| } | |
| } | |
| ASSERT (TermIndex != 0); | |
| // | |
| // Get Name for this node. | |
| // | |
| Status = AmlParseOptionHandleCommon ( | |
| AmlHandle, | |
| TermIndex, | |
| &DataType, | |
| &NameString, | |
| &NameSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return NULL; | |
| } | |
| ASSERT (DataType == EFI_ACPI_DATA_TYPE_NAME_STRING); | |
| return NameString; | |
| } | |
| /** | |
| Return offset of last option. | |
| @param[in] AmlHandle AML Handle. | |
| @param[out] Buffer Upon return, points to the offset after last option. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| AmlGetOffsetAfterLastOption ( | |
| IN EFI_AML_HANDLE *AmlHandle, | |
| OUT UINT8 **Buffer | |
| ) | |
| { | |
| EFI_ACPI_DATA_TYPE DataType; | |
| VOID *Data; | |
| UINTN DataSize; | |
| EFI_STATUS Status; | |
| Status = AmlParseOptionHandleCommon ( | |
| AmlHandle, | |
| AmlHandle->AmlByteEncoding->MaxIndex, | |
| &DataType, | |
| &Data, | |
| &DataSize | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // We need to parse the rest buffer after last node. | |
| // | |
| *Buffer = (UINT8 *)((UINTN)Data + DataSize); | |
| // | |
| // We need skip PkgLength if no Option | |
| // | |
| if (DataType == EFI_ACPI_DATA_TYPE_OPCODE) { | |
| *Buffer += AmlGetPkgLength (*Buffer, &DataSize); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Retrieve information according to AmlHandle | |
| @param[in] AmlHandle AML handle. | |
| @param[in] Index Index of the data to retrieve from the object. In general, indexes read from left-to-right | |
| in the ACPI encoding, with index 0 always being the ACPI opcode. | |
| @param[out] DataType Points to the returned data type or EFI_ACPI_DATA_TYPE_NONE if no data exists | |
| for the specified index. | |
| @param[out] Data Upon return, points to the pointer to the data. | |
| @param[out] DataSize Upon return, points to the size of Data. | |
| @retval EFI_SUCCESS Success. | |
| @retval EFI_INVALID_PARAMETER AmlHandle does not refer to a valid ACPI object. | |
| **/ | |
| EFI_STATUS | |
| AmlParseOptionHandleCommon ( | |
| IN EFI_AML_HANDLE *AmlHandle, | |
| IN AML_OP_PARSE_INDEX Index, | |
| OUT EFI_ACPI_DATA_TYPE *DataType, | |
| OUT VOID **Data, | |
| OUT UINTN *DataSize | |
| ) | |
| { | |
| return AmlParseOptionCommon ( | |
| AmlHandle->AmlByteEncoding, | |
| AmlHandle->Buffer, | |
| AmlHandle->Size, | |
| Index, | |
| DataType, | |
| Data, | |
| DataSize | |
| ); | |
| } |