| /** @file | |
| AML Parser. | |
| Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Parser/AmlParser.h> | |
| #include <AmlCoreInterface.h> | |
| #include <AmlDbgPrint/AmlDbgPrint.h> | |
| #include <Parser/AmlFieldListParser.h> | |
| #include <Parser/AmlMethodParser.h> | |
| #include <Parser/AmlResourceDataParser.h> | |
| #include <String/AmlString.h> | |
| #include <Tree/AmlNode.h> | |
| #include <Tree/AmlTree.h> | |
| /* | |
| AML Tree | |
| -------- | |
| Each ASL Statement is represented in AML as and ObjectNode. | |
| Each ObjectNode has an Opcode and has up to six FixedArguments | |
| followed by a list of VariableArguments. | |
| (ObjectNode) | |
| \ | |
| |- [0][1][2][3][4][5] # Fixed Arguments | |
| |- {(VarArg1)->(VarArg2)->(VarArg3)->...N} # Variable Arguments | |
| A RootNode is a special type of Object Node that does not have an | |
| Opcode or Fixed Arguments. It only has a list of VariableArguments | |
| (RootNode) | |
| \ | |
| |- {(VarArg1)->(VarArg2)->(VarArg3)->...N} # Variable Arguments | |
| A DataNode consists of a data buffer. | |
| A FixedArgument or VariableArgument can be either an ObjectNode or | |
| a DataNode. | |
| Example: | |
| ASL code sample: | |
| Device (DEV0) { | |
| Name (VAR0, 0x6) | |
| } | |
| Tree generated from the ASL code: | |
| (RootNode) | |
| \ | |
| |- {(Device statement (ObjectNode))} # Variable Arg of the | |
| \ # RootNode | |
| | | |
| |- [0] - Device Name (DataNode)(="DEV0") # Fixed Arg0 of the | |
| | # Device() statement | |
| | | |
| |- {(Name statement (ObjectNode))} # Variable Arg of the | |
| \ # Device() statement | |
| | | |
| |- [0] - Name statement(DataNode)(="VAR0") # Fixed Arg0 of the | |
| | # Name() statement | |
| |- [1] - Value(DataNode)(=0x6) # Fixed Arg1 of the | |
| # Name() statement | |
| */ | |
| // Forward declaration. | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseStream ( | |
| IN AML_NODE_HEADER *Node, | |
| IN OUT AML_STREAM *FStream, | |
| IN OUT LIST_ENTRY *NameSpaceRefList | |
| ); | |
| /** Function pointer to parse an AML construct. | |
| The expected format of the AML construct is passed in the | |
| ExpectedFormat argument. The available formats are available in | |
| the AML_PARSE_FORMAT enum definition. | |
| An object node or a data node is created in the function, | |
| and returned through the OutNode parameter. This node should | |
| be attached after this function returns. | |
| @param [in] ParentNode Parent node to which the parsed | |
| AML construct will be attached. | |
| @param [in] ExpectedFormat Format of the AML construct to parse. | |
| @param [in, out] FStream Forward stream containing the AML bytecode | |
| to parse. | |
| The stream must not be at its end. | |
| @param [out] OutNode Pointer holding the node created from the | |
| parsed AML bytecode. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| typedef | |
| EFI_STATUS | |
| (EFIAPI *AML_PARSE_FUNCTION)( | |
| IN CONST AML_NODE_HEADER *Node, | |
| IN AML_PARSE_FORMAT ExpectedFormat, | |
| IN OUT AML_STREAM *FStream, | |
| OUT AML_NODE_HEADER **OutNode | |
| ); | |
| /** Parse a UInt<X> (where X=8, 16, 32 or 64). | |
| A data node is created and returned through the OutNode parameter. | |
| @param [in] ParentNode Parent node to which the parsed | |
| AML construct will be attached. | |
| @param [in] ExpectedFormat Format of the AML construct to parse. | |
| @param [in, out] FStream Forward stream containing the AML bytecode | |
| to parse. | |
| The stream must not be at its end. | |
| @param [out] OutNode Pointer holding the node created from the | |
| parsed AML bytecode. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseUIntX ( | |
| IN CONST AML_NODE_HEADER *ParentNode, | |
| IN AML_PARSE_FORMAT ExpectedFormat, | |
| IN OUT AML_STREAM *FStream, | |
| OUT AML_NODE_HEADER **OutNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT32 UIntXSize; | |
| if ((!IS_AML_ROOT_NODE (ParentNode) && | |
| !IS_AML_OBJECT_NODE (ParentNode)) || | |
| ((ExpectedFormat != EAmlUInt8) && | |
| (ExpectedFormat != EAmlUInt16) && | |
| (ExpectedFormat != EAmlUInt32) && | |
| (ExpectedFormat != EAmlUInt64)) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (OutNode == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| switch (ExpectedFormat) { | |
| case EAmlUInt8: | |
| UIntXSize = 1; | |
| break; | |
| case EAmlUInt16: | |
| UIntXSize = 2; | |
| break; | |
| case EAmlUInt32: | |
| UIntXSize = 4; | |
| break; | |
| case EAmlUInt64: | |
| UIntXSize = 8; | |
| break; | |
| default: | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = AmlCreateDataNode ( | |
| AmlTypeToNodeDataType (ExpectedFormat), | |
| AmlStreamGetCurrPos (FStream), | |
| UIntXSize, | |
| (AML_DATA_NODE **)OutNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream), UIntXSize); | |
| // Move stream forward by the size of UIntX. | |
| Status = AmlStreamProgress (FStream, UIntXSize); | |
| if (EFI_ERROR (Status)) { | |
| AmlDeleteTree (*OutNode); | |
| ASSERT (0); | |
| } | |
| return Status; | |
| } | |
| /** Parse an AML NameString. | |
| A data node is created and returned through the OutNode parameter. | |
| @param [in] ParentNode Parent node to which the parsed | |
| AML construct will be attached. | |
| @param [in] ExpectedFormat Format of the AML construct to parse. | |
| @param [in, out] FStream Forward stream containing the AML bytecode | |
| to parse. | |
| The stream must not be at its end. | |
| @param [out] OutNode Pointer holding the node created from the | |
| parsed AML bytecode. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseNameString ( | |
| IN CONST AML_NODE_HEADER *ParentNode, | |
| IN AML_PARSE_FORMAT ExpectedFormat, | |
| IN OUT AML_STREAM *FStream, | |
| OUT AML_NODE_HEADER **OutNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| CONST UINT8 *Buffer; | |
| CONST AML_BYTE_ENCODING *ByteEncoding; | |
| UINT32 StrSize; | |
| if ((!IS_AML_ROOT_NODE (ParentNode) && | |
| !IS_AML_OBJECT_NODE (ParentNode)) || | |
| (ExpectedFormat != EAmlName) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (OutNode == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream); | |
| ByteEncoding = AmlGetByteEncoding (Buffer); | |
| if ((ByteEncoding == NULL) || | |
| ((ByteEncoding->Attribute & AML_IS_NAME_CHAR) == 0)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Parse the NameString. | |
| Status = AmlGetNameStringSize ((CONST CHAR8 *)Buffer, &StrSize); | |
| if ((EFI_ERROR (Status)) || | |
| (StrSize > AmlStreamGetFreeSpace (FStream))) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeNameString, | |
| Buffer, | |
| StrSize, | |
| (AML_DATA_NODE **)OutNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream), StrSize); | |
| // Move the stream forward by StrSize. | |
| Status = AmlStreamProgress (FStream, StrSize); | |
| if (EFI_ERROR (Status)) { | |
| AmlDeleteTree (*OutNode); | |
| ASSERT (0); | |
| } | |
| return Status; | |
| } | |
| /** Parse an AML String. | |
| A data node is created and returned through the OutNode parameter. | |
| @param [in] ParentNode Parent node to which the parsed | |
| AML construct will be attached. | |
| @param [in] ExpectedFormat Format of the AML construct to parse. | |
| @param [in, out] FStream Forward stream containing the AML bytecode | |
| to parse. | |
| The stream must not be at its end. | |
| @param [out] OutNode Pointer holding the node created from the | |
| parsed AML bytecode. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseString ( | |
| IN CONST AML_NODE_HEADER *ParentNode, | |
| IN AML_PARSE_FORMAT ExpectedFormat, | |
| IN OUT AML_STREAM *FStream, | |
| OUT AML_NODE_HEADER **OutNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT32 StrSize; | |
| UINT8 Byte; | |
| CONST UINT8 *Buffer; | |
| if ((!IS_AML_ROOT_NODE (ParentNode) && | |
| !IS_AML_OBJECT_NODE (ParentNode)) || | |
| (ExpectedFormat != EAmlString) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (OutNode == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream); | |
| StrSize = 0; | |
| // AML String is NULL terminated. | |
| do { | |
| // Reading the stream moves the stream forward as well. | |
| Status = AmlStreamReadByte (FStream, &Byte); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| StrSize++; | |
| } while (Byte != '\0'); | |
| AMLDBG_DUMP_RAW (Buffer, StrSize); | |
| Status = AmlCreateDataNode ( | |
| AmlTypeToNodeDataType (ExpectedFormat), | |
| Buffer, | |
| StrSize, | |
| (AML_DATA_NODE **)OutNode | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| /** Parse an AML object. | |
| An object can be resolved as an AML object with an OpCode, | |
| or a NameString. An object node or a data node is created | |
| and returned through the OutNode parameter. | |
| @param [in] ParentNode Parent node to which the parsed | |
| AML construct will be attached. | |
| @param [in] ExpectedFormat Format of the AML construct to parse. | |
| @param [in, out] FStream Forward stream containing the AML bytecode | |
| to parse. | |
| The stream must not be at its end. | |
| @param [out] OutNode Pointer holding the node created from the | |
| parsed AML bytecode. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseObject ( | |
| IN CONST AML_NODE_HEADER *ParentNode, | |
| IN AML_PARSE_FORMAT ExpectedFormat, | |
| IN OUT AML_STREAM *FStream, | |
| OUT AML_NODE_HEADER **OutNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT8 OpCodeSize; | |
| UINT32 PkgLength; | |
| UINT32 PkgOffset; | |
| UINT32 FreeSpace; | |
| CONST AML_BYTE_ENCODING *AmlByteEncoding; | |
| CONST UINT8 *Buffer; | |
| if ((!IS_AML_ROOT_NODE (ParentNode) && | |
| !IS_AML_OBJECT_NODE (ParentNode)) || | |
| (ExpectedFormat != EAmlObject) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (OutNode == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| PkgLength = 0; | |
| // 0. Get the AML Byte encoding. | |
| AmlByteEncoding = AmlGetByteEncoding (AmlStreamGetCurrPos (FStream)); | |
| if (AmlByteEncoding == NULL) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // 1. Check for NameString. | |
| // Indeed a NameString can be found when an AML object is expected. | |
| // e.g. VAR0 = 3 // VAR0 is assigned an object which is a UINT. | |
| // VAR1 = VAR2 // VAR2 is a NameString. | |
| // If this is a NameString, return. A NameString can be a variable, a | |
| // method invocation, etc. | |
| if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) { | |
| Status = AmlParseNameString ( | |
| ParentNode, | |
| EAmlName, | |
| FStream, | |
| OutNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| } | |
| return Status; | |
| } | |
| // 2. Determine the OpCode size to move the stream forward. | |
| Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream); | |
| if (*Buffer == AML_EXT_OP) { | |
| OpCodeSize = 2; | |
| } else { | |
| OpCodeSize = 1; | |
| } | |
| Status = AmlStreamProgress (FStream, OpCodeSize); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Print the opcode. | |
| AMLDBG_DUMP_RAW (Buffer, OpCodeSize); | |
| if (!IS_END_OF_STREAM (FStream)) { | |
| // 3. Parse the PkgLength field, if present. | |
| if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) { | |
| Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream); | |
| PkgOffset = AmlGetPkgLength (Buffer, &PkgLength); | |
| if (PkgOffset == 0) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Print the package length. | |
| AMLDBG_DUMP_RAW (Buffer, PkgOffset); | |
| // Adjust the size of the stream if it is valid package length. | |
| FreeSpace = AmlStreamGetFreeSpace (FStream); | |
| if (FreeSpace > PkgLength) { | |
| // Reduce the stream size by (FreeSpace - PkgLength) bytes. | |
| AmlStreamReduceMaxBufferSize (FStream, FreeSpace - PkgLength); | |
| } else if (FreeSpace != PkgLength) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = AmlStreamProgress (FStream, PkgOffset); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| } | |
| } else if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) { | |
| // The stream terminated unexpectedly. A PkgLen had to be parsed. | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // 4. Create an Object Node. | |
| Status = AmlCreateObjectNode ( | |
| AmlByteEncoding, | |
| PkgLength, | |
| (AML_OBJECT_NODE **)OutNode | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| /** Parse a FieldPkgLen. | |
| A FieldPkgLen can only be found in a field list, i.e. in a NamedField field | |
| element. The PkgLen is otherwise part of the object node structure. | |
| A data node is created and returned through the OutNode parameter. | |
| @param [in] ParentNode Parent node to which the parsed | |
| AML construct will be attached. | |
| @param [in] ExpectedFormat Format of the AML construct to parse. | |
| @param [in, out] FStream Forward stream containing the AML bytecode | |
| to parse. | |
| The stream must not be at its end. | |
| @param [out] OutNode Pointer holding the node created from the | |
| parsed AML bytecode. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseFieldPkgLen ( | |
| IN CONST AML_NODE_HEADER *ParentNode, | |
| IN AML_PARSE_FORMAT ExpectedFormat, | |
| IN OUT AML_STREAM *FStream, | |
| OUT AML_NODE_HEADER **OutNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS Status1; | |
| CONST UINT8 *Buffer; | |
| UINT32 PkgOffset; | |
| UINT32 PkgLength; | |
| if (!AmlNodeHasAttribute ( | |
| (CONST AML_OBJECT_NODE *)ParentNode, | |
| AML_IS_FIELD_ELEMENT | |
| ) || | |
| (ExpectedFormat != EAmlFieldPkgLen) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (OutNode == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream); | |
| PkgOffset = AmlGetPkgLength (Buffer, &PkgLength); | |
| if (PkgOffset == 0) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Warning: Since, updating of field elements is not supported, store the | |
| // FieldPkgLength in a Data Node as a raw buffer. | |
| Status = AmlCreateDataNode ( | |
| AmlTypeToNodeDataType (ExpectedFormat), | |
| Buffer, | |
| PkgOffset, | |
| (AML_DATA_NODE **)OutNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| AMLDBG_DUMP_RAW (Buffer, PkgOffset); | |
| Status = AmlStreamProgress (FStream, PkgOffset); | |
| if (EFI_ERROR (Status)) { | |
| Status1 = AmlDeleteNode (*OutNode); | |
| ASSERT_EFI_ERROR (Status1); | |
| ASSERT (0); | |
| } | |
| return Status; | |
| } | |
| /** Array of functions pointers to parse the AML constructs. | |
| The AML Byte encoding tables in Aml.c describe the format of the AML | |
| statements. The AML_PARSE_FORMAT enum definition lists these constructs | |
| and the corresponding parsing functions. | |
| */ | |
| AML_PARSE_FUNCTION mParseType[EAmlParseFormatMax] = { | |
| NULL, // EAmlNone | |
| AmlParseUIntX, // EAmlUInt8 | |
| AmlParseUIntX, // EAmlUInt16 | |
| AmlParseUIntX, // EAmlUInt32 | |
| AmlParseUIntX, // EAmlUInt64 | |
| AmlParseObject, // EAmlObject | |
| AmlParseNameString, // EAmlName | |
| AmlParseString, // EAmlString | |
| AmlParseFieldPkgLen // EAmlFieldPkgLen | |
| }; | |
| /** Check whether the NameString stored in the data node is a method invocation. | |
| If so, create a method invocation node and return it. | |
| @param [in] ParentNode Node to which the parsed AML construct | |
| will be attached. | |
| @param [in] DataNode Data node containing a NameString, | |
| potentially being a method invocation. | |
| @param [in, out] NameSpaceRefList List of namespace reference nodes. | |
| @param [out] OutNode Pointer holding the method invocation | |
| node if the NameString contained in the | |
| data node is a method invocation. | |
| NULL otherwise. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlCheckAndParseMethodInvoc ( | |
| IN CONST AML_NODE_HEADER *ParentNode, | |
| IN AML_DATA_NODE *DataNode, | |
| IN OUT LIST_ENTRY *NameSpaceRefList, | |
| OUT AML_OBJECT_NODE **OutNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_NAMESPACE_REF_NODE *NameSpaceRefNode; | |
| AML_OBJECT_NODE *MethodInvocationNode; | |
| AML_STREAM FStream; | |
| if ((!IS_AML_ROOT_NODE (ParentNode) && | |
| !IS_AML_OBJECT_NODE (ParentNode)) || | |
| !IS_AML_DATA_NODE (DataNode) || | |
| (DataNode->DataType != EAmlNodeDataTypeNameString) || | |
| (NameSpaceRefList == NULL) || | |
| (OutNode == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Initialize a stream containing the NameString which is checked. | |
| Status = AmlStreamInit ( | |
| &FStream, | |
| DataNode->Buffer, | |
| DataNode->Size, | |
| EAmlStreamDirectionForward | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Check whether the NameString is a method invocation. | |
| NameSpaceRefNode = NULL; | |
| Status = AmlIsMethodInvocation ( | |
| ParentNode, | |
| &FStream, | |
| NameSpaceRefList, | |
| &NameSpaceRefNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| MethodInvocationNode = NULL; | |
| if (NameSpaceRefNode != NULL) { | |
| // A matching method definition has been found. | |
| // Create a method invocation node. | |
| Status = AmlCreateMethodInvocationNode ( | |
| NameSpaceRefNode, | |
| (AML_DATA_NODE *)DataNode, | |
| &MethodInvocationNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| } | |
| *OutNode = MethodInvocationNode; | |
| return EFI_SUCCESS; | |
| } | |
| /** Call the appropriate function to parse the AML construct in the stream. | |
| The ExpectedFormat parameter allows to choose the right parsing function. | |
| An object node or a data node is created according to format. | |
| @param [in] ParentNode Node to which the parsed AML construct | |
| will be attached. | |
| @param [in] ExpectedFormat Format of the AML construct to parse. | |
| @param [in, out] FStream Forward stream containing the AML | |
| bytecode to parse. | |
| The stream must not be at its end. | |
| @param [in, out] NameSpaceRefList List of namespace reference nodes. | |
| @param [out] OutNode Pointer holding the node created from the | |
| parsed AML bytecode. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseArgument ( | |
| IN CONST AML_NODE_HEADER *ParentNode, | |
| IN AML_PARSE_FORMAT ExpectedFormat, | |
| IN OUT AML_STREAM *FStream, | |
| IN OUT LIST_ENTRY *NameSpaceRefList, | |
| OUT AML_NODE_HEADER **OutNode | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_PARSE_FUNCTION ParsingFunction; | |
| AML_DATA_NODE *DataNode; | |
| AML_OBJECT_NODE *MethodInvocationNode; | |
| if ((!IS_AML_ROOT_NODE (ParentNode) && | |
| !IS_AML_OBJECT_NODE (ParentNode)) || | |
| (ExpectedFormat >= EAmlParseFormatMax) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (NameSpaceRefList == NULL) || | |
| (OutNode == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| ParsingFunction = mParseType[ExpectedFormat]; | |
| if (ParsingFunction == NULL) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Note: The ParsingFunction moves the stream forward as it | |
| // consumes the AML bytecode | |
| Status = ParsingFunction ( | |
| ParentNode, | |
| ExpectedFormat, | |
| FStream, | |
| OutNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Check whether the parsed argument is a NameString when an object | |
| // is expected. In such case, it could be a method invocation. | |
| DataNode = (AML_DATA_NODE *)*OutNode; | |
| if (IS_AML_DATA_NODE (DataNode) && | |
| (DataNode->DataType == EAmlNodeDataTypeNameString) && | |
| (ExpectedFormat == EAmlObject)) | |
| { | |
| Status = AmlCheckAndParseMethodInvoc ( | |
| ParentNode, | |
| (AML_DATA_NODE *)*OutNode, | |
| NameSpaceRefList, | |
| &MethodInvocationNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // A method invocation node has been created and the DataNode containing | |
| // the NameString has been attached to the MethodInvocationNode. | |
| // Replace the OutNode with the MethodInvocationNode. | |
| if (MethodInvocationNode != NULL) { | |
| *OutNode = (AML_NODE_HEADER *)MethodInvocationNode; | |
| } | |
| } | |
| return Status; | |
| } | |
| /** Parse the Bytelist in the stream. | |
| According to the content of the stream, create data node(s) | |
| and add them to the variable list of arguments. | |
| The byte list may be a list of resource data element or a simple byte list. | |
| @param [in] BufferNode Object node having a byte list. | |
| @param [in, out] FStream Forward stream containing the AML bytecode | |
| to parse. | |
| The stream must not be at its end. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseByteList ( | |
| IN AML_OBJECT_NODE *BufferNode, | |
| IN OUT AML_STREAM *FStream | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_NODE_HEADER *NewNode; | |
| CONST UINT8 *Buffer; | |
| UINT32 BufferSize; | |
| // Check whether the node is an Object Node and has byte list. | |
| if (!AmlNodeHasAttribute (BufferNode, AML_HAS_BYTE_LIST) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // The buffer contains a list of resource data elements. | |
| if (AmlRdIsResourceDataBuffer (FStream)) { | |
| // Parse the resource data elements and add them as data nodes. | |
| // AmlParseResourceData() moves the stream forward. | |
| Status = AmlParseResourceData (BufferNode, FStream); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| } | |
| } else { | |
| // The buffer doesn't contain a list of resource data elements. | |
| // Create a single node holding the whole buffer data. | |
| // CreateDataNode checks the Buffer and BufferSize values. | |
| Buffer = (CONST UINT8 *)AmlStreamGetCurrPos (FStream); | |
| BufferSize = AmlStreamGetFreeSpace (FStream); | |
| Status = AmlCreateDataNode ( | |
| EAmlNodeDataTypeRaw, | |
| Buffer, | |
| BufferSize, | |
| (AML_DATA_NODE **)&NewNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| Status = AmlVarListAddTailInternal ( | |
| (AML_NODE_HEADER *)BufferNode, | |
| NewNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| AmlDeleteTree (NewNode); | |
| return Status; | |
| } | |
| AMLDBG_DUMP_RAW (Buffer, BufferSize); | |
| // Move the stream forward as we have consumed the Buffer. | |
| Status = AmlStreamProgress (FStream, BufferSize); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** Parse the list of fixed arguments of the input ObjectNode. | |
| For each argument, create a node and add it to the fixed argument list | |
| of the Node. | |
| If a fixed argument has children, parse them. | |
| @param [in] ObjectNode Object node to parse the fixed arguments | |
| from. | |
| @param [in] FStream Forward stream containing the AML | |
| bytecode to parse. | |
| The stream must not be at its end. | |
| @param [in] NameSpaceRefList List of namespace reference nodes. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseFixedArguments ( | |
| IN AML_OBJECT_NODE *ObjectNode, | |
| IN AML_STREAM *FStream, | |
| IN LIST_ENTRY *NameSpaceRefList | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| AML_NODE_HEADER *FixedArgNode; | |
| AML_STREAM FixedArgFStream; | |
| EAML_PARSE_INDEX TermIndex; | |
| EAML_PARSE_INDEX MaxIndex; | |
| CONST AML_PARSE_FORMAT *Format; | |
| // Fixed arguments of method invocations node are handled differently. | |
| if (!IS_AML_OBJECT_NODE (ObjectNode) || | |
| AmlNodeCompareOpCode (ObjectNode, AML_METHOD_INVOC_OP, 0) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (NameSpaceRefList == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| TermIndex = EAmlParseIndexTerm0; | |
| MaxIndex = (EAML_PARSE_INDEX)AmlGetFixedArgumentCount ( | |
| (AML_OBJECT_NODE *)ObjectNode | |
| ); | |
| if ((ObjectNode->AmlByteEncoding != NULL) && | |
| (ObjectNode->AmlByteEncoding->Format != NULL)) | |
| { | |
| Format = ObjectNode->AmlByteEncoding->Format; | |
| } else { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // Parse all the FixedArgs. | |
| while ((TermIndex < MaxIndex) && | |
| !IS_END_OF_STREAM (FStream) && | |
| (Format[TermIndex] != EAmlNone)) | |
| { | |
| // Initialize a FixedArgStream to parse the current fixed argument. | |
| Status = AmlStreamInitSubStream (FStream, &FixedArgFStream); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Parse the current fixed argument. | |
| Status = AmlParseArgument ( | |
| (CONST AML_NODE_HEADER *)ObjectNode, | |
| Format[TermIndex], | |
| &FixedArgFStream, | |
| NameSpaceRefList, | |
| &FixedArgNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Add the fixed argument to the parent node's fixed argument list. | |
| // FixedArgNode can be an object or data node. | |
| Status = AmlSetFixedArgument ( | |
| (AML_OBJECT_NODE *)ObjectNode, | |
| TermIndex, | |
| FixedArgNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| // Delete the sub-tree if the insertion failed. | |
| // Otherwise its reference will be lost. | |
| // Use DeleteTree because if the argument was a method invocation, | |
| // multiple nodes have been created. | |
| AmlDeleteTree (FixedArgNode); | |
| return Status; | |
| } | |
| // Parse the AML bytecode of the FixedArgNode if this is an object node. | |
| if (IS_AML_OBJECT_NODE (FixedArgNode) && | |
| !IS_END_OF_STREAM (&FixedArgFStream)) | |
| { | |
| Status = AmlParseStream ( | |
| FixedArgNode, | |
| &FixedArgFStream, | |
| NameSpaceRefList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| } | |
| // Move the stream forward as we have consumed the sub-stream. | |
| Status = AmlStreamProgress ( | |
| FStream, | |
| AmlStreamGetIndex (&FixedArgFStream) | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| TermIndex++; | |
| } // while | |
| return EFI_SUCCESS; | |
| } | |
| /** Parse the variable list of arguments of the input ObjectNode. | |
| For each variable argument, create a node and add it to the variable list of | |
| arguments of the Node. | |
| If a variable argument has children, parse them recursively. | |
| The arguments of method invocation nodes are added to the variable list of | |
| arguments of the method invocation node. It is necessary to first get | |
| the number of arguments to parse for this kind of node. A method invocation | |
| can have at most 7 fixed arguments. | |
| @param [in] Node Node to parse the variable arguments | |
| from. | |
| @param [in] FStream Forward stream containing the AML | |
| bytecode to parse. | |
| The stream must not be at its end. | |
| @param [in] NameSpaceRefList List of namespace reference nodes. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseVariableArguments ( | |
| IN AML_NODE_HEADER *Node, | |
| IN AML_STREAM *FStream, | |
| IN LIST_ENTRY *NameSpaceRefList | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| BOOLEAN IsMethodInvocation; | |
| UINT8 MethodInvocationArgCount; | |
| AML_NODE_HEADER *VarArgNode; | |
| AML_STREAM VarArgFStream; | |
| if ((!AmlNodeHasAttribute ( | |
| (CONST AML_OBJECT_NODE *)Node, | |
| AML_HAS_CHILD_OBJ | |
| ) && | |
| !IS_AML_ROOT_NODE (Node)) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (NameSpaceRefList == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = AmlGetMethodInvocationArgCount ( | |
| (CONST AML_OBJECT_NODE *)Node, | |
| &IsMethodInvocation, | |
| &MethodInvocationArgCount | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Parse variable arguments while the Stream is not empty. | |
| while (!IS_END_OF_STREAM (FStream)) { | |
| // If the number of variable arguments are counted, decrement the counter. | |
| if ((IsMethodInvocation) && (MethodInvocationArgCount-- == 0)) { | |
| return EFI_SUCCESS; | |
| } | |
| // Initialize a VarArgStream to parse the current variable argument. | |
| Status = AmlStreamInitSubStream (FStream, &VarArgFStream); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Parse the current variable argument. | |
| Status = AmlParseArgument ( | |
| Node, | |
| EAmlObject, | |
| &VarArgFStream, | |
| NameSpaceRefList, | |
| &VarArgNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| // Add the variable argument to its parent variable list of arguments. | |
| // VarArgNode can be an object or data node. | |
| Status = AmlVarListAddTailInternal ( | |
| (AML_NODE_HEADER *)Node, | |
| VarArgNode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| // Delete the sub-tree if the insertion failed. | |
| // Otherwise its reference will be lost. | |
| // Use DeleteTree because if the argument was a method invocation, | |
| // multiple nodes have been created. | |
| AmlDeleteTree (VarArgNode); | |
| return Status; | |
| } | |
| // Parse the AML bytecode of the VarArgNode if this is an object node. | |
| if (IS_AML_OBJECT_NODE (VarArgNode) && | |
| (!IS_END_OF_STREAM (&VarArgFStream))) | |
| { | |
| Status = AmlParseStream (VarArgNode, &VarArgFStream, NameSpaceRefList); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| } | |
| // Move the stream forward as we have consumed the sub-stream. | |
| Status = AmlStreamProgress ( | |
| FStream, | |
| AmlStreamGetIndex (&VarArgFStream) | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| } // while | |
| // If the number of variable arguments are counted, check all the | |
| // MethodInvocationArgCount have been parsed. | |
| if (IsMethodInvocation && (MethodInvocationArgCount != 0)) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| return Status; | |
| } | |
| /** Parse the AML stream and populate the root node. | |
| @param [in] RootNode RootNode to which the children are | |
| added. | |
| @param [in, out] FStream Forward stream containing the AML | |
| bytecode to parse. | |
| The stream must not be at its end. | |
| @param [in, out] NameSpaceRefList List of namespace reference nodes. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlPopulateRootNode ( | |
| IN AML_ROOT_NODE *RootNode, | |
| IN OUT AML_STREAM *FStream, | |
| IN OUT LIST_ENTRY *NameSpaceRefList | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| if (!IS_AML_ROOT_NODE (RootNode) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (NameSpaceRefList == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // A Root Node only has variable arguments. | |
| Status = AmlParseVariableArguments ( | |
| (AML_NODE_HEADER *)RootNode, | |
| FStream, | |
| NameSpaceRefList | |
| ); | |
| ASSERT_EFI_ERROR (Status); | |
| return Status; | |
| } | |
| /** Parse the AML stream an populate the object node. | |
| @param [in] ObjectNode ObjectNode to which the children are | |
| added. | |
| @param [in, out] FStream Forward stream containing the AML | |
| bytecode to parse. | |
| The stream must not be at its end. | |
| @param [in, out] NameSpaceRefList List of namespace reference nodes. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlPopulateObjectNode ( | |
| IN AML_OBJECT_NODE *ObjectNode, | |
| IN OUT AML_STREAM *FStream, | |
| IN OUT LIST_ENTRY *NameSpaceRefList | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| if (!IS_AML_OBJECT_NODE (ObjectNode) || | |
| !IS_STREAM (FStream) || | |
| IS_END_OF_STREAM (FStream) || | |
| !IS_STREAM_FORWARD (FStream) || | |
| (NameSpaceRefList == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Status = EFI_SUCCESS; | |
| // Don't parse the fixed arguments of method invocation nodes. | |
| // The AML encoding for method invocations in the ACPI specification 6.3 is: | |
| // MethodInvocation := NameString TermArgList | |
| // Since the AML specification does not define an OpCode for method | |
| // invocation, this AML parser defines a pseudo opcode and redefines the | |
| // grammar for simplicity as: | |
| // MethodInvocation := MethodInvocationOp NameString ArgumentCount TermArgList | |
| // ArgumentCount := ByteData | |
| // Due to this difference, the MethodInvocationOp and the fixed argument | |
| // i.e. ArgumentCount is not available in the AML stream and need to be | |
| // handled differently. | |
| if (!AmlNodeCompareOpCode (ObjectNode, AML_METHOD_INVOC_OP, 0)) { | |
| // Parse the fixed list of arguments. | |
| Status = AmlParseFixedArguments ( | |
| ObjectNode, | |
| FStream, | |
| NameSpaceRefList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| } | |
| // Save the association [node reference/pathname] in the NameSpaceRefList. | |
| // This allows to identify method invocations from other namespace | |
| // paths. Method invocation need to be parsed differently. | |
| if (AmlNodeHasAttribute ( | |
| (CONST AML_OBJECT_NODE *)ObjectNode, | |
| AML_IN_NAMESPACE | |
| )) | |
| { | |
| Status = AmlAddNameSpaceReference ( | |
| (CONST AML_OBJECT_NODE *)ObjectNode, | |
| NameSpaceRefList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| } | |
| if (!IS_END_OF_STREAM (FStream)) { | |
| // Parse the variable list of arguments if present. | |
| if (AmlNodeHasAttribute (ObjectNode, AML_HAS_CHILD_OBJ)) { | |
| Status = AmlParseVariableArguments ( | |
| (AML_NODE_HEADER *)ObjectNode, | |
| FStream, | |
| NameSpaceRefList | |
| ); | |
| } else if (AmlNodeHasAttribute (ObjectNode, AML_HAS_BYTE_LIST)) { | |
| // Parse the byte list if present. | |
| Status = AmlParseByteList ( | |
| ObjectNode, | |
| FStream | |
| ); | |
| } else if (AmlNodeHasAttribute (ObjectNode, AML_HAS_FIELD_LIST)) { | |
| // Parse the field list if present. | |
| Status = AmlParseFieldList ( | |
| ObjectNode, | |
| FStream, | |
| NameSpaceRefList | |
| ); | |
| } | |
| // Check status and assert | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| } | |
| } | |
| return Status; | |
| } | |
| /** Invoke the appropriate parsing functions based on the Node type. | |
| @param [in] Node Node from which the children are parsed. | |
| Must be a root node or an object node. | |
| @param [in] FStream Forward stream containing the AML | |
| bytecode to parse. | |
| The stream must not be at its end. | |
| @param [in] NameSpaceRefList List of namespace reference nodes. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseStream ( | |
| IN AML_NODE_HEADER *Node, | |
| IN AML_STREAM *FStream, | |
| IN LIST_ENTRY *NameSpaceRefList | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| if (IS_AML_ROOT_NODE (Node)) { | |
| Status = AmlPopulateRootNode ( | |
| (AML_ROOT_NODE *)Node, | |
| FStream, | |
| NameSpaceRefList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| } | |
| } else if (IS_AML_OBJECT_NODE (Node)) { | |
| Status = AmlPopulateObjectNode ( | |
| (AML_OBJECT_NODE *)Node, | |
| FStream, | |
| NameSpaceRefList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| } | |
| } else { | |
| // Data node or other. | |
| ASSERT (0); | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| return Status; | |
| } | |
| /** Parse the definition block. | |
| This function parses the whole AML blob. It starts with the ACPI DSDT/SSDT | |
| header and then parses the AML bytestream. | |
| A tree structure is returned via the RootPtr. | |
| The tree must be deleted with the AmlDeleteTree function. | |
| @param [in] DefinitionBlock Pointer to the definition block. | |
| @param [out] RootPtr Pointer to the root node of the tree. | |
| @retval EFI_SUCCESS The function completed successfully. | |
| @retval EFI_BUFFER_TOO_SMALL No space left in the buffer. | |
| @retval EFI_INVALID_PARAMETER Invalid parameter. | |
| @retval EFI_OUT_OF_RESOURCES Could not allocate memory. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| AmlParseDefinitionBlock ( | |
| IN CONST EFI_ACPI_DESCRIPTION_HEADER *DefinitionBlock, | |
| OUT AML_ROOT_NODE **RootPtr | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EFI_STATUS Status1; | |
| AML_STREAM Stream; | |
| AML_ROOT_NODE *Root; | |
| LIST_ENTRY NameSpaceRefList; | |
| UINT8 *Buffer; | |
| UINT32 MaxBufferSize; | |
| if ((DefinitionBlock == NULL) || | |
| (RootPtr == NULL)) | |
| { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| Buffer = (UINT8 *)DefinitionBlock + sizeof (EFI_ACPI_DESCRIPTION_HEADER); | |
| if (DefinitionBlock->Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) { | |
| ASSERT (0); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| MaxBufferSize = DefinitionBlock->Length - | |
| (UINT32)sizeof (EFI_ACPI_DESCRIPTION_HEADER); | |
| // Create a root node. | |
| Status = AmlCreateRootNode ( | |
| (EFI_ACPI_DESCRIPTION_HEADER *)DefinitionBlock, | |
| &Root | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| return Status; | |
| } | |
| *RootPtr = Root; | |
| if (MaxBufferSize == 0) { | |
| return EFI_SUCCESS; | |
| } | |
| // Initialize a stream to parse the AML bytecode. | |
| Status = AmlStreamInit ( | |
| &Stream, | |
| Buffer, | |
| MaxBufferSize, | |
| EAmlStreamDirectionForward | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| // Initialize the NameSpaceRefList, holding references to nodes declaring | |
| // a name in the AML namespace. | |
| InitializeListHead (&NameSpaceRefList); | |
| // Parse the whole AML blob. | |
| Status = AmlParseStream ( | |
| (AML_NODE_HEADER *)Root, | |
| &Stream, | |
| &NameSpaceRefList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| ASSERT (0); | |
| goto error_handler; | |
| } | |
| // Check the whole AML blob has been parsed. | |
| if (!IS_END_OF_STREAM (&Stream)) { | |
| ASSERT (0); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto error_handler; | |
| } | |
| // Print the list of NameSpace reference nodes. | |
| // AmlDbgPrintNameSpaceRefList (&NameSpaceRefList); | |
| // Delete the NameSpaceRefList | |
| goto exit_handler; | |
| error_handler: | |
| if (Root != NULL) { | |
| AmlDeleteTree ((AML_NODE_HEADER *)Root); | |
| } | |
| exit_handler: | |
| Status1 = AmlDeleteNameSpaceRefList (&NameSpaceRefList); | |
| if (EFI_ERROR (Status1)) { | |
| ASSERT (0); | |
| if (!EFI_ERROR (Status)) { | |
| return Status1; | |
| } | |
| } | |
| return Status; | |
| } |