]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlResourceDataParser.c
DynamicTablesPkg: AmlLib fix ECC errors
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / Parser / AmlResourceDataParser.c
1 /** @file
2 AML Resource Data Parser.
3
4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 @par Glossary:
9 - Rd or RD - Resource Data
10 - Rds or RDS - Resource Data Small
11 - Rdl or RDL - Resource Data Large
12 **/
13
14 #include <Parser/AmlResourceDataParser.h>
15
16 #include <AmlCoreInterface.h>
17 #include <AmlDbgPrint/AmlDbgPrint.h>
18 #include <Tree/AmlNode.h>
19 #include <Tree/AmlTree.h>
20
21 /** Get the size of a resource data element using a stream.
22
23 If the resource data element is of the large type, the Header
24 is expected to be at least 3 bytes long.
25
26 The use of a stream makes this function safer
27 than the version without stream.
28
29 @param [in] FStream Forward stream pointing to a resource data
30 element.
31 The stream must not be at its end.
32
33 @return The size of the resource data element.
34 Zero if error.
35 **/
36 UINT32
37 EFIAPI
38 AmlRdStreamGetRdSize (
39 IN CONST AML_STREAM * FStream
40 )
41 {
42 CONST AML_RD_HEADER * CurrRdElement;
43
44 if (!IS_STREAM (FStream) ||
45 IS_END_OF_STREAM (FStream) ||
46 !IS_STREAM_FORWARD (FStream)) {
47 ASSERT (0);
48 return 0;
49 }
50
51 CurrRdElement = (CONST AML_RD_HEADER*)AmlStreamGetCurrPos (FStream);
52 if (CurrRdElement == NULL) {
53 ASSERT (0);
54 return 0;
55 }
56
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))) {
61 return 0;
62 }
63
64 return AmlRdGetSize (CurrRdElement);
65 }
66
67 /** Check the nesting of resource data elements that are dependent
68 function descriptors.
69
70 @param [in] FStream Forward stream pointing to a resource data
71 element. The stream is not
72 modified/progressing.
73 The stream must not be at its end.
74 @param [in, out] InFunctionDesc Pointer holding the nesting of the
75 resource data buffer.
76 InFunctionDesc holds TRUE if the resource
77 data at the address of Buffer is currently
78 in a dependent function descriptor list.
79
80 @retval FALSE The Header being parsed is ending a function descriptor
81 list when none started. This should not be possible for a
82 resource data buffer.
83 @retval TRUE Otherwise.
84 **/
85 STATIC
86 BOOLEAN
87 EFIAPI
88 AmlRdCheckFunctionDescNesting (
89 IN CONST AML_STREAM * FStream,
90 IN OUT BOOLEAN * InFunctionDesc
91 )
92 {
93 CONST AML_RD_HEADER * CurrRdElement;
94
95 if (!IS_STREAM (FStream) ||
96 IS_END_OF_STREAM (FStream) ||
97 (InFunctionDesc == NULL)) {
98 ASSERT (0);
99 return FALSE;
100 }
101
102 CurrRdElement = AmlStreamGetCurrPos (FStream);
103 if (CurrRdElement == NULL) {
104 ASSERT (0);
105 return FALSE;
106 }
107
108 // Starting a dependent function descriptor.
109 // It is possible to start one when one has already started.
110 if (AmlRdCompareDescId (
111 CurrRdElement,
112 AML_RD_BUILD_SMALL_DESC_ID (
113 ACPI_SMALL_START_DEPENDENT_DESCRIPTOR_NAME))) {
114 *InFunctionDesc = TRUE;
115 return TRUE;
116 }
117
118 // Ending a dependent function descriptor.
119 if (AmlRdCompareDescId (
120 CurrRdElement,
121 AML_RD_BUILD_SMALL_DESC_ID (
122 ACPI_SMALL_END_DEPENDENT_DESCRIPTOR_NAME))) {
123 if (*InFunctionDesc) {
124 *InFunctionDesc = FALSE;
125 return TRUE;
126 }
127
128 // It should not be possible to end a dependent function descriptor
129 // when none started.
130 return FALSE;
131 }
132
133 return TRUE;
134 }
135
136 /** Check whether the input stream is pointing to a valid list
137 of resource data elements.
138
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.
142
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
145 a FieldList.
146
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.
151
152 @retval TRUE The buffer is holding a valid list of resource data elements.
153 @retval FALSE Otherwise.
154 **/
155 BOOLEAN
156 EFIAPI
157 AmlRdIsResourceDataBuffer (
158 IN CONST AML_STREAM * FStream
159 )
160 {
161 EFI_STATUS Status;
162 UINT32 FreeSpace;
163 AML_STREAM SubStream;
164 CONST AML_RD_HEADER * CurrRdElement;
165 UINT32 CurrRdElementSize;
166 BOOLEAN InFunctionDesc;
167
168 if (!IS_STREAM (FStream) ||
169 IS_END_OF_STREAM (FStream) ||
170 !IS_STREAM_FORWARD (FStream)) {
171 ASSERT (0);
172 return FALSE;
173 }
174
175 // Create a sub-stream from the input stream to leave it untouched.
176 Status = AmlStreamInitSubStream (FStream, &SubStream);
177 if (EFI_ERROR (Status)) {
178 ASSERT (0);
179 return FALSE;
180 }
181
182 CurrRdElement = AmlStreamGetCurrPos (&SubStream);
183 if (CurrRdElement == NULL) {
184 ASSERT (0);
185 return FALSE;
186 }
187
188 // The first element cannot be an end tag.
189 if (AmlRdCompareDescId (
190 CurrRdElement,
191 AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {
192 return FALSE;
193 }
194
195 InFunctionDesc = FALSE;
196 while (TRUE) {
197 FreeSpace = AmlStreamGetFreeSpace (&SubStream);
198 CurrRdElement = AmlStreamGetCurrPos (&SubStream);
199 CurrRdElementSize = AmlRdStreamGetRdSize (&SubStream);
200 if ((FreeSpace == 0) ||
201 (CurrRdElement == NULL) ||
202 (CurrRdElementSize == 0)) {
203 return FALSE;
204 }
205
206 if (!AmlRdCheckFunctionDescNesting (&SubStream, &InFunctionDesc)) {
207 return FALSE;
208 }
209
210 if (CurrRdElementSize > FreeSpace) {
211 return FALSE;
212 } else if (CurrRdElementSize == FreeSpace) {
213 return TRUE;
214 }
215
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 (
220 CurrRdElement,
221 AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {
222 return FALSE;
223 }
224
225 Status = AmlStreamProgress (&SubStream, CurrRdElementSize);
226 if (EFI_ERROR (Status)) {
227 ASSERT (0);
228 return FALSE;
229 }
230 } // while
231
232 return FALSE;
233 }
234
235 /** Parse a ResourceDataBuffer.
236
237 For each resource data element, create a data node
238 and add them to the variable list of arguments of the BufferNode.
239
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.
242
243 @param [in] BufferNode Buffer node.
244 @param [in] FStream Forward stream pointing to a resource data
245 element.
246 The stream must not be at its end.
247
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.
251 **/
252 EFI_STATUS
253 EFIAPI
254 AmlParseResourceData (
255 IN AML_OBJECT_NODE * BufferNode,
256 IN AML_STREAM * FStream
257 )
258 {
259 EFI_STATUS Status;
260 AML_DATA_NODE * NewNode;
261 UINT32 FreeSpace;
262 CONST AML_RD_HEADER * CurrRdElement;
263 UINT32 CurrRdElementSize;
264
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)) {
270 ASSERT (0);
271 return EFI_INVALID_PARAMETER;
272 }
273
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.
277 while (TRUE) {
278 FreeSpace = AmlStreamGetFreeSpace (FStream);
279 if (FreeSpace == 0) {
280 break;
281 }
282
283 CurrRdElement = (CONST AML_RD_HEADER*)AmlStreamGetCurrPos (FStream);
284 CurrRdElementSize = AmlRdStreamGetRdSize (FStream);
285
286 Status = AmlCreateDataNode (
287 EAmlNodeDataTypeResourceData,
288 (CONST UINT8*)CurrRdElement,
289 CurrRdElementSize,
290 &NewNode
291 );
292 if (EFI_ERROR (Status)) {
293 ASSERT (0);
294 return Status;
295 }
296
297 Status = AmlVarListAddTailInternal (
298 (AML_NODE_HEADER*)BufferNode,
299 (AML_NODE_HEADER*)NewNode
300 );
301 if (EFI_ERROR (Status)) {
302 ASSERT (0);
303 AmlDeleteTree ((AML_NODE_HEADER*)NewNode);
304 return Status;
305 }
306
307 Status = AmlStreamProgress (FStream, CurrRdElementSize);
308 if (EFI_ERROR (Status)) {
309 ASSERT (0);
310 return Status;
311 }
312
313 DumpRaw (CurrRdElement, CurrRdElementSize);
314
315 // Exit the loop when finding the resource data end tag.
316 if (AmlRdCompareDescId (
317 CurrRdElement,
318 AML_RD_BUILD_SMALL_DESC_ID (ACPI_SMALL_END_TAG_DESCRIPTOR_NAME))) {
319 if (FreeSpace != CurrRdElementSize) {
320 ASSERT (0);
321 return EFI_INVALID_PARAMETER;
322 }
323 break;
324 }
325 } // while
326
327 return EFI_SUCCESS;
328 }