2 AML Resource Data Parser.
4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 - Rd or RD - Resource Data
10 - Rds or RDS - Resource Data Small
11 - Rdl or RDL - Resource Data Large
14 #include <Parser/AmlResourceDataParser.h>
16 #include <AmlCoreInterface.h>
17 #include <AmlDbgPrint/AmlDbgPrint.h>
18 #include <Tree/AmlNode.h>
19 #include <Tree/AmlTree.h>
21 /** Get the size of a resource data element using a stream.
23 If the resource data element is of the large type, the Header
24 is expected to be at least 3 bytes long.
26 The use of a stream makes this function safer
27 than the version without stream.
29 @param [in] FStream Forward stream pointing to a resource data
31 The stream must not be at its end.
33 @return The size of the resource data element.
38 AmlRdStreamGetRdSize (
39 IN CONST AML_STREAM
* FStream
42 CONST AML_RD_HEADER
* CurrRdElement
;
44 if (!IS_STREAM (FStream
) ||
45 IS_END_OF_STREAM (FStream
) ||
46 !IS_STREAM_FORWARD (FStream
)) {
51 CurrRdElement
= (CONST AML_RD_HEADER
*)AmlStreamGetCurrPos (FStream
);
52 if (CurrRdElement
== NULL
) {
57 // If the resource data element is of the large type, check for overflow.
58 if (AML_RD_IS_LARGE (CurrRdElement
) &&
59 (AmlStreamGetFreeSpace (FStream
) <
60 sizeof (ACPI_LARGE_RESOURCE_HEADER
))) {
64 return AmlRdGetSize (CurrRdElement
);
67 /** Check the nesting of resource data elements that are dependent
70 @param [in] FStream Forward stream pointing to a resource data
71 element. The stream is not
73 The stream must not be at its end.
74 @param [in, out] InFunctionDesc Pointer holding the nesting of the
76 InFunctionDesc holds TRUE if the resource
77 data at the address of Buffer is currently
78 in a dependent function descriptor list.
80 @retval FALSE The Header being parsed is ending a function descriptor
81 list when none started. This should not be possible for a
83 @retval TRUE Otherwise.
88 AmlRdCheckFunctionDescNesting (
89 IN CONST AML_STREAM
* FStream
,
90 IN OUT BOOLEAN
* InFunctionDesc
93 CONST AML_RD_HEADER
* CurrRdElement
;
95 if (!IS_STREAM (FStream
) ||
96 IS_END_OF_STREAM (FStream
) ||
97 (InFunctionDesc
== NULL
)) {
102 CurrRdElement
= AmlStreamGetCurrPos (FStream
);
103 if (CurrRdElement
== NULL
) {
108 // Starting a dependent function descriptor.
109 // It is possible to start one when one has already started.
110 if (AmlRdCompareDescId (
112 AML_RD_BUILD_SMALL_DESC_ID (
113 ACPI_SMALL_START_DEPENDENT_DESCRIPTOR_NAME
))) {
114 *InFunctionDesc
= TRUE
;
118 // Ending a dependent function descriptor.
119 if (AmlRdCompareDescId (
121 AML_RD_BUILD_SMALL_DESC_ID (
122 ACPI_SMALL_END_DEPENDENT_DESCRIPTOR_NAME
))) {
123 if (*InFunctionDesc
) {
124 *InFunctionDesc
= FALSE
;
128 // It should not be possible to end a dependent function descriptor
129 // when none started.
136 /** Check whether the input stream is pointing to a valid list
137 of resource data elements.
139 The check is based on the size of resource data elements.
140 This means that a buffer can pass this check with non-existing descriptor Ids
141 that have a correct size.
143 A list of resource data elements can contain one unique resource data
144 element, without an end tag resource data. This is the case for
147 @param [in] FStream Forward stream ideally pointing to a resource
148 data element. The stream is not
149 modified/progressing.
150 The stream must not be at its end.
152 @retval TRUE The buffer is holding a valid list of resource data elements.
153 @retval FALSE Otherwise.
157 AmlRdIsResourceDataBuffer (
158 IN CONST AML_STREAM
* FStream
163 AML_STREAM SubStream
;
164 CONST AML_RD_HEADER
* CurrRdElement
;
165 UINT32 CurrRdElementSize
;
166 BOOLEAN InFunctionDesc
;
168 if (!IS_STREAM (FStream
) ||
169 IS_END_OF_STREAM (FStream
) ||
170 !IS_STREAM_FORWARD (FStream
)) {
175 // Create a sub-stream from the input stream to leave it untouched.
176 Status
= AmlStreamInitSubStream (FStream
, &SubStream
);
177 if (EFI_ERROR (Status
)) {
182 CurrRdElement
= AmlStreamGetCurrPos (&SubStream
);
183 if (CurrRdElement
== NULL
) {
188 // The first element cannot be an end tag.
189 if (AmlRdCompareDescId (
191 AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME
))) {
195 InFunctionDesc
= FALSE
;
197 FreeSpace
= AmlStreamGetFreeSpace (&SubStream
);
198 CurrRdElement
= AmlStreamGetCurrPos (&SubStream
);
199 CurrRdElementSize
= AmlRdStreamGetRdSize (&SubStream
);
200 if ((FreeSpace
== 0) ||
201 (CurrRdElement
== NULL
) ||
202 (CurrRdElementSize
== 0)) {
206 if (!AmlRdCheckFunctionDescNesting (&SubStream
, &InFunctionDesc
)) {
210 if (CurrRdElementSize
> FreeSpace
) {
212 } else if (CurrRdElementSize
== FreeSpace
) {
216 // @todo Might want to check the CRC when available.
217 // An end tag resource data element must be the last element of the list.
218 // Thus the function should have already returned.
219 if (AmlRdCompareDescId (
221 AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME
))) {
225 Status
= AmlStreamProgress (&SubStream
, CurrRdElementSize
);
226 if (EFI_ERROR (Status
)) {
235 /** Parse a ResourceDataBuffer.
237 For each resource data element, create a data node
238 and add them to the variable list of arguments of the BufferNode.
240 The input stream is expected to point to a valid list of resource data
241 elements. A function is available to check it for the caller.
243 @param [in] BufferNode Buffer node.
244 @param [in] FStream Forward stream pointing to a resource data
246 The stream must not be at its end.
248 @retval EFI_SUCCESS The function completed successfully.
249 @retval EFI_INVALID_PARAMETER Invalid parameter.
250 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
254 AmlParseResourceData (
255 IN AML_OBJECT_NODE
* BufferNode
,
256 IN AML_STREAM
* FStream
260 AML_DATA_NODE
* NewNode
;
262 CONST AML_RD_HEADER
* CurrRdElement
;
263 UINT32 CurrRdElementSize
;
265 // Check that BufferNode is an ObjectNode and has a ByteList.
266 if (!AmlNodeHasAttribute (BufferNode
, AML_HAS_BYTE_LIST
) ||
267 !IS_STREAM (FStream
) ||
268 IS_END_OF_STREAM (FStream
) ||
269 !IS_STREAM_FORWARD (FStream
)) {
271 return EFI_INVALID_PARAMETER
;
274 // Iterate through the resource data elements and create nodes.
275 // We assume the Buffer has already been validated as a list of
276 // resource data elements, so less checks are made.
278 FreeSpace
= AmlStreamGetFreeSpace (FStream
);
279 if (FreeSpace
== 0) {
283 CurrRdElement
= (CONST AML_RD_HEADER
*)AmlStreamGetCurrPos (FStream
);
284 CurrRdElementSize
= AmlRdStreamGetRdSize (FStream
);
286 Status
= AmlCreateDataNode (
287 EAmlNodeDataTypeResourceData
,
288 (CONST UINT8
*)CurrRdElement
,
292 if (EFI_ERROR (Status
)) {
297 Status
= AmlVarListAddTailInternal (
298 (AML_NODE_HEADER
*)BufferNode
,
299 (AML_NODE_HEADER
*)NewNode
301 if (EFI_ERROR (Status
)) {
303 AmlDeleteTree ((AML_NODE_HEADER
*)NewNode
);
307 Status
= AmlStreamProgress (FStream
, CurrRdElementSize
);
308 if (EFI_ERROR (Status
)) {
313 DumpRaw (CurrRdElement
, CurrRdElementSize
);
315 // Exit the loop when finding the resource data end tag.
316 if (AmlRdCompareDescId (
318 AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME
))) {
319 if (FreeSpace
!= CurrRdElementSize
) {
321 return EFI_INVALID_PARAMETER
;