]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/Parser/AmlParser.c
e3b9f249058fee10a14a40a731159cb3c878957c
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / Parser / AmlParser.c
1 /** @file
2 AML 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/AmlParser.h>
10
11 #include <AmlCoreInterface.h>
12 #include <AmlDbgPrint/AmlDbgPrint.h>
13 #include <Parser/AmlFieldListParser.h>
14 #include <Parser/AmlMethodParser.h>
15 #include <Parser/AmlResourceDataParser.h>
16 #include <String/AmlString.h>
17 #include <Tree/AmlNode.h>
18 #include <Tree/AmlTree.h>
19
20 /*
21 AML Tree
22 --------
23
24 Each ASL Statement is represented in AML as and ObjectNode.
25 Each ObjectNode has an Opcode and has up to six FixedArguments
26 followed by a list of VariableArguments.
27 (ObjectNode)
28 \
29 |- [0][1][2][3][4][5] # Fixed Arguments
30 |- {(VarArg1)->(VarArg2)->(VarArg3)->...N} # Variable Arguments
31
32 A RootNode is a special type of Object Node that does not have an
33 Opcode or Fixed Arguments. It only has a list of VariableArguments
34 (RootNode)
35 \
36 |- {(VarArg1)->(VarArg2)->(VarArg3)->...N} # Variable Arguments
37
38 A DataNode consists of a data buffer.
39
40 A FixedArgument or VariableArgument can be either an ObjectNode or
41 a DataNode.
42
43 Example:
44 ASL code sample:
45 Device (DEV0) {
46 Name (VAR0, 0x6)
47 }
48
49 Tree generated from the ASL code:
50 (RootNode)
51 \
52 |- {(Device statement (ObjectNode))} # Variable Arg of the
53 \ # RootNode
54 |
55 |- [0] - Device Name (DataNode)(="DEV0") # Fixed Arg0 of the
56 | # Device() statement
57 |
58 |- {(Name statement (ObjectNode))} # Variable Arg of the
59 \ # Device() statement
60 |
61 |- [0] - Name statement(DataNode)(="VAR0") # Fixed Arg0 of the
62 | # Name() statement
63 |- [1] - Value(DataNode)(=0x6) # Fixed Arg1 of the
64 # Name() statement
65 */
66
67 // Forward declaration.
68 STATIC
69 EFI_STATUS
70 EFIAPI
71 AmlParseStream (
72 IN AML_NODE_HEADER * Node,
73 IN OUT AML_STREAM * FStream,
74 IN OUT LIST_ENTRY * NameSpaceRefList
75 );
76
77 /** Function pointer to parse an AML construct.
78
79 The expected format of the AML construct is passed in the
80 ExpectedFormat argument. The available formats are available in
81 the AML_PARSE_FORMAT enum definition.
82
83 An object node or a data node is created in the function,
84 and returned through the OutNode parameter. This node should
85 be attached after this function returns.
86
87 @param [in] ParentNode Parent node to which the parsed
88 AML construct will be attached.
89 @param [in] ExpectedFormat Format of the AML construct to parse.
90 @param [in, out] FStream Forward stream containing the AML bytecode
91 to parse.
92 The stream must not be at its end.
93 @param [out] OutNode Pointer holding the node created from the
94 parsed AML bytecode.
95
96 @retval EFI_SUCCESS The function completed successfully.
97 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
98 @retval EFI_INVALID_PARAMETER Invalid parameter.
99 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
100 **/
101 typedef
102 EFI_STATUS
103 EFIAPI
104 (*AML_PARSE_FUNCTION) (
105 IN CONST AML_NODE_HEADER * Node,
106 IN AML_PARSE_FORMAT ExpectedFormat,
107 IN OUT AML_STREAM * FStream,
108 OUT AML_NODE_HEADER ** OutNode
109 );
110
111 /** Parse a UInt<X> (where X=8, 16, 32 or 64).
112
113 A data node is created and returned through the OutNode parameter.
114
115 @param [in] ParentNode Parent node to which the parsed
116 AML construct will be attached.
117 @param [in] ExpectedFormat Format of the AML construct to parse.
118 @param [in, out] FStream Forward stream containing the AML bytecode
119 to parse.
120 The stream must not be at its end.
121 @param [out] OutNode Pointer holding the node created from the
122 parsed AML bytecode.
123
124 @retval EFI_SUCCESS The function completed successfully.
125 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
126 @retval EFI_INVALID_PARAMETER Invalid parameter.
127 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
128 **/
129 STATIC
130 EFI_STATUS
131 EFIAPI
132 AmlParseUIntX (
133 IN CONST AML_NODE_HEADER * ParentNode,
134 IN AML_PARSE_FORMAT ExpectedFormat,
135 IN OUT AML_STREAM * FStream,
136 OUT AML_NODE_HEADER ** OutNode
137 )
138 {
139 EFI_STATUS Status;
140 UINT32 UIntXSize;
141
142 if ((!IS_AML_ROOT_NODE (ParentNode) &&
143 !IS_AML_OBJECT_NODE (ParentNode)) ||
144 ((ExpectedFormat != EAmlUInt8) &&
145 (ExpectedFormat != EAmlUInt16) &&
146 (ExpectedFormat != EAmlUInt32) &&
147 (ExpectedFormat != EAmlUInt64)) ||
148 !IS_STREAM (FStream) ||
149 IS_END_OF_STREAM (FStream) ||
150 !IS_STREAM_FORWARD (FStream) ||
151 (OutNode == NULL)) {
152 ASSERT (0);
153 return EFI_INVALID_PARAMETER;
154 }
155
156 switch (ExpectedFormat) {
157 case EAmlUInt8:
158 UIntXSize = 1;
159 break;
160 case EAmlUInt16:
161 UIntXSize = 2;
162 break;
163 case EAmlUInt32:
164 UIntXSize = 4;
165 break;
166 case EAmlUInt64:
167 UIntXSize = 8;
168 break;
169 default:
170 ASSERT (0);
171 return EFI_INVALID_PARAMETER;
172 }
173
174 Status = AmlCreateDataNode (
175 AmlTypeToNodeDataType (ExpectedFormat),
176 AmlStreamGetCurrPos (FStream),
177 UIntXSize,
178 (AML_DATA_NODE**)OutNode
179 );
180 if (EFI_ERROR (Status)) {
181 ASSERT (0);
182 return Status;
183 }
184
185 AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream), UIntXSize);
186
187 // Move stream forward by the size of UIntX.
188 Status = AmlStreamProgress (FStream, UIntXSize);
189 if (EFI_ERROR (Status)) {
190 AmlDeleteTree (*OutNode);
191 ASSERT (0);
192 }
193
194 return Status;
195 }
196
197 /** Parse an AML NameString.
198
199 A data node is created and returned through the OutNode parameter.
200
201 @param [in] ParentNode Parent node to which the parsed
202 AML construct will be attached.
203 @param [in] ExpectedFormat Format of the AML construct to parse.
204 @param [in, out] FStream Forward stream containing the AML bytecode
205 to parse.
206 The stream must not be at its end.
207 @param [out] OutNode Pointer holding the node created from the
208 parsed AML bytecode.
209
210 @retval EFI_SUCCESS The function completed successfully.
211 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
212 @retval EFI_INVALID_PARAMETER Invalid parameter.
213 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
214 **/
215 STATIC
216 EFI_STATUS
217 EFIAPI
218 AmlParseNameString (
219 IN CONST AML_NODE_HEADER * ParentNode,
220 IN AML_PARSE_FORMAT ExpectedFormat,
221 IN OUT AML_STREAM * FStream,
222 OUT AML_NODE_HEADER ** OutNode
223 )
224 {
225 EFI_STATUS Status;
226
227 CONST UINT8 * Buffer;
228 CONST AML_BYTE_ENCODING * ByteEncoding;
229 UINT32 StrSize;
230
231 if ((!IS_AML_ROOT_NODE (ParentNode) &&
232 !IS_AML_OBJECT_NODE (ParentNode)) ||
233 (ExpectedFormat != EAmlName) ||
234 !IS_STREAM (FStream) ||
235 IS_END_OF_STREAM (FStream) ||
236 !IS_STREAM_FORWARD (FStream) ||
237 (OutNode == NULL)) {
238 ASSERT (0);
239 return EFI_INVALID_PARAMETER;
240 }
241
242 Buffer = (CONST UINT8*)AmlStreamGetCurrPos (FStream);
243 ByteEncoding = AmlGetByteEncoding (Buffer);
244 if ((ByteEncoding == NULL) ||
245 ((ByteEncoding->Attribute & AML_IS_NAME_CHAR) == 0)) {
246 ASSERT (0);
247 return EFI_INVALID_PARAMETER;
248 }
249
250 // Parse the NameString.
251 Status = AmlGetNameStringSize ((CONST CHAR8*)Buffer, &StrSize);
252 if ((EFI_ERROR (Status)) ||
253 (StrSize > AmlStreamGetFreeSpace (FStream))) {
254 ASSERT (0);
255 return EFI_INVALID_PARAMETER;
256 }
257
258 Status = AmlCreateDataNode (
259 EAmlNodeDataTypeNameString,
260 Buffer,
261 StrSize,
262 (AML_DATA_NODE**)OutNode
263 );
264 if (EFI_ERROR (Status)) {
265 ASSERT (0);
266 return Status;
267 }
268
269 AMLDBG_DUMP_RAW (AmlStreamGetCurrPos (FStream), StrSize);
270
271 // Move the stream forward by StrSize.
272 Status = AmlStreamProgress (FStream, StrSize);
273 if (EFI_ERROR (Status)) {
274 AmlDeleteTree (*OutNode);
275 ASSERT (0);
276 }
277
278 return Status;
279 }
280
281 /** Parse an AML String.
282
283 A data node is created and returned through the OutNode parameter.
284
285 @param [in] ParentNode Parent node to which the parsed
286 AML construct will be attached.
287 @param [in] ExpectedFormat Format of the AML construct to parse.
288 @param [in, out] FStream Forward stream containing the AML bytecode
289 to parse.
290 The stream must not be at its end.
291 @param [out] OutNode Pointer holding the node created from the
292 parsed AML bytecode.
293
294 @retval EFI_SUCCESS The function completed successfully.
295 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
296 @retval EFI_INVALID_PARAMETER Invalid parameter.
297 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
298 **/
299 STATIC
300 EFI_STATUS
301 EFIAPI
302 AmlParseString (
303 IN CONST AML_NODE_HEADER * ParentNode,
304 IN AML_PARSE_FORMAT ExpectedFormat,
305 IN OUT AML_STREAM * FStream,
306 OUT AML_NODE_HEADER ** OutNode
307 )
308 {
309 EFI_STATUS Status;
310 UINT32 StrSize;
311 UINT8 Byte;
312 CONST UINT8 * Buffer;
313
314 if ((!IS_AML_ROOT_NODE (ParentNode) &&
315 !IS_AML_OBJECT_NODE (ParentNode)) ||
316 (ExpectedFormat != EAmlString) ||
317 !IS_STREAM (FStream) ||
318 IS_END_OF_STREAM (FStream) ||
319 !IS_STREAM_FORWARD (FStream) ||
320 (OutNode == NULL)) {
321 ASSERT (0);
322 return EFI_INVALID_PARAMETER;
323 }
324
325 Buffer = (CONST UINT8*)AmlStreamGetCurrPos (FStream);
326 StrSize = 0;
327 // AML String is NULL terminated.
328 do {
329 // Reading the stream moves the stream forward aswell.
330 Status = AmlStreamReadByte (FStream, &Byte);
331 if (EFI_ERROR (Status)) {
332 ASSERT (0);
333 return Status;
334 }
335 StrSize++;
336 } while (Byte != '\0');
337
338 AMLDBG_DUMP_RAW (Buffer, StrSize);
339
340 Status = AmlCreateDataNode (
341 AmlTypeToNodeDataType (ExpectedFormat),
342 Buffer,
343 StrSize,
344 (AML_DATA_NODE**)OutNode
345 );
346 ASSERT_EFI_ERROR (Status);
347
348 return Status;
349 }
350
351 /** Parse an AML object.
352
353 An object can be resolved as an AML object with an OpCode,
354 or a NameString. An object node or a data node is created
355 and returned through the OutNode parameter.
356
357 @param [in] ParentNode Parent node to which the parsed
358 AML construct will be attached.
359 @param [in] ExpectedFormat Format of the AML construct to parse.
360 @param [in, out] FStream Forward stream containing the AML bytecode
361 to parse.
362 The stream must not be at its end.
363 @param [out] OutNode Pointer holding the node created from the
364 parsed AML bytecode.
365
366 @retval EFI_SUCCESS The function completed successfully.
367 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
368 @retval EFI_INVALID_PARAMETER Invalid parameter.
369 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
370 **/
371 STATIC
372 EFI_STATUS
373 EFIAPI
374 AmlParseObject (
375 IN CONST AML_NODE_HEADER * ParentNode,
376 IN AML_PARSE_FORMAT ExpectedFormat,
377 IN OUT AML_STREAM * FStream,
378 OUT AML_NODE_HEADER ** OutNode
379 )
380 {
381 EFI_STATUS Status;
382
383 UINT8 OpCodeSize;
384 UINT32 PkgLength;
385 UINT32 PkgOffset;
386 UINT32 FreeSpace;
387
388 CONST AML_BYTE_ENCODING * AmlByteEncoding;
389 CONST UINT8 * Buffer;
390
391 if ((!IS_AML_ROOT_NODE (ParentNode) &&
392 !IS_AML_OBJECT_NODE (ParentNode)) ||
393 (ExpectedFormat != EAmlObject) ||
394 !IS_STREAM (FStream) ||
395 IS_END_OF_STREAM (FStream) ||
396 !IS_STREAM_FORWARD (FStream) ||
397 (OutNode == NULL)) {
398 ASSERT (0);
399 return EFI_INVALID_PARAMETER;
400 }
401
402 PkgLength = 0;
403
404 // 0. Get the AML Byte encoding.
405 AmlByteEncoding = AmlGetByteEncoding (AmlStreamGetCurrPos (FStream));
406 if (AmlByteEncoding == NULL) {
407 ASSERT (0);
408 return EFI_INVALID_PARAMETER;
409 }
410
411 // 1. Check for NameString.
412 // Indeed a NameString can be found when an AML object is expected.
413 // e.g. VAR0 = 3 // VAR0 is assigned an object which is a UINT.
414 // VAR1 = VAR2 // VAR2 is a NameString.
415 // If this is a NameString, return. A NameString can be a variable, a
416 // method invocation, etc.
417 if ((AmlByteEncoding->Attribute & AML_IS_NAME_CHAR) != 0) {
418 Status = AmlParseNameString (
419 ParentNode,
420 EAmlName,
421 FStream,
422 OutNode
423 );
424 if (EFI_ERROR (Status)) {
425 ASSERT (0);
426 }
427 return Status;
428 }
429
430 // 2. Determine the OpCode size to move the stream forward.
431 Buffer = (CONST UINT8*)AmlStreamGetCurrPos (FStream);
432 if (*Buffer == AML_EXT_OP) {
433 OpCodeSize = 2;
434 } else {
435 OpCodeSize = 1;
436 }
437 Status = AmlStreamProgress (FStream, OpCodeSize);
438 if (EFI_ERROR (Status)) {
439 ASSERT (0);
440 return Status;
441 }
442
443 // Print the opcode.
444 AMLDBG_DUMP_RAW (Buffer, OpCodeSize);
445
446 if (!IS_END_OF_STREAM (FStream)) {
447 // 3. Parse the PkgLength field, if present.
448 if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
449 Buffer = (CONST UINT8*)AmlStreamGetCurrPos (FStream);
450 PkgOffset = AmlGetPkgLength (Buffer, &PkgLength);
451 if (PkgOffset == 0) {
452 ASSERT (0);
453 return EFI_INVALID_PARAMETER;
454 }
455
456 // Print the package length.
457 AMLDBG_DUMP_RAW (Buffer, PkgOffset);
458
459 // Adjust the size of the stream if it is valid package length.
460 FreeSpace = AmlStreamGetFreeSpace (FStream);
461 if (FreeSpace > PkgLength) {
462 // Reduce the stream size by (FreeSpace - PkgLength) bytes.
463 AmlStreamReduceMaxBufferSize (FStream, FreeSpace - PkgLength);
464 } else if (FreeSpace != PkgLength) {
465 ASSERT (0);
466 return EFI_INVALID_PARAMETER;
467 }
468
469 Status = AmlStreamProgress (FStream, PkgOffset);
470 if (EFI_ERROR (Status)) {
471 ASSERT (0);
472 return Status;
473 }
474 }
475 } else if ((AmlByteEncoding->Attribute & AML_HAS_PKG_LENGTH) != 0) {
476 // The stream terminated unexpectedly. A PkgLen had to be parsed.
477 ASSERT (0);
478 return EFI_INVALID_PARAMETER;
479 }
480
481 // 4. Create an Object Node.
482 Status = AmlCreateObjectNode (
483 AmlByteEncoding,
484 PkgLength,
485 (AML_OBJECT_NODE**)OutNode
486 );
487 ASSERT_EFI_ERROR (Status);
488
489 return Status;
490 }
491
492 /** Parse a FieldPkgLen.
493
494 A FieldPkgLen can only be found in a field list, i.e. in a NamedField field
495 element. The PkgLen is otherwise part of the object node structure.
496 A data node is created and returned through the OutNode parameter.
497
498 @param [in] ParentNode Parent node to which the parsed
499 AML construct will be attached.
500 @param [in] ExpectedFormat Format of the AML construct to parse.
501 @param [in, out] FStream Forward stream containing the AML bytecode
502 to parse.
503 The stream must not be at its end.
504 @param [out] OutNode Pointer holding the node created from the
505 parsed AML bytecode.
506
507 @retval EFI_SUCCESS The function completed successfully.
508 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
509 @retval EFI_INVALID_PARAMETER Invalid parameter.
510 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
511 **/
512 STATIC
513 EFI_STATUS
514 EFIAPI
515 AmlParseFieldPkgLen (
516 IN CONST AML_NODE_HEADER * ParentNode,
517 IN AML_PARSE_FORMAT ExpectedFormat,
518 IN OUT AML_STREAM * FStream,
519 OUT AML_NODE_HEADER ** OutNode
520 )
521 {
522 EFI_STATUS Status;
523 EFI_STATUS Status1;
524 CONST UINT8 * Buffer;
525 UINT32 PkgOffset;
526 UINT32 PkgLength;
527
528 if (!AmlNodeHasAttribute (
529 (CONST AML_OBJECT_NODE*)ParentNode,
530 AML_IS_FIELD_ELEMENT
531 ) ||
532 (ExpectedFormat != EAmlFieldPkgLen) ||
533 !IS_STREAM (FStream) ||
534 IS_END_OF_STREAM (FStream) ||
535 !IS_STREAM_FORWARD (FStream) ||
536 (OutNode == NULL)) {
537 ASSERT (0);
538 return EFI_INVALID_PARAMETER;
539 }
540
541 Buffer = (CONST UINT8*)AmlStreamGetCurrPos (FStream);
542
543 PkgOffset = AmlGetPkgLength (Buffer, &PkgLength);
544 if (PkgOffset == 0) {
545 ASSERT (0);
546 return EFI_INVALID_PARAMETER;
547 }
548
549 // Warning: Since, updating of field elements is not supported, store the
550 // FieldPkgLength in a Data Node as a raw buffer.
551 Status = AmlCreateDataNode (
552 AmlTypeToNodeDataType (ExpectedFormat),
553 Buffer,
554 PkgOffset,
555 (AML_DATA_NODE**)OutNode
556 );
557 if (EFI_ERROR (Status)) {
558 ASSERT (0);
559 return Status;
560 }
561
562 AMLDBG_DUMP_RAW (Buffer, PkgOffset);
563
564 Status = AmlStreamProgress (FStream, PkgOffset);
565 if (EFI_ERROR (Status)) {
566 Status1 = AmlDeleteNode (*OutNode);
567 ASSERT_EFI_ERROR (Status1);
568 ASSERT (0);
569 }
570
571 return Status;
572 }
573
574 /** Array of functions pointers to parse the AML constructs.
575
576 The AML Byte encoding tables in Aml.c describe the format of the AML
577 statements. The AML_PARSE_FORMAT enum definition lists these constructs
578 and the corresponding parsing functions.
579 */
580 AML_PARSE_FUNCTION mParseType[EAmlParseFormatMax] = {
581 NULL, // EAmlNone
582 AmlParseUIntX, // EAmlUInt8
583 AmlParseUIntX, // EAmlUInt16
584 AmlParseUIntX, // EAmlUInt32
585 AmlParseUIntX, // EAmlUInt64
586 AmlParseObject, // EAmlObject
587 AmlParseNameString, // EAmlName
588 AmlParseString, // EAmlString
589 AmlParseFieldPkgLen // EAmlFieldPkgLen
590 };
591
592 /** Check whether the NameString stored in the data node is a method invocation.
593 If so, create a method invocation node and return it.
594
595 @param [in] ParentNode Node to which the parsed AML construct
596 will be attached.
597 @param [in] DataNode Data node containing a NameString,
598 potentially being a method invocation.
599 @param [in, out] NameSpaceRefList List of namespace reference nodes.
600 @param [out] OutNode Pointer holding the method invocation
601 node if the NameString contained in the
602 data node is a method invocation.
603 NULL otherwise.
604
605 @retval EFI_SUCCESS The function completed successfully.
606 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
607 @retval EFI_INVALID_PARAMETER Invalid parameter.
608 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
609 **/
610 STATIC
611 EFI_STATUS
612 EFIAPI
613 AmlCheckAndParseMethodInvoc (
614 IN CONST AML_NODE_HEADER * ParentNode,
615 IN AML_DATA_NODE * DataNode,
616 IN OUT LIST_ENTRY * NameSpaceRefList,
617 OUT AML_OBJECT_NODE ** OutNode
618 )
619 {
620 EFI_STATUS Status;
621 AML_NAMESPACE_REF_NODE * NameSpaceRefNode;
622 AML_OBJECT_NODE * MethodInvocationNode;
623 AML_STREAM FStream;
624
625 if ((!IS_AML_ROOT_NODE (ParentNode) &&
626 !IS_AML_OBJECT_NODE (ParentNode)) ||
627 !IS_AML_DATA_NODE (DataNode) ||
628 (DataNode->DataType != EAmlNodeDataTypeNameString) ||
629 (NameSpaceRefList == NULL) ||
630 (OutNode == NULL)) {
631 ASSERT (0);
632 return EFI_INVALID_PARAMETER;
633 }
634
635 // Initialize a stream containing the NameString which is checked.
636 Status = AmlStreamInit (
637 &FStream,
638 DataNode->Buffer,
639 DataNode->Size,
640 EAmlStreamDirectionForward
641 );
642 if (EFI_ERROR (Status)) {
643 ASSERT (0);
644 return Status;
645 }
646
647 // Check whether the NameString is a method invocation.
648 NameSpaceRefNode = NULL;
649 Status = AmlIsMethodInvocation (
650 ParentNode,
651 &FStream,
652 NameSpaceRefList,
653 &NameSpaceRefNode
654 );
655 if (EFI_ERROR (Status)) {
656 ASSERT (0);
657 return Status;
658 }
659
660 MethodInvocationNode = NULL;
661 if (NameSpaceRefNode != NULL) {
662 // A matching method definition has been found.
663 // Create a method invocation node.
664 Status = AmlCreateMethodInvocationNode (
665 NameSpaceRefNode,
666 (AML_DATA_NODE*)DataNode,
667 &MethodInvocationNode
668 );
669 if (EFI_ERROR (Status)) {
670 ASSERT (0);
671 return Status;
672 }
673 }
674
675 *OutNode = MethodInvocationNode;
676
677 return EFI_SUCCESS;
678 }
679
680 /** Call the appropriate function to parse the AML construct in the stream.
681
682 The ExpectedFormat parameter allows to choose the right parsing function.
683 An object node or a data node is created according to format.
684
685 @param [in] ParentNode Node to which the parsed AML construct
686 will be attached.
687 @param [in] ExpectedFormat Format of the AML construct to parse.
688 @param [in, out] FStream Forward stream containing the AML
689 bytecode to parse.
690 The stream must not be at its end.
691 @param [in, out] NameSpaceRefList List of namespace reference nodes.
692 @param [out] OutNode Pointer holding the node created from the
693 parsed AML bytecode.
694
695 @retval EFI_SUCCESS The function completed successfully.
696 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
697 @retval EFI_INVALID_PARAMETER Invalid parameter.
698 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
699 **/
700 STATIC
701 EFI_STATUS
702 EFIAPI
703 AmlParseArgument (
704 IN CONST AML_NODE_HEADER * ParentNode,
705 IN AML_PARSE_FORMAT ExpectedFormat,
706 IN OUT AML_STREAM * FStream,
707 IN OUT LIST_ENTRY * NameSpaceRefList,
708 OUT AML_NODE_HEADER ** OutNode
709 )
710 {
711 EFI_STATUS Status;
712 AML_PARSE_FUNCTION ParsingFunction;
713 AML_DATA_NODE * DataNode;
714 AML_OBJECT_NODE * MethodInvocationNode;
715
716 if ((!IS_AML_ROOT_NODE (ParentNode) &&
717 !IS_AML_OBJECT_NODE (ParentNode)) ||
718 (ExpectedFormat >= EAmlParseFormatMax) ||
719 !IS_STREAM (FStream) ||
720 IS_END_OF_STREAM (FStream) ||
721 !IS_STREAM_FORWARD (FStream) ||
722 (NameSpaceRefList == NULL) ||
723 (OutNode == NULL)) {
724 ASSERT (0);
725 return EFI_INVALID_PARAMETER;
726 }
727
728 ParsingFunction = mParseType[ExpectedFormat];
729 if (ParsingFunction == NULL) {
730 ASSERT (0);
731 return EFI_INVALID_PARAMETER;
732 }
733
734 // Note: The ParsingFunction moves the stream forward as it
735 // consumes the AML bytecode
736 Status = ParsingFunction (
737 ParentNode,
738 ExpectedFormat,
739 FStream,
740 OutNode
741 );
742 if (EFI_ERROR (Status)) {
743 ASSERT (0);
744 return Status;
745 }
746
747 // Check whether the parsed argument is a NameString when an object
748 // is expected. In such case, it could be a method invocation.
749 DataNode = (AML_DATA_NODE*)*OutNode;
750 if (IS_AML_DATA_NODE (DataNode) &&
751 (DataNode->DataType == EAmlNodeDataTypeNameString) &&
752 (ExpectedFormat == EAmlObject)) {
753 Status = AmlCheckAndParseMethodInvoc (
754 ParentNode,
755 (AML_DATA_NODE*)*OutNode,
756 NameSpaceRefList,
757 &MethodInvocationNode);
758 if (EFI_ERROR (Status)) {
759 ASSERT (0);
760 return Status;
761 }
762
763 // A method invocation node has been created and the DataNode containing
764 // the NameString has been attached to the MethodInvocationNode.
765 // Replace the OutNode with the MethodInvocationNode.
766 if (MethodInvocationNode != NULL) {
767 *OutNode = (AML_NODE_HEADER*)MethodInvocationNode;
768 }
769 }
770
771 return Status;
772 }
773
774 /** Parse the Bytelist in the stream.
775 According to the content of the stream, create data node(s)
776 and add them to the variable list of arguments.
777 The byte list may be a list of resource data element or a simple byte list.
778
779 @param [in] BufferNode Object node having a byte list.
780 @param [in, out] FStream Forward stream containing the AML bytecode
781 to parse.
782 The stream must not be at its end.
783
784 @retval EFI_SUCCESS The function completed successfully.
785 @retval EFI_INVALID_PARAMETER Invalid parameter.
786 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
787 **/
788 STATIC
789 EFI_STATUS
790 EFIAPI
791 AmlParseByteList (
792 IN AML_OBJECT_NODE * BufferNode,
793 IN OUT AML_STREAM * FStream
794 )
795 {
796 EFI_STATUS Status;
797 AML_NODE_HEADER * NewNode;
798 CONST UINT8 * Buffer;
799 UINT32 BufferSize;
800
801 // Check whether the node is an Object Node and has byte list.
802 if (!AmlNodeHasAttribute (BufferNode, AML_HAS_BYTE_LIST) ||
803 !IS_STREAM (FStream) ||
804 IS_END_OF_STREAM (FStream) ||
805 !IS_STREAM_FORWARD (FStream)) {
806 ASSERT (0);
807 return EFI_INVALID_PARAMETER;
808 }
809
810 // The buffer contains a list of resource data elements.
811 if (AmlRdIsResourceDataBuffer (FStream)) {
812 // Parse the resource data elements and add them as data nodes.
813 // AmlParseResourceData() moves the stream forward.
814 Status = AmlParseResourceData (BufferNode, FStream);
815 if (EFI_ERROR (Status)) {
816 ASSERT (0);
817 }
818 } else {
819 // The buffer doesn't contain a list of resource data elements.
820 // Create a single node holding the whole buffer data.
821
822 // CreateDataNode checks the Buffer and BufferSize values.
823 Buffer = (CONST UINT8*)AmlStreamGetCurrPos (FStream);
824 BufferSize = AmlStreamGetFreeSpace (FStream);
825
826 Status = AmlCreateDataNode (
827 EAmlNodeDataTypeRaw,
828 Buffer,
829 BufferSize,
830 (AML_DATA_NODE**)&NewNode
831 );
832 if (EFI_ERROR (Status)) {
833 ASSERT (0);
834 return Status;
835 }
836
837 Status = AmlVarListAddTailInternal (
838 (AML_NODE_HEADER*)BufferNode,
839 NewNode
840 );
841 if (EFI_ERROR (Status)) {
842 ASSERT (0);
843 AmlDeleteTree (NewNode);
844 return Status;
845 }
846
847 AMLDBG_DUMP_RAW (Buffer, BufferSize);
848
849 // Move the stream forward as we have consumed the Buffer.
850 Status = AmlStreamProgress (FStream, BufferSize);
851 if (EFI_ERROR (Status)) {
852 ASSERT (0);
853 }
854 }
855
856 return Status;
857 }
858
859 /** Parse the list of fixed arguments of the input ObjectNode.
860
861 For each argument, create a node and add it to the fixed argument list
862 of the Node.
863 If a fixed argument has children, parse them.
864
865 @param [in] ObjectNode Object node to parse the fixed arguments
866 from.
867 @param [in] FStream Forward stream containing the AML
868 bytecode to parse.
869 The stream must not be at its end.
870 @param [in] NameSpaceRefList List of namespace reference nodes.
871
872 @retval EFI_SUCCESS The function completed successfully.
873 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
874 @retval EFI_INVALID_PARAMETER Invalid parameter.
875 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
876 **/
877 EFI_STATUS
878 EFIAPI
879 AmlParseFixedArguments (
880 IN AML_OBJECT_NODE * ObjectNode,
881 IN AML_STREAM * FStream,
882 IN LIST_ENTRY * NameSpaceRefList
883 )
884 {
885 EFI_STATUS Status;
886
887 AML_NODE_HEADER * FixedArgNode;
888 AML_STREAM FixedArgFStream;
889
890 EAML_PARSE_INDEX TermIndex;
891 EAML_PARSE_INDEX MaxIndex;
892 CONST AML_PARSE_FORMAT * Format;
893
894 // Fixed arguments of method invocations node are handled differently.
895 if (!IS_AML_OBJECT_NODE (ObjectNode) ||
896 AmlNodeCompareOpCode (ObjectNode, AML_METHOD_INVOC_OP, 0) ||
897 !IS_STREAM (FStream) ||
898 IS_END_OF_STREAM (FStream) ||
899 !IS_STREAM_FORWARD (FStream) ||
900 (NameSpaceRefList == NULL)) {
901 ASSERT (0);
902 return EFI_INVALID_PARAMETER;
903 }
904
905 TermIndex = EAmlParseIndexTerm0;
906 MaxIndex = (EAML_PARSE_INDEX)AmlGetFixedArgumentCount (
907 (AML_OBJECT_NODE*)ObjectNode
908 );
909 if ((ObjectNode->AmlByteEncoding != NULL) &&
910 (ObjectNode->AmlByteEncoding->Format != NULL)) {
911 Format = ObjectNode->AmlByteEncoding->Format;
912 } else {
913 ASSERT (0);
914 return EFI_INVALID_PARAMETER;
915 }
916
917 // Parse all the FixedArgs.
918 while ((TermIndex < MaxIndex) &&
919 !IS_END_OF_STREAM (FStream) &&
920 (Format[TermIndex] != EAmlNone)) {
921 // Initialize a FixedArgStream to parse the current fixed argument.
922 Status = AmlStreamInitSubStream (FStream, &FixedArgFStream);
923 if (EFI_ERROR (Status)) {
924 ASSERT (0);
925 return Status;
926 }
927
928 // Parse the current fixed argument.
929 Status = AmlParseArgument (
930 (CONST AML_NODE_HEADER*)ObjectNode,
931 Format[TermIndex],
932 &FixedArgFStream,
933 NameSpaceRefList,
934 &FixedArgNode
935 );
936 if (EFI_ERROR (Status)) {
937 ASSERT (0);
938 return Status;
939 }
940
941 // Add the fixed argument to the parent node's fixed argument list.
942 // FixedArgNode can be an object or data node.
943 Status = AmlSetFixedArgument (
944 (AML_OBJECT_NODE*)ObjectNode,
945 TermIndex,
946 FixedArgNode
947 );
948 if (EFI_ERROR (Status)) {
949 ASSERT (0);
950 // Delete the sub-tree if the insertion failed.
951 // Otherwise its reference will be lost.
952 // Use DeleteTree because if the argument was a method invocation,
953 // multiple nodes have been created.
954 AmlDeleteTree (FixedArgNode);
955 return Status;
956 }
957
958 // Parse the AML bytecode of the FixedArgNode if this is an object node.
959 if (IS_AML_OBJECT_NODE (FixedArgNode) &&
960 !IS_END_OF_STREAM (&FixedArgFStream)) {
961 Status = AmlParseStream (
962 FixedArgNode,
963 &FixedArgFStream,
964 NameSpaceRefList
965 );
966 if (EFI_ERROR (Status)) {
967 ASSERT (0);
968 return Status;
969 }
970 }
971
972 // Move the stream forward as we have consumed the sub-stream.
973 Status = AmlStreamProgress (
974 FStream,
975 AmlStreamGetIndex (&FixedArgFStream)
976 );
977 if (EFI_ERROR (Status)) {
978 ASSERT (0);
979 return Status;
980 }
981
982 TermIndex++;
983 } // while
984
985 return EFI_SUCCESS;
986 }
987
988 /** Parse the variable list of arguments of the input ObjectNode.
989
990 For each variable argument, create a node and add it to the variable list of
991 arguments of the Node.
992 If a variable argument has children, parse them recursively.
993
994 The arguments of method invocation nodes are added to the variable list of
995 arguments of the method invocation node. It is necessary to first get
996 the number of arguments to parse for this kind of node. A method invocation
997 can have at most 7 fixed arguments.
998
999 @param [in] Node Node to parse the variable arguments
1000 from.
1001 @param [in] FStream Forward stream containing the AML
1002 bytecode to parse.
1003 The stream must not be at its end.
1004 @param [in] NameSpaceRefList List of namespace reference nodes.
1005
1006 @retval EFI_SUCCESS The function completed successfully.
1007 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1008 @retval EFI_INVALID_PARAMETER Invalid parameter.
1009 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1010 **/
1011 EFI_STATUS
1012 EFIAPI
1013 AmlParseVariableArguments (
1014 IN AML_NODE_HEADER * Node,
1015 IN AML_STREAM * FStream,
1016 IN LIST_ENTRY * NameSpaceRefList
1017 )
1018 {
1019 EFI_STATUS Status;
1020
1021 BOOLEAN IsMethodInvocation;
1022 UINT8 MethodInvocationArgCount;
1023
1024 AML_NODE_HEADER * VarArgNode;
1025 AML_STREAM VarArgFStream;
1026
1027 if ((!AmlNodeHasAttribute (
1028 (CONST AML_OBJECT_NODE*)Node,
1029 AML_HAS_CHILD_OBJ
1030 ) &&
1031 !IS_AML_ROOT_NODE (Node)) ||
1032 !IS_STREAM (FStream) ||
1033 IS_END_OF_STREAM (FStream) ||
1034 !IS_STREAM_FORWARD (FStream) ||
1035 (NameSpaceRefList == NULL)) {
1036 ASSERT (0);
1037 return EFI_INVALID_PARAMETER;
1038 }
1039
1040 Status = AmlGetMethodInvocationArgCount (
1041 (CONST AML_OBJECT_NODE*)Node,
1042 &IsMethodInvocation,
1043 &MethodInvocationArgCount
1044 );
1045 if (EFI_ERROR (Status)) {
1046 ASSERT (0);
1047 return Status;
1048 }
1049
1050 // Parse variable arguments while the Stream is not empty.
1051 while (!IS_END_OF_STREAM (FStream)) {
1052 // If the number of variable arguments are counted, decrement the counter.
1053 if ((IsMethodInvocation) && (MethodInvocationArgCount-- == 0)) {
1054 return EFI_SUCCESS;
1055 }
1056
1057 // Initialize a VarArgStream to parse the current variable argument.
1058 Status = AmlStreamInitSubStream (FStream, &VarArgFStream);
1059 if (EFI_ERROR (Status)) {
1060 ASSERT (0);
1061 return Status;
1062 }
1063
1064 // Parse the current variable argument.
1065 Status = AmlParseArgument (
1066 Node,
1067 EAmlObject,
1068 &VarArgFStream,
1069 NameSpaceRefList,
1070 &VarArgNode
1071 );
1072 if (EFI_ERROR (Status)) {
1073 ASSERT (0);
1074 return Status;
1075 }
1076
1077 // Add the variable argument to its parent variable list of arguments.
1078 // VarArgNode can be an object or data node.
1079 Status = AmlVarListAddTailInternal (
1080 (AML_NODE_HEADER*)Node,
1081 VarArgNode
1082 );
1083 if (EFI_ERROR (Status)) {
1084 ASSERT (0);
1085 // Delete the sub-tree if the insertion failed.
1086 // Otherwise its reference will be lost.
1087 // Use DeleteTree because if the argument was a method invocation,
1088 // multiple nodes have been created.
1089 AmlDeleteTree (VarArgNode);
1090 return Status;
1091 }
1092
1093 // Parse the AML bytecode of the VarArgNode if this is an object node.
1094 if (IS_AML_OBJECT_NODE (VarArgNode) &&
1095 (!IS_END_OF_STREAM (&VarArgFStream))) {
1096 Status = AmlParseStream (VarArgNode, &VarArgFStream, NameSpaceRefList);
1097 if (EFI_ERROR (Status)) {
1098 ASSERT (0);
1099 return Status;
1100 }
1101 }
1102
1103 // Move the stream forward as we have consumed the sub-stream.
1104 Status = AmlStreamProgress (
1105 FStream,
1106 AmlStreamGetIndex (&VarArgFStream)
1107 );
1108 if (EFI_ERROR (Status)) {
1109 ASSERT (0);
1110 return Status;
1111 }
1112 } // while
1113
1114 // If the number of variable arguments are counted, check all the
1115 // MethodInvocationArgCount have been parsed.
1116 if (IsMethodInvocation && (MethodInvocationArgCount != 0)) {
1117 ASSERT (0);
1118 return EFI_INVALID_PARAMETER;
1119 }
1120
1121 return Status;
1122 }
1123
1124 /** Parse the AML stream and populate the root node.
1125
1126 @param [in] RootNode RootNode to which the children are
1127 added.
1128 @param [in, out] FStream Forward stream containing the AML
1129 bytecode to parse.
1130 The stream must not be at its end.
1131 @param [in, out] NameSpaceRefList List of namespace reference nodes.
1132
1133 @retval EFI_SUCCESS The function completed successfully.
1134 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1135 @retval EFI_INVALID_PARAMETER Invalid parameter.
1136 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1137 **/
1138 STATIC
1139 EFI_STATUS
1140 EFIAPI
1141 AmlPopulateRootNode (
1142 IN AML_ROOT_NODE * RootNode,
1143 IN OUT AML_STREAM * FStream,
1144 IN OUT LIST_ENTRY * NameSpaceRefList
1145 )
1146 {
1147 EFI_STATUS Status;
1148
1149 if (!IS_AML_ROOT_NODE (RootNode) ||
1150 !IS_STREAM (FStream) ||
1151 IS_END_OF_STREAM (FStream) ||
1152 !IS_STREAM_FORWARD (FStream) ||
1153 (NameSpaceRefList == NULL)) {
1154 ASSERT (0);
1155 return EFI_INVALID_PARAMETER;
1156 }
1157
1158 // A Root Node only has variable arguments.
1159 Status = AmlParseVariableArguments (
1160 (AML_NODE_HEADER*)RootNode,
1161 FStream,
1162 NameSpaceRefList
1163 );
1164 ASSERT_EFI_ERROR (Status);
1165
1166 return Status;
1167 }
1168
1169 /** Parse the AML stream an populate the object node.
1170
1171 @param [in] ObjectNode ObjectNode to which the children are
1172 added.
1173 @param [in, out] FStream Forward stream containing the AML
1174 bytecode to parse.
1175 The stream must not be at its end.
1176 @param [in, out] NameSpaceRefList List of namespace reference nodes.
1177
1178 @retval EFI_SUCCESS The function completed successfully.
1179 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1180 @retval EFI_INVALID_PARAMETER Invalid parameter.
1181 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1182 **/
1183 STATIC
1184 EFI_STATUS
1185 EFIAPI
1186 AmlPopulateObjectNode (
1187 IN AML_OBJECT_NODE * ObjectNode,
1188 IN OUT AML_STREAM * FStream,
1189 IN OUT LIST_ENTRY * NameSpaceRefList
1190 )
1191 {
1192 EFI_STATUS Status;
1193
1194 if (!IS_AML_OBJECT_NODE (ObjectNode) ||
1195 !IS_STREAM (FStream) ||
1196 IS_END_OF_STREAM (FStream) ||
1197 !IS_STREAM_FORWARD (FStream) ||
1198 (NameSpaceRefList == NULL)) {
1199 ASSERT (0);
1200 return EFI_INVALID_PARAMETER;
1201 }
1202
1203 Status = EFI_SUCCESS;
1204
1205 // Don't parse the fixed arguments of method invocation nodes.
1206 // The AML encoding for method invocations in the ACPI specification 6.3 is:
1207 // MethodInvocation := NameString TermArgList
1208 // Since the AML specification does not define an OpCode for method
1209 // invocation, this AML parser defines a pseudo opcode and redefines the
1210 // grammar for simplicity as:
1211 // MethodInvocation := MethodInvocationOp NameString ArgumentCount TermArgList
1212 // ArgumentCount := ByteData
1213 // Due to this difference, the MethodInvocationOp and the fixed argument
1214 // i.e. ArgumentCount is not available in the AML stream and need to be
1215 // handled differently.
1216 if (!AmlNodeCompareOpCode (ObjectNode, AML_METHOD_INVOC_OP, 0)) {
1217 // Parse the fixed list of arguments.
1218 Status = AmlParseFixedArguments (
1219 ObjectNode,
1220 FStream,
1221 NameSpaceRefList
1222 );
1223 if (EFI_ERROR (Status)) {
1224 ASSERT (0);
1225 return Status;
1226 }
1227 }
1228
1229 // Save the association [node reference/pathname] in the NameSpaceRefList.
1230 // This allows to identify method invocations from other namespace
1231 // paths. Method invocation need to be parsed differently.
1232 if (AmlNodeHasAttribute (
1233 (CONST AML_OBJECT_NODE*)ObjectNode,
1234 AML_IN_NAMESPACE)) {
1235 Status = AmlAddNameSpaceReference (
1236 (CONST AML_OBJECT_NODE*)ObjectNode,
1237 NameSpaceRefList
1238 );
1239 if (EFI_ERROR (Status)) {
1240 ASSERT (0);
1241 return Status;
1242 }
1243 }
1244
1245 if (!IS_END_OF_STREAM (FStream)) {
1246 // Parse the variable list of arguments if present.
1247 if (AmlNodeHasAttribute (ObjectNode, AML_HAS_CHILD_OBJ)) {
1248 Status = AmlParseVariableArguments (
1249 (AML_NODE_HEADER*)ObjectNode,
1250 FStream,
1251 NameSpaceRefList
1252 );
1253 } else if (AmlNodeHasAttribute (ObjectNode, AML_HAS_BYTE_LIST)) {
1254 // Parse the byte list if present.
1255 Status = AmlParseByteList (
1256 ObjectNode,
1257 FStream
1258 );
1259 } else if (AmlNodeHasAttribute (ObjectNode, AML_HAS_FIELD_LIST)) {
1260 // Parse the field list if present.
1261 Status = AmlParseFieldList (
1262 ObjectNode,
1263 FStream,
1264 NameSpaceRefList
1265 );
1266 }
1267
1268 // Check status and assert
1269 if (EFI_ERROR (Status)) {
1270 ASSERT (0);
1271 }
1272 }
1273
1274 return Status;
1275 }
1276
1277 /** Invoke the appropriate parsing functions based on the Node type.
1278
1279 @param [in] Node Node from which the children are parsed.
1280 Must be a root node or an object node.
1281 @param [in] FStream Forward stream containing the AML
1282 bytecode to parse.
1283 The stream must not be at its end.
1284 @param [in] NameSpaceRefList List of namespace reference nodes.
1285
1286 @retval EFI_SUCCESS The function completed successfully.
1287 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1288 @retval EFI_INVALID_PARAMETER Invalid parameter.
1289 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1290 **/
1291 STATIC
1292 EFI_STATUS
1293 EFIAPI
1294 AmlParseStream (
1295 IN AML_NODE_HEADER * Node,
1296 IN AML_STREAM * FStream,
1297 IN LIST_ENTRY * NameSpaceRefList
1298 )
1299 {
1300 EFI_STATUS Status;
1301
1302 if (IS_AML_ROOT_NODE (Node)) {
1303 Status = AmlPopulateRootNode (
1304 (AML_ROOT_NODE*)Node,
1305 FStream,
1306 NameSpaceRefList
1307 );
1308 if (EFI_ERROR (Status)) {
1309 ASSERT (0);
1310 }
1311
1312 } else if (IS_AML_OBJECT_NODE (Node)) {
1313 Status = AmlPopulateObjectNode (
1314 (AML_OBJECT_NODE*)Node,
1315 FStream,
1316 NameSpaceRefList
1317 );
1318 if (EFI_ERROR (Status)) {
1319 ASSERT (0);
1320 }
1321
1322 } else {
1323 // Data node or other.
1324 ASSERT (0);
1325 Status = EFI_INVALID_PARAMETER;
1326 }
1327
1328 return Status;
1329 }
1330
1331 /** Parse the definition block.
1332
1333 This function parses the whole AML blob. It starts with the ACPI DSDT/SSDT
1334 header and then parses the AML bytestream.
1335 A tree structure is returned via the RootPtr.
1336 The tree must be deleted with the AmlDeleteTree function.
1337
1338 @param [in] DefinitionBlock Pointer to the definition block.
1339 @param [out] RootPtr Pointer to the root node of the tree.
1340
1341 @retval EFI_SUCCESS The function completed successfully.
1342 @retval EFI_BUFFER_TOO_SMALL No space left in the buffer.
1343 @retval EFI_INVALID_PARAMETER Invalid parameter.
1344 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
1345 **/
1346 EFI_STATUS
1347 EFIAPI
1348 AmlParseDefinitionBlock (
1349 IN CONST EFI_ACPI_DESCRIPTION_HEADER * DefinitionBlock,
1350 OUT AML_ROOT_NODE ** RootPtr
1351 )
1352 {
1353 EFI_STATUS Status;
1354 EFI_STATUS Status1;
1355 AML_STREAM Stream;
1356 AML_ROOT_NODE * Root;
1357
1358 LIST_ENTRY NameSpaceRefList;
1359
1360 UINT8 * Buffer;
1361 UINT32 MaxBufferSize;
1362
1363 if ((DefinitionBlock == NULL) ||
1364 (RootPtr == NULL)) {
1365 ASSERT (0);
1366 return EFI_INVALID_PARAMETER;
1367 }
1368
1369 Buffer = (UINT8*)DefinitionBlock + sizeof (EFI_ACPI_DESCRIPTION_HEADER);
1370 if (DefinitionBlock->Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) {
1371 ASSERT (0);
1372 return EFI_INVALID_PARAMETER;
1373 }
1374 MaxBufferSize = DefinitionBlock->Length -
1375 (UINT32)sizeof (EFI_ACPI_DESCRIPTION_HEADER);
1376
1377 // Create a root node.
1378 Status = AmlCreateRootNode (
1379 (EFI_ACPI_DESCRIPTION_HEADER*)DefinitionBlock,
1380 &Root
1381 );
1382 if (EFI_ERROR (Status)) {
1383 ASSERT (0);
1384 return Status;
1385 }
1386
1387 *RootPtr = Root;
1388
1389 if (MaxBufferSize == 0) {
1390 return EFI_SUCCESS;
1391 }
1392
1393 // Initialize a stream to parse the AML bytecode.
1394 Status = AmlStreamInit (
1395 &Stream,
1396 Buffer,
1397 MaxBufferSize,
1398 EAmlStreamDirectionForward
1399 );
1400 if (EFI_ERROR (Status)) {
1401 ASSERT (0);
1402 goto error_handler;
1403 }
1404
1405 // Initialize the NameSpaceRefList, holding references to nodes declaring
1406 // a name in the AML namespace.
1407 InitializeListHead (&NameSpaceRefList);
1408
1409 // Parse the whole AML blob.
1410 Status = AmlParseStream (
1411 (AML_NODE_HEADER*)Root,
1412 &Stream,
1413 &NameSpaceRefList
1414 );
1415 if (EFI_ERROR (Status)) {
1416 ASSERT (0);
1417 goto error_handler;
1418 }
1419
1420 // Check the whole AML blob has been parsed.
1421 if (!IS_END_OF_STREAM (&Stream)) {
1422 ASSERT (0);
1423 Status = EFI_INVALID_PARAMETER;
1424 goto error_handler;
1425 }
1426
1427 // Print the list of NameSpace reference nodes.
1428 // AmlDbgPrintNameSpaceRefList (&NameSpaceRefList);
1429
1430 // Delete the NameSpaceRefList
1431 goto exit_handler;
1432
1433 error_handler:
1434 if (Root != NULL) {
1435 AmlDeleteTree ((AML_NODE_HEADER*)Root);
1436 }
1437
1438 exit_handler:
1439 Status1 = AmlDeleteNameSpaceRefList (&NameSpaceRefList);
1440 if (EFI_ERROR (Status1)) {
1441 ASSERT (0);
1442 if (!EFI_ERROR (Status)) {
1443 return Status1;
1444 }
1445 }
1446
1447 return Status;
1448 }