4 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include <Parser/AmlFieldListParser.h>
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>
18 /** Parse a field element.
20 The field elements this function can parse are one of:
24 - ExtendedAccessField.
25 Indeed, the NamedField field element doesn't have an OpCode. Thus it needs
26 to be parsed differently.
28 @param [in] FieldByteEncoding Field byte encoding to parse.
29 @param [in, out] FieldNode Field node to attach the field
31 Must have the AML_HAS_FIELD_LIST
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.
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.
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
58 AML_OBJECT_NODE
* NewNode
;
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
)) {
75 return EFI_INVALID_PARAMETER
;
78 CurrPos
= AmlStreamGetCurrPos (FStream
);
79 if (CurrPos
== NULL
) {
81 return EFI_INVALID_PARAMETER
;
84 // Skip the field opcode (1 byte) as it is already in the FieldByteEncoding.
86 Status
= AmlStreamProgress (FStream
, 1);
87 if (EFI_ERROR (Status
)) {
92 CurrPos
= AmlStreamGetCurrPos (FStream
);
93 if (CurrPos
== NULL
) {
95 return EFI_INVALID_PARAMETER
;
98 // Parse the PkgLen if available.
100 if ((FieldByteEncoding
->Attribute
& AML_HAS_PKG_LENGTH
) ==
101 AML_HAS_PKG_LENGTH
) {
102 PkgLenOffset
= AmlGetPkgLength (CurrPos
, &PkgLenSize
);
103 if (PkgLenOffset
== 0) {
105 return EFI_INVALID_PARAMETER
;
108 // Move stream forward as the PkgLen has been read.
109 DumpRaw (CurrPos
, PkgLenOffset
);
110 Status
= AmlStreamProgress (FStream
, PkgLenOffset
);
111 if (EFI_ERROR (Status
)) {
116 // Update the current position as PkgLen has been parsed.
117 CurrPos
= AmlStreamGetCurrPos (FStream
);
120 Status
= AmlCreateObjectNode (
125 if (EFI_ERROR (Status
)) {
130 // Add the FieldElement to the Variable Argument List.
131 Status
= AmlVarListAddTailInternal (
132 (AML_NODE_HEADER
*)FieldNode
,
133 (AML_NODE_HEADER
*)NewNode
135 if (EFI_ERROR (Status
)) {
137 // Delete the sub-tree if the insertion failed.
138 // Otherwise its reference will be lost.
139 AmlDeleteTree ((AML_NODE_HEADER
*)NewNode
);
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 (
151 if (EFI_ERROR (Status
)) {
159 /** Parse a named field element.
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.
164 @param [in] NamedFieldByteEncoding Field byte encoding to parse.
165 @param [in, out] FieldNode Field node to attach the field
167 Must have the AML_HAS_FIELD_LIST
169 @param [in, out] FStream Forward stream pointing to a named
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.
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.
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
192 AML_OBJECT_NODE
* NewNode
;
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
)) {
204 return EFI_INVALID_PARAMETER
;
207 // Create a NamedField node.
208 Status
= AmlCreateObjectNode (
209 AmlGetFieldEncodingByOpCode (AML_FIELD_NAMED_OP
, 0),
213 if (EFI_ERROR (Status
)) {
218 // Add the NamedField node to the variable argument list.
219 Status
= AmlVarListAddTailInternal (
220 (AML_NODE_HEADER
*)FieldNode
,
221 (AML_NODE_HEADER
*)NewNode
223 if (EFI_ERROR (Status
)) {
225 // Delete the sub-tree if the insertion failed.
226 // Otherwise its reference will be lost.
227 AmlDeleteTree ((AML_NODE_HEADER
*)NewNode
);
231 // Parse the fixed arguments: [0]NameSeg, [1]PkgLen.
232 Status
= AmlParseFixedArguments (
237 if (EFI_ERROR (Status
)) {
242 // Add the NamedField to the namespace reference list.
243 Status
= AmlAddNameSpaceReference (
247 ASSERT_EFI_ERROR (Status
);
252 /** Parse the FieldList contained in the stream.
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
258 Nodes that can have a field list are referred as field nodes. They have the
259 AML_HAS_FIELD_LIST attribute.
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.
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.
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.
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.
283 The branch created from parsing a field node is as:
286 |- [FixedArg[0]][FixedArg[1]] # Fixed Arguments
287 |- {(FieldElement[0])->(FieldElement[1])->...)} # Variable Arguments
289 With FieldElement[n] being one of NamedField, ReservedField, AccessField,
290 ConnectField, ExtendedAccessField.
292 @param [in] FieldNode Field node.
293 Must have the AML_HAS_FIELD_LIST
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.
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.
309 IN AML_OBJECT_NODE
* FieldNode
,
310 IN AML_STREAM
* FStream
,
311 IN LIST_ENTRY
* NameSpaceRefList
317 CONST AML_BYTE_ENCODING
* FieldByteEncoding
;
318 CONST AML_BYTE_ENCODING
* NamedFieldByteEncoding
;
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
)) {
327 return EFI_INVALID_PARAMETER
;
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
);
335 // Check for a field opcode.
336 FieldByteEncoding
= AmlGetFieldEncoding (CurrPos
);
337 if (FieldByteEncoding
!= NULL
) {
338 Status
= AmlParseFieldElement (
344 if (EFI_ERROR (Status
)) {
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
,
362 if (EFI_ERROR (Status
)) {
367 // A field opcode or an AML byte encoding is expected.
369 return EFI_INVALID_PARAMETER
;