]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlFieldListParser.c
c25ee22dc7c4b22b1448e11cf9bbd4e5e77c4316
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / Parser / AmlFieldListParser.c
1 /** @file
2 AML Field List Parser.
3
4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 #include <Parser/AmlFieldListParser.h>
10
11 #include <AmlCoreInterface.h>
12 #include <AmlDbgPrint/AmlDbgPrint.h>
13 #include <Parser/AmlMethodParser.h>
14 #include <Parser/AmlParser.h>
15 #include <Tree/AmlNode.h>
16 #include <Tree/AmlTree.h>
17
18 /** Parse a field element.
19
20 The field elements this function can parse are one of:
21 - ReservedField;
22 - AccessField;
23 - ConnectField;
24 - ExtendedAccessField.
25 Indeed, the NamedField field element doesn't have an OpCode. Thus it needs
26 to be parsed differently.
27
28 @param [in] FieldByteEncoding Field byte encoding to parse.
29 @param [in, out] FieldNode Field node to attach the field
30 element to.
31 Must have the AML_HAS_FIELD_LIST
32 attribute.
33 @param [in, out] FStream Forward stream pointing to a field
34 element not being a named field.
35 The stream must not be at its end.
36 @param [in, out] NameSpaceRefList List of namespace reference nodes,
37 allowing to associate an absolute
38 path to a node in the tree.
39
40 @retval EFI_SUCCESS The function completed successfully.
41 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
42 @retval EFI_INVALID_PARAMETER Invalid parameter.
43 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
44 */
45 STATIC
46 EFI_STATUS
47 EFIAPI
48 AmlParseFieldElement (
49 IN CONST AML_BYTE_ENCODING * FieldByteEncoding,
50 IN OUT AML_OBJECT_NODE * FieldNode,
51 IN OUT AML_STREAM * FStream,
52 IN OUT LIST_ENTRY * NameSpaceRefList
53 )
54 {
55 EFI_STATUS Status;
56
57 UINT8 * CurrPos;
58 AML_OBJECT_NODE * NewNode;
59
60 UINT32 PkgLenOffset;
61 UINT32 PkgLenSize;
62
63 // Check whether the node is an Object Node and has a field list.
64 // The byte encoding must be a field element.
65 if ((FieldByteEncoding == NULL) ||
66 ((FieldByteEncoding->Attribute & AML_IS_FIELD_ELEMENT) == 0) ||
67 ((FieldByteEncoding->Attribute & AML_IS_PSEUDO_OPCODE) ==
68 AML_IS_PSEUDO_OPCODE) ||
69 !AmlNodeHasAttribute (FieldNode, AML_HAS_FIELD_LIST) ||
70 !IS_STREAM (FStream) ||
71 IS_END_OF_STREAM (FStream) ||
72 !IS_STREAM_FORWARD (FStream) ||
73 (NameSpaceRefList == NULL)) {
74 ASSERT (0);
75 return EFI_INVALID_PARAMETER;
76 }
77
78 CurrPos = AmlStreamGetCurrPos (FStream);
79 if (CurrPos == NULL) {
80 ASSERT (0);
81 return EFI_INVALID_PARAMETER;
82 }
83
84 // Skip the field opcode (1 byte) as it is already in the FieldByteEncoding.
85 DumpRaw (CurrPos, 1);
86 Status = AmlStreamProgress (FStream, 1);
87 if (EFI_ERROR (Status)) {
88 ASSERT (0);
89 return Status;
90 }
91
92 CurrPos = AmlStreamGetCurrPos (FStream);
93 if (CurrPos == NULL) {
94 ASSERT (0);
95 return EFI_INVALID_PARAMETER;
96 }
97
98 // Parse the PkgLen if available.
99 PkgLenSize = 0;
100 if ((FieldByteEncoding->Attribute & AML_HAS_PKG_LENGTH) ==
101 AML_HAS_PKG_LENGTH) {
102 PkgLenOffset = AmlGetPkgLength (CurrPos, &PkgLenSize);
103 if (PkgLenOffset == 0) {
104 ASSERT (0);
105 return EFI_INVALID_PARAMETER;
106 }
107
108 // Move stream forward as the PkgLen has been read.
109 DumpRaw (CurrPos, PkgLenOffset);
110 Status = AmlStreamProgress (FStream, PkgLenOffset);
111 if (EFI_ERROR (Status)) {
112 ASSERT (0);
113 return Status;
114 }
115
116 // Update the current position as PkgLen has been parsed.
117 CurrPos = AmlStreamGetCurrPos (FStream);
118 }
119
120 Status = AmlCreateObjectNode (
121 FieldByteEncoding,
122 PkgLenSize,
123 &NewNode
124 );
125 if (EFI_ERROR (Status)) {
126 ASSERT (0);
127 return Status;
128 }
129
130 // Add the FieldElement to the Variable Argument List.
131 Status = AmlVarListAddTailInternal (
132 (AML_NODE_HEADER*)FieldNode,
133 (AML_NODE_HEADER*)NewNode
134 );
135 if (EFI_ERROR (Status)) {
136 ASSERT (0);
137 // Delete the sub-tree if the insertion failed.
138 // Otherwise its reference will be lost.
139 AmlDeleteTree ((AML_NODE_HEADER*)NewNode);
140 return Status;
141 }
142
143 // Some field elements do not have fixed arguments.
144 if (!IS_END_OF_STREAM (FStream)) {
145 // Parse the fixed arguments of the field element.
146 Status = AmlParseFixedArguments (
147 NewNode,
148 FStream,
149 NameSpaceRefList
150 );
151 if (EFI_ERROR (Status)) {
152 ASSERT (0);
153 }
154 }
155
156 return Status;
157 }
158
159 /** Parse a named field element.
160
161 Indeed, the NamedField field element doesn't have an OpCode. Thus it needs
162 to be parsed differently. NamedField field element start with a char.
163
164 @param [in] NamedFieldByteEncoding Field byte encoding to parse.
165 @param [in, out] FieldNode Field node to attach the field
166 element to.
167 Must have the AML_HAS_FIELD_LIST
168 attribute.
169 @param [in, out] FStream Forward stream pointing to a named
170 field element.
171 The stream must not be at its end.
172 @param [in, out] NameSpaceRefList List of namespace reference nodes,
173 allowing to associate an absolute
174 path to a node in the tree.
175
176 @retval EFI_SUCCESS The function completed successfully.
177 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
178 @retval EFI_INVALID_PARAMETER Invalid parameter.
179 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
180 */
181 STATIC
182 EFI_STATUS
183 EFIAPI
184 AmlParseNamedFieldElement (
185 IN CONST AML_BYTE_ENCODING * NamedFieldByteEncoding,
186 IN OUT AML_OBJECT_NODE * FieldNode,
187 IN OUT AML_STREAM * FStream,
188 IN OUT LIST_ENTRY * NameSpaceRefList
189 )
190 {
191 EFI_STATUS Status;
192 AML_OBJECT_NODE * NewNode;
193
194 // Check whether the node is an Object Node and has a field list.
195 // The byte encoding must be a char.
196 if ((NamedFieldByteEncoding == NULL) ||
197 ((NamedFieldByteEncoding->Attribute & AML_IS_NAME_CHAR) == 0) ||
198 !AmlNodeHasAttribute (FieldNode, AML_HAS_FIELD_LIST) ||
199 !IS_STREAM (FStream) ||
200 IS_END_OF_STREAM (FStream) ||
201 !IS_STREAM_FORWARD (FStream) ||
202 (NameSpaceRefList == NULL)) {
203 ASSERT (0);
204 return EFI_INVALID_PARAMETER;
205 }
206
207 // Create a NamedField node.
208 Status = AmlCreateObjectNode (
209 AmlGetFieldEncodingByOpCode (AML_FIELD_NAMED_OP, 0),
210 0,
211 &NewNode
212 );
213 if (EFI_ERROR (Status)) {
214 ASSERT (0);
215 return Status;
216 }
217
218 // Add the NamedField node to the variable argument list.
219 Status = AmlVarListAddTailInternal (
220 (AML_NODE_HEADER*)FieldNode,
221 (AML_NODE_HEADER*)NewNode
222 );
223 if (EFI_ERROR (Status)) {
224 ASSERT (0);
225 // Delete the sub-tree if the insertion failed.
226 // Otherwise its reference will be lost.
227 AmlDeleteTree ((AML_NODE_HEADER*)NewNode);
228 return Status;
229 }
230
231 // Parse the fixed arguments: [0]NameSeg, [1]PkgLen.
232 Status = AmlParseFixedArguments (
233 NewNode,
234 FStream,
235 NameSpaceRefList
236 );
237 if (EFI_ERROR (Status)) {
238 ASSERT (0);
239 return Status;
240 }
241
242 // Add the NamedField to the namespace reference list.
243 Status = AmlAddNameSpaceReference (
244 NewNode,
245 NameSpaceRefList
246 );
247 ASSERT_EFI_ERROR (Status);
248
249 return Status;
250 }
251
252 /** Parse the FieldList contained in the stream.
253
254 Create an object node for each field element parsed in the field list
255 available in the Stream, and add them to the variable list of arguments
256 of the FieldNode.
257
258 Nodes that can have a field list are referred as field nodes. They have the
259 AML_HAS_FIELD_LIST attribute.
260
261 According to the ACPI 6.3 specification, s20.2.5.2 "Named Objects Encoding",
262 field elements can be:
263 - NamedField := NameSeg PkgLength;
264 - ReservedField := 0x00 PkgLength;
265 - AccessField := 0x01 AccessType AccessAttrib;
266 - ConnectField := <0x02 NameString> | <0x02 BufferData>;
267 - ExtendedAccessField := 0x03 AccessType ExtendedAccessAttrib AccessLength.
268
269 A small set of opcodes describes the field elements. They are referred as
270 field opcodes. An AML_BYTE_ENCODING table has been created for field OpCodes.
271 Field elements:
272 - don't have a SubOpCode;
273 - have at most 3 fixed arguments (as opposed to 6 for standard AML objects);
274 - don't have a variable list of arguments;
275 - only the NamedField field element is part of the AML namespace.
276
277 ConnectField's BufferData is a buffer node containing a single
278 resource data element.
279 NamedField field elements don't have an AML OpCode. NameSeg starts with a
280 Char type and can thus be differentiated from the Opcodes for other fields.
281 A pseudo OpCode has been created to simplify the parser.
282
283 The branch created from parsing a field node is as:
284 (FieldNode)
285 \
286 |- [FixedArg[0]][FixedArg[1]] # Fixed Arguments
287 |- {(FieldElement[0])->(FieldElement[1])->...)} # Variable Arguments
288
289 With FieldElement[n] being one of NamedField, ReservedField, AccessField,
290 ConnectField, ExtendedAccessField.
291
292 @param [in] FieldNode Field node.
293 Must have the AML_HAS_FIELD_LIST
294 attribute.
295 @param [in] FStream Forward stream pointing to a field list.
296 The stream must not be at its end.
297 @param [in] NameSpaceRefList List of namespace reference nodes,
298 allowing to associate an absolute
299 path to a node in the tree.
300
301 @retval EFI_SUCCESS The function completed successfully.
302 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
303 @retval EFI_INVALID_PARAMETER Invalid parameter.
304 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
305 **/
306 EFI_STATUS
307 EFIAPI
308 AmlParseFieldList (
309 IN AML_OBJECT_NODE * FieldNode,
310 IN AML_STREAM * FStream,
311 IN LIST_ENTRY * NameSpaceRefList
312 )
313 {
314 EFI_STATUS Status;
315
316 UINT8 * CurrPos;
317 CONST AML_BYTE_ENCODING * FieldByteEncoding;
318 CONST AML_BYTE_ENCODING * NamedFieldByteEncoding;
319
320 // Check whether the node is an Object Node and has a field list.
321 if (!AmlNodeHasAttribute (FieldNode, AML_HAS_FIELD_LIST) ||
322 !IS_STREAM (FStream) ||
323 IS_END_OF_STREAM (FStream) ||
324 !IS_STREAM_FORWARD (FStream) ||
325 (NameSpaceRefList == NULL)) {
326 ASSERT (0);
327 return EFI_INVALID_PARAMETER;
328 }
329
330 // Iterate through the field elements, creating nodes
331 // and adding them to the variable list of elements of Node.
332 while (!IS_END_OF_STREAM (FStream)) {
333 CurrPos = AmlStreamGetCurrPos (FStream);
334
335 // Check for a field opcode.
336 FieldByteEncoding = AmlGetFieldEncoding (CurrPos);
337 if (FieldByteEncoding != NULL) {
338 Status = AmlParseFieldElement (
339 FieldByteEncoding,
340 FieldNode,
341 FStream,
342 NameSpaceRefList
343 );
344 if (EFI_ERROR (Status)) {
345 ASSERT (0);
346 return Status;
347 }
348 } else {
349 // Handle the case of Pseudo OpCodes.
350 // NamedField has a Pseudo OpCode and starts with a NameChar. Therefore,
351 // call AmlGetByteEncoding() to check that the encoding is NameChar.
352 NamedFieldByteEncoding = AmlGetByteEncoding (CurrPos);
353 if ((NamedFieldByteEncoding != NULL) &&
354 (NamedFieldByteEncoding->Attribute & AML_IS_NAME_CHAR)) {
355 // This is a NamedField field element since it is starting with a char.
356 Status = AmlParseNamedFieldElement (
357 NamedFieldByteEncoding,
358 FieldNode,
359 FStream,
360 NameSpaceRefList
361 );
362 if (EFI_ERROR (Status)) {
363 ASSERT (0);
364 return Status;
365 }
366 } else {
367 // A field opcode or an AML byte encoding is expected.
368 ASSERT (0);
369 return EFI_INVALID_PARAMETER;
370 }
371 }
372 } // while
373
374 return EFI_SUCCESS;
375 }