1 /** @file
2   AML Node.
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 <Tree/AmlNode.h>
10 
11 #include <AmlCoreInterface.h>
12 #include <Tree/AmlTree.h>
13 
14 /** Initialize an AML_NODE_HEADER structure.
15 
16   @param  [in]  Node      Pointer to a node header.
17   @param  [in]  NodeType  NodeType to initialize the Node with.
18                           Must be an EAML_NODE_TYPE.
19 
20   @retval EFI_SUCCESS             The function completed successfully.
21   @retval EFI_INVALID_PARAMETER   Invalid parameter.
22 **/
23 STATIC
24 EFI_STATUS
25 EFIAPI
AmlInitializeNodeHeader(IN AML_NODE_HEADER * Node,IN EAML_NODE_TYPE NodeType)26 AmlInitializeNodeHeader (
27   IN  AML_NODE_HEADER   * Node,
28   IN  EAML_NODE_TYPE      NodeType
29   )
30 {
31   if (Node == NULL) {
32     ASSERT (0);
33     return EFI_INVALID_PARAMETER;
34   }
35 
36   InitializeListHead (&Node->Link);
37 
38   Node->Parent = NULL;
39   Node->NodeType = NodeType;
40 
41   return EFI_SUCCESS;
42 }
43 
44 /** Delete a root node and its ACPI DSDT/SSDT header.
45 
46   It is the caller's responsibility to check the RootNode has been removed
47   from the tree and is not referencing any other node in the tree.
48 
49   @param  [in]  RootNode  Pointer to a root node.
50 
51   @retval EFI_SUCCESS             The function completed successfully.
52   @retval EFI_INVALID_PARAMETER   Invalid parameter.
53 **/
54 STATIC
55 EFI_STATUS
56 EFIAPI
AmlDeleteRootNode(IN AML_ROOT_NODE * RootNode)57 AmlDeleteRootNode (
58   IN  AML_ROOT_NODE  * RootNode
59   )
60 {
61   if (!IS_AML_ROOT_NODE (RootNode)) {
62     ASSERT (0);
63     return EFI_INVALID_PARAMETER;
64   }
65 
66   if ((RootNode->SdtHeader != NULL)) {
67     FreePool (RootNode->SdtHeader);
68   } else {
69     ASSERT (0);
70     return EFI_INVALID_PARAMETER;
71   }
72 
73   FreePool (RootNode);
74   return EFI_SUCCESS;
75 }
76 
77 /** Create an AML_ROOT_NODE.
78     This node will be the root of the tree.
79 
80   @param  [in]  SdtHeader       Pointer to an ACPI DSDT/SSDT header to copy
81                                 the data from.
82   @param  [out] NewRootNodePtr  The created AML_ROOT_NODE.
83 
84   @retval EFI_SUCCESS             The function completed successfully.
85   @retval EFI_INVALID_PARAMETER   Invalid parameter.
86   @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
87 **/
88 EFI_STATUS
89 EFIAPI
AmlCreateRootNode(IN CONST EFI_ACPI_DESCRIPTION_HEADER * SdtHeader,OUT AML_ROOT_NODE ** NewRootNodePtr)90 AmlCreateRootNode (
91   IN  CONST EFI_ACPI_DESCRIPTION_HEADER   * SdtHeader,
92   OUT       AML_ROOT_NODE                ** NewRootNodePtr
93   )
94 {
95   EFI_STATUS        Status;
96   AML_ROOT_NODE   * RootNode;
97 
98   if ((SdtHeader == NULL) ||
99       (NewRootNodePtr == NULL)) {
100     ASSERT (0);
101     return EFI_INVALID_PARAMETER;
102   }
103 
104   RootNode = AllocateZeroPool (sizeof (AML_ROOT_NODE));
105   if (RootNode == NULL) {
106     ASSERT (0);
107     return EFI_OUT_OF_RESOURCES;
108   }
109 
110   Status = AmlInitializeNodeHeader (&RootNode->NodeHeader, EAmlNodeRoot);
111   if (EFI_ERROR (Status)) {
112     FreePool (RootNode);
113     ASSERT (0);
114     return Status;
115   }
116 
117   InitializeListHead (&RootNode->VariableArgs);
118 
119   RootNode->SdtHeader = AllocateCopyPool (
120                           sizeof (EFI_ACPI_DESCRIPTION_HEADER),
121                           SdtHeader
122                           );
123   if (RootNode->SdtHeader == NULL) {
124     ASSERT (0);
125     AmlDeleteRootNode (RootNode);
126     return EFI_OUT_OF_RESOURCES;
127   }
128 
129   *NewRootNodePtr = RootNode;
130 
131   return EFI_SUCCESS;
132 }
133 
134 /** Delete an object node.
135 
136   It is the caller's responsibility to check the ObjectNode has been removed
137   from the tree and is not referencing any other node in the tree.
138 
139   @param  [in]  ObjectNode  Pointer to an object node.
140 
141   @retval EFI_SUCCESS             The function completed successfully.
142   @retval EFI_INVALID_PARAMETER   Invalid parameter.
143 **/
144 STATIC
145 EFI_STATUS
146 EFIAPI
AmlDeleteObjectNode(IN AML_OBJECT_NODE * ObjectNode)147 AmlDeleteObjectNode (
148   IN  AML_OBJECT_NODE   * ObjectNode
149   )
150 {
151   if (!IS_AML_OBJECT_NODE (ObjectNode)) {
152     ASSERT (0);
153     return EFI_INVALID_PARAMETER;
154   }
155 
156   FreePool (ObjectNode);
157   return EFI_SUCCESS;
158 }
159 
160 /** Create an AML_OBJECT_NODE.
161 
162   @param  [in]  AmlByteEncoding   Byte encoding entry.
163   @param  [in]  PkgLength         PkgLength of the node if the AmlByteEncoding
164                                   has the PkgLen attribute.
165                                   0 otherwise.
166   @param  [out] NewObjectNodePtr  The created AML_OBJECT_NODE.
167 
168   @retval EFI_SUCCESS             The function completed successfully.
169   @retval EFI_INVALID_PARAMETER   Invalid parameter.
170   @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
171 **/
172 EFI_STATUS
173 EFIAPI
AmlCreateObjectNode(IN CONST AML_BYTE_ENCODING * AmlByteEncoding,IN UINT32 PkgLength,OUT AML_OBJECT_NODE ** NewObjectNodePtr)174 AmlCreateObjectNode (
175   IN  CONST  AML_BYTE_ENCODING   * AmlByteEncoding,
176   IN         UINT32                PkgLength,
177   OUT        AML_OBJECT_NODE    ** NewObjectNodePtr
178   )
179 {
180   EFI_STATUS            Status;
181   AML_OBJECT_NODE     * ObjectNode;
182 
183   if ((AmlByteEncoding == NULL)  ||
184       (NewObjectNodePtr == NULL)) {
185     ASSERT (0);
186     return EFI_INVALID_PARAMETER;
187   }
188 
189   ObjectNode = AllocateZeroPool (sizeof (AML_OBJECT_NODE));
190   if (ObjectNode == NULL) {
191     ASSERT (0);
192     return EFI_OUT_OF_RESOURCES;
193   }
194 
195   Status = AmlInitializeNodeHeader (&ObjectNode->NodeHeader, EAmlNodeObject);
196   if (EFI_ERROR (Status)) {
197     FreePool (ObjectNode);
198     ASSERT (0);
199     return Status;
200   }
201 
202   InitializeListHead (&ObjectNode->VariableArgs);
203 
204   // ObjectNode->FixedArgs[...] is already initialised to NULL as the
205   // ObjectNode is Zero allocated.
206   ObjectNode->AmlByteEncoding = AmlByteEncoding;
207   ObjectNode->PkgLen = PkgLength;
208 
209   *NewObjectNodePtr = ObjectNode;
210 
211   return EFI_SUCCESS;
212 }
213 
214 /** Delete a data node and its buffer.
215 
216   It is the caller's responsibility to check the DataNode has been removed
217   from the tree and is not referencing any other node in the tree.
218 
219   @param  [in]  DataNode  Pointer to a data node.
220 
221   @retval EFI_SUCCESS             The function completed successfully.
222   @retval EFI_INVALID_PARAMETER   Invalid parameter.
223   @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
224 **/
225 STATIC
226 EFI_STATUS
227 EFIAPI
AmlDeleteDataNode(IN AML_DATA_NODE * DataNode)228 AmlDeleteDataNode (
229   IN  AML_DATA_NODE   * DataNode
230   )
231 {
232   if (!IS_AML_DATA_NODE (DataNode)) {
233     ASSERT (0);
234     return EFI_INVALID_PARAMETER;
235   }
236 
237   if (DataNode->Buffer != NULL) {
238     FreePool (DataNode->Buffer);
239   } else {
240     ASSERT (0);
241     return EFI_INVALID_PARAMETER;
242   }
243 
244   FreePool (DataNode);
245   return EFI_SUCCESS;
246 }
247 
248 /** Create an AML_DATA_NODE.
249 
250   @param  [in]  DataType        DataType of the node.
251   @param  [in]  Data            Pointer to the AML bytecode corresponding to
252                                 this node. Data is copied from there.
253   @param  [in]  DataSize        Number of bytes to consider at the address
254                                 pointed by Data.
255   @param  [out] NewDataNodePtr  The created AML_DATA_NODE.
256 
257   @retval EFI_SUCCESS             The function completed successfully.
258   @retval EFI_INVALID_PARAMETER   Invalid parameter.
259   @retval EFI_OUT_OF_RESOURCES    Could not allocate memory.
260 **/
261 EFI_STATUS
262 EFIAPI
AmlCreateDataNode(IN EAML_NODE_DATA_TYPE DataType,IN CONST UINT8 * Data,IN UINT32 DataSize,OUT AML_DATA_NODE ** NewDataNodePtr)263 AmlCreateDataNode (
264   IN        EAML_NODE_DATA_TYPE     DataType,
265   IN  CONST UINT8                 * Data,
266   IN        UINT32                  DataSize,
267   OUT       AML_DATA_NODE        ** NewDataNodePtr
268   )
269 {
270   EFI_STATUS        Status;
271   AML_DATA_NODE   * DataNode;
272 
273   // A data node must not be created for certain data types.
274   if ((DataType == EAmlNodeDataTypeNone)       ||
275       (DataType == EAmlNodeDataTypeReserved1)  ||
276       (DataType == EAmlNodeDataTypeReserved2)  ||
277       (DataType == EAmlNodeDataTypeReserved3)  ||
278       (DataType == EAmlNodeDataTypeReserved4)  ||
279       (DataType == EAmlNodeDataTypeReserved5)  ||
280       (Data == NULL)                           ||
281       (DataSize == 0)                          ||
282       (NewDataNodePtr == NULL)) {
283     ASSERT (0);
284     return EFI_INVALID_PARAMETER;
285   }
286 
287   DataNode = AllocateZeroPool (sizeof (AML_DATA_NODE));
288   if (DataNode == NULL) {
289     ASSERT (0);
290     return EFI_OUT_OF_RESOURCES;
291   }
292 
293   Status = AmlInitializeNodeHeader (&DataNode->NodeHeader, EAmlNodeData);
294   if (EFI_ERROR (Status)) {
295     FreePool (DataNode);
296     ASSERT (0);
297     return Status;
298   }
299 
300   DataNode->Buffer = AllocateCopyPool (DataSize, Data);
301   if (DataNode->Buffer == NULL) {
302     AmlDeleteDataNode (DataNode);
303     ASSERT (0);
304     return EFI_OUT_OF_RESOURCES;
305   }
306 
307   DataNode->DataType = DataType;
308   DataNode->Size = DataSize;
309 
310   *NewDataNodePtr = DataNode;
311 
312   return EFI_SUCCESS;
313 }
314 
315 /** Delete a Node.
316 
317   @param  [in]  Node  Pointer to a Node.
318 
319   @retval EFI_SUCCESS             The function completed successfully.
320   @retval EFI_INVALID_PARAMETER   Invalid parameter.
321 **/
322 EFI_STATUS
323 EFIAPI
AmlDeleteNode(IN AML_NODE_HEADER * Node)324 AmlDeleteNode (
325   IN  AML_NODE_HEADER   * Node
326   )
327 {
328   EFI_STATUS          Status;
329   EAML_PARSE_INDEX    Index;
330 
331   // Check that the node being deleted is unlinked.
332   // When removing the node, its parent and list are reset
333   // with InitializeListHead. Thus it must be empty.
334   if (!IS_AML_NODE_VALID (Node) ||
335       !AML_NODE_IS_DETACHED (Node)) {
336     ASSERT (0);
337     return EFI_INVALID_PARAMETER;
338   }
339 
340   switch (Node->NodeType) {
341     case EAmlNodeRoot:
342     {
343       // Check the variable list of arguments has been cleaned.
344       if (!IsListEmpty (AmlNodeGetVariableArgList (Node))) {
345         ASSERT (0);
346         return EFI_INVALID_PARAMETER;
347       }
348 
349       Status = AmlDeleteRootNode ((AML_ROOT_NODE*)Node);
350       if (EFI_ERROR (Status)) {
351         ASSERT (0);
352       }
353       break;
354     }
355 
356     case EAmlNodeObject:
357     {
358       // Check the variable list of arguments has been cleaned.
359       if (!IsListEmpty (AmlNodeGetVariableArgList (Node))) {
360         ASSERT (0);
361         return EFI_INVALID_PARAMETER;
362       }
363 
364       // Check the fixed argument list has been cleaned.
365       for (Index = EAmlParseIndexTerm0; Index < EAmlParseIndexMax; Index++) {
366         if (((AML_OBJECT_NODE*)Node)->FixedArgs[Index] != NULL) {
367           ASSERT (0);
368           return EFI_INVALID_PARAMETER;
369         }
370       }
371 
372       Status = AmlDeleteObjectNode ((AML_OBJECT_NODE*)Node);
373       if (EFI_ERROR (Status)) {
374         ASSERT (0);
375       }
376       break;
377     }
378 
379     case EAmlNodeData:
380     {
381       Status = AmlDeleteDataNode ((AML_DATA_NODE*)Node);
382       if (EFI_ERROR (Status)) {
383         ASSERT (0);
384       }
385       break;
386     }
387 
388     default:
389     {
390       ASSERT (0);
391       Status = EFI_INVALID_PARAMETER;
392       break;
393     }
394   } // switch
395 
396   return Status;
397 }
398 
399 /** Check whether ObjectNode has the input attribute.
400     This function can be used to check ObjectNode is an object node
401     at the same time.
402 
403   @param  [in]  ObjectNode  Pointer to an object node.
404   @param  [in]  Attribute   Attribute to check for.
405 
406   @retval TRUE    The node is an AML object and the attribute is present.
407   @retval FALSE   Otherwise.
408 **/
409 BOOLEAN
410 EFIAPI
AmlNodeHasAttribute(IN CONST AML_OBJECT_NODE * ObjectNode,IN AML_OP_ATTRIBUTE Attribute)411 AmlNodeHasAttribute (
412   IN  CONST AML_OBJECT_NODE   * ObjectNode,
413   IN        AML_OP_ATTRIBUTE    Attribute
414   )
415 {
416   if (!IS_AML_OBJECT_NODE (ObjectNode) ||
417       (ObjectNode->AmlByteEncoding == NULL)) {
418     return FALSE;
419   }
420 
421   return ((ObjectNode->AmlByteEncoding->Attribute &
422            Attribute) == 0 ? FALSE : TRUE);
423 }
424 
425 /** Check whether ObjectNode has the input OpCode/SubOpcode couple.
426 
427   @param  [in]  ObjectNode  Pointer to an object node.
428   @param  [in]  OpCode      OpCode to check
429   @param  [in]  SubOpCode   SubOpCode to check
430 
431   @retval TRUE    The node is an AML object and
432                   the Opcode and the SubOpCode match.
433   @retval FALSE   Otherwise.
434 **/
435 BOOLEAN
436 EFIAPI
AmlNodeCompareOpCode(IN CONST AML_OBJECT_NODE * ObjectNode,IN UINT8 OpCode,IN UINT8 SubOpCode)437 AmlNodeCompareOpCode (
438   IN  CONST  AML_OBJECT_NODE  * ObjectNode,
439   IN         UINT8              OpCode,
440   IN         UINT8              SubOpCode
441   )
442 {
443   if (!IS_AML_OBJECT_NODE (ObjectNode) ||
444       (ObjectNode->AmlByteEncoding == NULL)) {
445     return FALSE;
446   }
447 
448   ASSERT (AmlIsOpCodeValid (OpCode, SubOpCode));
449 
450   return ((ObjectNode->AmlByteEncoding->OpCode == OpCode) &&
451            (ObjectNode->AmlByteEncoding->SubOpCode == SubOpCode)) ?
452            TRUE : FALSE;
453 }
454 
455 /** Check whether a Node is an integer node.
456 
457   By integer node we mean an object node having one of the following opcode:
458    - AML_BYTE_PREFIX;
459    - AML_WORD_PREFIX;
460    - AML_DWORD_PREFIX;
461    - AML_QWORD_PREFIX.
462 
463   @param  [in]  Node  The node to check.
464 
465   @retval TRUE  The Node is an integer node.
466   @retval FALSE Otherwise.
467 */
468 BOOLEAN
469 EFIAPI
IsIntegerNode(IN AML_OBJECT_NODE * Node)470 IsIntegerNode (
471   IN  AML_OBJECT_NODE   * Node
472   )
473 {
474   UINT8   OpCode;
475 
476   if (!IS_AML_OBJECT_NODE (Node)  ||
477       (Node->AmlByteEncoding == NULL)) {
478     return FALSE;
479   }
480 
481   // Check Node is an integer node.
482   OpCode = Node->AmlByteEncoding->OpCode;
483   if ((OpCode != AML_BYTE_PREFIX)   &&
484       (OpCode != AML_WORD_PREFIX)   &&
485       (OpCode != AML_DWORD_PREFIX)  &&
486       (OpCode != AML_QWORD_PREFIX)) {
487     return FALSE;
488   }
489 
490   return TRUE;
491 }
492 
493 /** Check whether a Node is a ZeroOp, a OneOp or a OnesOp.
494 
495   These two objects don't have a data node holding
496   a value. This require special handling.
497 
498   @param  [in]  Node  The node to check.
499 
500   @retval TRUE  The Node is a ZeroOp or OneOp.
501   @retval FALSE Otherwise.
502 */
503 BOOLEAN
504 EFIAPI
IsSpecialIntegerNode(IN AML_OBJECT_NODE * Node)505 IsSpecialIntegerNode (
506   IN  AML_OBJECT_NODE   * Node
507   )
508 {
509   UINT8   OpCode;
510 
511   if (!IS_AML_OBJECT_NODE (Node)  ||
512       (Node->AmlByteEncoding == NULL)) {
513     return FALSE;
514   }
515 
516   OpCode = Node->AmlByteEncoding->OpCode;
517 
518   if ((OpCode != AML_ZERO_OP) &&
519       (OpCode != AML_ONE_OP)  &&
520       (OpCode != AML_ONES_OP)) {
521     return FALSE;
522   }
523 
524   return TRUE;
525 }
526 
527 /** Check whether Node corresponds to a method definition.
528 
529   A method definition can be introduced:
530    - By a method object, having an AML_METHOD_OP OpCode;
531    - By an external definition of a method, having an AML_EXTERNAL_OP OpCode
532      and an ObjectType byte set to the MethodObj.
533 
534   Note:
535   An alias node, having an AML_ALIAS_OP, can be resolved to a method
536   definition. This function doesn't handle this case.
537 
538   @param [in] Node    Node to check whether it is a method definition.
539 
540   @retval TRUE  The Node is a method definition.
541   @retval FALSE Otherwise.
542 **/
543 BOOLEAN
544 EFIAPI
AmlIsMethodDefinitionNode(IN CONST AML_OBJECT_NODE * Node)545 AmlIsMethodDefinitionNode (
546   IN  CONST AML_OBJECT_NODE   * Node
547   )
548 {
549   AML_DATA_NODE   * ObjectType;
550 
551   // Node is checked to be an object node aswell.
552   if (AmlNodeCompareOpCode (Node, AML_METHOD_OP, 0)) {
553     return TRUE;
554   } else if (AmlNodeCompareOpCode (Node, AML_EXTERNAL_OP, 0)) {
555     // If the node is an external definition, check this is a method.
556     // DefExternal := ExternalOp NameString ObjectType ArgumentCount
557     // ExternalOp := 0x15
558     // ObjectType := ByteData
559     // ArgumentCount := ByteData (0 – 7)
560     ObjectType = (AML_DATA_NODE*)AmlGetFixedArgument (
561                                    (AML_OBJECT_NODE*)Node,
562                                    EAmlParseIndexTerm1
563                                    );
564     if (IS_AML_DATA_NODE (ObjectType)                   &&
565         (ObjectType->DataType == EAmlNodeDataTypeUInt)  &&
566         ((ObjectType->Size == 1))) {
567       if (*((UINT8*)ObjectType->Buffer) == (UINT8)EAmlObjTypeMethodObj) {
568         // The external definition is a method.
569         return TRUE;
570       } else {
571         // The external definition is not a method.
572         return FALSE;
573       }
574     } else {
575       // The tree is inconsistent.
576       ASSERT (0);
577       return FALSE;
578     }
579   }
580 
581   // This is not a method definition.
582   return FALSE;
583 }
584 
585 /** Get the index at which the name of the node is stored.
586 
587   @param  [in]  ObjectNode  Pointer to an object node.
588                             Must have the AML_IN_NAMESPACE attribute.
589   @param  [out] Index       Index of the name in the fixed list of arguments.
590 
591   @retval EFI_SUCCESS             The function completed successfully.
592   @retval EFI_INVALID_PARAMETER   Invalid parameter.
593 **/
594 EFI_STATUS
AmlNodeGetNameIndex(IN CONST AML_OBJECT_NODE * ObjectNode,OUT EAML_PARSE_INDEX * Index)595 AmlNodeGetNameIndex (
596   IN  CONST AML_OBJECT_NODE     * ObjectNode,
597   OUT       EAML_PARSE_INDEX    * Index
598   )
599 {
600   EAML_PARSE_INDEX    NameIndex;
601 
602   if (!AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE)   ||
603       (ObjectNode->AmlByteEncoding == NULL)                 ||
604       (Index == NULL)) {
605     ASSERT (0);
606     return EFI_INVALID_PARAMETER;
607   }
608 
609   NameIndex = ObjectNode->AmlByteEncoding->NameIndex;
610 
611   if ((NameIndex > ObjectNode->AmlByteEncoding->MaxIndex)   ||
612       (ObjectNode->AmlByteEncoding->Format[NameIndex] != EAmlName)) {
613     ASSERT (0);
614     return EFI_INVALID_PARAMETER;
615   }
616 
617   *Index = NameIndex;
618 
619   return EFI_SUCCESS;
620 }
621 
622 /** Get the name of the Node.
623 
624   Node must be part of the namespace.
625 
626   @param [in] ObjectNode    Pointer to an object node,
627                             which is part of the namespace.
628 
629   @return A pointer to the name.
630           NULL otherwise.
631           Return NULL for the root node.
632 **/
633 CHAR8 *
634 EFIAPI
AmlNodeGetName(IN CONST AML_OBJECT_NODE * ObjectNode)635 AmlNodeGetName (
636   IN  CONST AML_OBJECT_NODE   * ObjectNode
637   )
638 {
639   EFI_STATUS          Status;
640   EAML_PARSE_INDEX    NameIndex;
641   AML_DATA_NODE     * DataNode;
642 
643   if (!AmlNodeHasAttribute (ObjectNode, AML_IN_NAMESPACE)) {
644     ASSERT (0);
645     return NULL;
646   }
647 
648   // Get the index at which the name is stored in the fixed arguments list.
649   Status = AmlNodeGetNameIndex (ObjectNode, &NameIndex);
650   if (EFI_ERROR (Status)) {
651     ASSERT (0);
652     return NULL;
653   }
654 
655   // The name is stored in a Data node.
656   DataNode = (AML_DATA_NODE*)ObjectNode->FixedArgs[NameIndex];
657   if (IS_AML_DATA_NODE (DataNode) &&
658       (DataNode->DataType == EAmlNodeDataTypeNameString)) {
659     return (CHAR8*)DataNode->Buffer;
660   }
661 
662   /* Return NULL if no name is found.
663      This can occur if the name of a node is defined as a further
664      fixed argument.
665      E.g.:  CreateField (BD03, 0x28, Add (ID03 + 0x08), BF33)
666                                      ^
667                              The parser is here.
668      The parent of the Add statement is the CreateField statement. This
669      statement defines a name in the AML namespace. This name defined as
670      the fourth fixed argument. It hasn't been parsed yet.
671   */
672   return NULL;
673 }
674