1 /** @file
2   AML Code Generation.
3 
4   Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8 
9 #include <AmlNodeDefines.h>
10 
11 #include <AcpiTableGenerator.h>
12 
13 #include <AmlCoreInterface.h>
14 #include <AmlEncoding/Aml.h>
15 #include <Tree/AmlNode.h>
16 #include <Tree/AmlTree.h>
17 #include <String/AmlString.h>
18 #include <Utils/AmlUtility.h>
19 
20 /** Utility function to link a node when returning from a CodeGen function.
21 
22   @param [in]  Node           Newly created node.
23   @param [in]  ParentNode     If provided, set ParentNode as the parent
24                               of the node created.
25   @param [out] NewObjectNode  If success, contains the created object node.
26 
27   @retval  EFI_SUCCESS            The function completed successfully.
28   @retval  EFI_INVALID_PARAMETER  Invalid parameter.
29 **/
30 STATIC
31 EFI_STATUS
32 EFIAPI
LinkNode(IN AML_OBJECT_NODE * Node,IN AML_NODE_HEADER * ParentNode,IN AML_OBJECT_NODE ** NewObjectNode)33 LinkNode (
34   IN  AML_OBJECT_NODE    * Node,
35   IN  AML_NODE_HEADER    * ParentNode,
36   IN  AML_OBJECT_NODE   ** NewObjectNode
37   )
38 {
39   EFI_STATUS    Status;
40 
41   if (NewObjectNode != NULL) {
42     *NewObjectNode = Node;
43   }
44 
45   // Add RdNode as the last element.
46   if (ParentNode != NULL) {
47     Status = AmlVarListAddTail (ParentNode, (AML_NODE_HEADER*)Node);
48     if (EFI_ERROR (Status)) {
49       ASSERT (0);
50       return Status;
51     }
52   }
53 
54   return EFI_SUCCESS;
55 }
56 
57 /** AML code generation for DefinitionBlock.
58 
59   Create a Root Node handle.
60   It is the caller's responsibility to free the allocated memory
61   with the AmlDeleteTree function.
62 
63   AmlCodeGenDefinitionBlock (TableSignature, OemID, TableID, OEMRevision) is
64   equivalent to the following ASL code:
65     DefinitionBlock (AMLFileName, TableSignature, ComplianceRevision,
66       OemID, TableID, OEMRevision) {}
67   with the ComplianceRevision set to 2 and the AMLFileName is ignored.
68 
69   @param[in]  TableSignature       4-character ACPI signature.
70                                    Must be 'DSDT' or 'SSDT'.
71   @param[in]  OemId                6-character string OEM identifier.
72   @param[in]  OemTableId           8-character string OEM table identifier.
73   @param[in]  OemRevision          OEM revision number.
74   @param[out] DefinitionBlockTerm  The ASL Term handle representing a
75                                    Definition Block.
76 
77   @retval EFI_SUCCESS             Success.
78   @retval EFI_INVALID_PARAMETER   Invalid parameter.
79   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
80 **/
81 EFI_STATUS
82 EFIAPI
AmlCodeGenDefinitionBlock(IN CONST CHAR8 * TableSignature,IN CONST CHAR8 * OemId,IN CONST CHAR8 * OemTableId,IN UINT32 OemRevision,OUT AML_ROOT_NODE ** NewRootNode)83 AmlCodeGenDefinitionBlock (
84   IN  CONST CHAR8             * TableSignature,
85   IN  CONST CHAR8             * OemId,
86   IN  CONST CHAR8             * OemTableId,
87   IN        UINT32              OemRevision,
88   OUT       AML_ROOT_NODE    ** NewRootNode
89   )
90 {
91   EFI_STATUS                      Status;
92   EFI_ACPI_DESCRIPTION_HEADER     AcpiHeader;
93 
94   if ((TableSignature == NULL)  ||
95       (OemId == NULL)           ||
96       (OemTableId == NULL)      ||
97       (NewRootNode == NULL)) {
98     ASSERT (0);
99     return EFI_INVALID_PARAMETER;
100   }
101 
102   CopyMem (&AcpiHeader.Signature, TableSignature, 4);
103   AcpiHeader.Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
104   AcpiHeader.Revision = 2;
105   CopyMem (&AcpiHeader.OemId, OemId, 6);
106   CopyMem (&AcpiHeader.OemTableId, OemTableId, 8);
107   AcpiHeader.OemRevision = OemRevision;
108   AcpiHeader.CreatorId = TABLE_GENERATOR_CREATOR_ID_ARM;
109   AcpiHeader.CreatorRevision = CREATE_REVISION (1, 0);
110 
111   Status = AmlCreateRootNode (&AcpiHeader, NewRootNode);
112   ASSERT_EFI_ERROR (Status);
113 
114   return Status;
115 }
116 
117 /** AML code generation for a String object node.
118 
119   @param [in]  String          Pointer to a NULL terminated string.
120   @param [out] NewObjectNode   If success, contains the created
121                                String object node.
122 
123   @retval EFI_SUCCESS             Success.
124   @retval EFI_INVALID_PARAMETER   Invalid parameter.
125   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
126 **/
127 STATIC
128 EFI_STATUS
129 EFIAPI
AmlCodeGenString(IN CHAR8 * String,OUT AML_OBJECT_NODE ** NewObjectNode)130 AmlCodeGenString (
131   IN  CHAR8               * String,
132   OUT AML_OBJECT_NODE    ** NewObjectNode
133   )
134 {
135   EFI_STATUS          Status;
136   AML_OBJECT_NODE   * ObjectNode;
137   AML_DATA_NODE     * DataNode;
138 
139   if ((String == NULL)  ||
140       (NewObjectNode == NULL)) {
141     ASSERT (0);
142     return EFI_INVALID_PARAMETER;
143   }
144 
145   ObjectNode = NULL;
146   DataNode = NULL;
147 
148   Status = AmlCreateObjectNode (
149              AmlGetByteEncodingByOpCode (AML_STRING_PREFIX, 0),
150              0,
151              &ObjectNode
152              );
153   if (EFI_ERROR (Status)) {
154     ASSERT (0);
155     return Status;
156   }
157 
158   Status = AmlCreateDataNode (
159              EAmlNodeDataTypeString,
160              (UINT8*)String,
161              (UINT32)AsciiStrLen (String) + 1,
162              &DataNode
163              );
164   if (EFI_ERROR (Status)) {
165     ASSERT (0);
166     goto error_handler;
167   }
168 
169   Status = AmlSetFixedArgument (
170              ObjectNode,
171              EAmlParseIndexTerm0,
172              (AML_NODE_HEADER*)DataNode
173              );
174   if (EFI_ERROR (Status)) {
175     ASSERT (0);
176     AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
177     goto error_handler;
178   }
179 
180   *NewObjectNode = ObjectNode;
181   return Status;
182 
183 error_handler:
184   if (ObjectNode != NULL) {
185     AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
186   }
187 
188   return Status;
189 }
190 
191 /** AML code generation for an Integer object node.
192 
193   @param [in]  Integer         Integer of the Integer object node.
194   @param [out] NewObjectNode   If success, contains the created
195                                Integer object node.
196 
197   @retval EFI_SUCCESS             Success.
198   @retval EFI_INVALID_PARAMETER   Invalid parameter.
199   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
200 **/
201 STATIC
202 EFI_STATUS
203 EFIAPI
AmlCodeGenInteger(IN UINT64 Integer,OUT AML_OBJECT_NODE ** NewObjectNode)204 AmlCodeGenInteger (
205   IN  UINT64                Integer,
206   OUT AML_OBJECT_NODE    ** NewObjectNode
207   )
208 {
209   EFI_STATUS          Status;
210   INT8                ValueWidthDiff;
211 
212   if (NewObjectNode == NULL) {
213     ASSERT (0);
214     return EFI_INVALID_PARAMETER;
215   }
216 
217    // Create an object node containing Zero.
218    Status = AmlCreateObjectNode (
219              AmlGetByteEncodingByOpCode (AML_ZERO_OP, 0),
220              0,
221              NewObjectNode
222              );
223   if (EFI_ERROR (Status)) {
224     ASSERT (0);
225     return Status;
226   }
227 
228   // Update the object node with integer value.
229   Status = AmlNodeSetIntegerValue (*NewObjectNode, Integer, &ValueWidthDiff);
230   if (EFI_ERROR (Status)) {
231     ASSERT (0);
232     AmlDeleteTree ((AML_NODE_HEADER*)*NewObjectNode);
233   }
234 
235   return Status;
236 }
237 
238 /** AML code generation for a Name object node.
239 
240   @param  [in] NameString     The new variable name.
241                               Must be a NULL-terminated ASL NameString
242                               e.g.: "DEV0", "DV15.DEV0", etc.
243                               This input string is copied.
244   @param [in]  Object         Object associated to the NameString.
245   @param [in]  ParentNode     If provided, set ParentNode as the parent
246                               of the node created.
247   @param [out] NewObjectNode  If success, contains the created node.
248 
249   @retval EFI_SUCCESS             Success.
250   @retval EFI_INVALID_PARAMETER   Invalid parameter.
251   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
252 **/
253 STATIC
254 EFI_STATUS
255 EFIAPI
AmlCodeGenName(IN CONST CHAR8 * NameString,IN AML_OBJECT_NODE * Object,IN AML_NODE_HEADER * ParentNode,OPTIONAL OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL)256 AmlCodeGenName (
257   IN  CONST CHAR8              * NameString,
258   IN        AML_OBJECT_NODE    * Object,
259   IN        AML_NODE_HEADER    * ParentNode,     OPTIONAL
260   OUT       AML_OBJECT_NODE   ** NewObjectNode   OPTIONAL
261   )
262 {
263   EFI_STATUS          Status;
264   AML_OBJECT_NODE   * ObjectNode;
265   AML_DATA_NODE     * DataNode;
266   CHAR8             * AmlNameString;
267   UINT32              AmlNameStringSize;
268 
269   if ((NameString == NULL)    ||
270       (Object == NULL)        ||
271       ((ParentNode == NULL) && (NewObjectNode == NULL))) {
272     ASSERT (0);
273     return EFI_INVALID_PARAMETER;
274   }
275 
276   ObjectNode = NULL;
277   DataNode = NULL;
278   AmlNameString = NULL;
279 
280   Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
281   if (EFI_ERROR (Status)) {
282     ASSERT (0);
283     return Status;
284   }
285 
286   Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
287   if (EFI_ERROR (Status)) {
288     ASSERT (0);
289     goto error_handler1;
290   }
291 
292   Status = AmlCreateObjectNode (
293              AmlGetByteEncodingByOpCode (AML_NAME_OP, 0),
294              0,
295              &ObjectNode
296              );
297   if (EFI_ERROR (Status)) {
298     ASSERT (0);
299     goto error_handler1;
300   }
301 
302   Status = AmlCreateDataNode (
303              EAmlNodeDataTypeNameString,
304              (UINT8*)AmlNameString,
305              AmlNameStringSize,
306              &DataNode
307              );
308   if (EFI_ERROR (Status)) {
309     ASSERT (0);
310     goto error_handler2;
311   }
312 
313   Status = AmlSetFixedArgument (
314              ObjectNode,
315              EAmlParseIndexTerm0,
316              (AML_NODE_HEADER*)DataNode
317              );
318   if (EFI_ERROR (Status)) {
319     ASSERT (0);
320     AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
321     goto error_handler2;
322   }
323 
324   Status = AmlSetFixedArgument (
325              ObjectNode,
326              EAmlParseIndexTerm1,
327              (AML_NODE_HEADER*)Object
328              );
329   if (EFI_ERROR (Status)) {
330     ASSERT (0);
331     goto error_handler2;
332   }
333 
334   Status = LinkNode (
335              ObjectNode,
336              ParentNode,
337              NewObjectNode
338              );
339   if (EFI_ERROR (Status)) {
340     ASSERT (0);
341     goto error_handler2;
342   }
343 
344   // Free AmlNameString before returning as it is copied
345   // in the call to AmlCreateDataNode().
346   goto error_handler1;
347 
348 error_handler2:
349   if (ObjectNode != NULL) {
350     AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
351   }
352 
353 error_handler1:
354   if (AmlNameString != NULL) {
355     FreePool (AmlNameString);
356   }
357 
358   return Status;
359 }
360 
361 /** AML code generation for a Name object node, containing a String.
362 
363   AmlCodeGenNameString ("_HID", "HID0000", ParentNode, NewObjectNode) is
364   equivalent of the following ASL code:
365     Name(_HID, "HID0000")
366 
367   @param  [in] NameString     The new variable name.
368                               Must be a NULL-terminated ASL NameString
369                               e.g.: "DEV0", "DV15.DEV0", etc.
370                               The input string is copied.
371   @param [in]  String         NULL terminated String to associate to the
372                               NameString.
373   @param [in]  ParentNode     If provided, set ParentNode as the parent
374                               of the node created.
375   @param [out] NewObjectNode  If success, contains the created node.
376 
377   @retval EFI_SUCCESS             Success.
378   @retval EFI_INVALID_PARAMETER   Invalid parameter.
379   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
380 **/
381 EFI_STATUS
382 EFIAPI
AmlCodeGenNameString(IN CONST CHAR8 * NameString,IN CHAR8 * String,IN AML_NODE_HEADER * ParentNode,OPTIONAL OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL)383 AmlCodeGenNameString (
384   IN  CONST CHAR8              * NameString,
385   IN        CHAR8              * String,
386   IN        AML_NODE_HEADER    * ParentNode,     OPTIONAL
387   OUT       AML_OBJECT_NODE   ** NewObjectNode   OPTIONAL
388   )
389 {
390   EFI_STATUS          Status;
391   AML_OBJECT_NODE   * ObjectNode;
392 
393   if ((NameString == NULL)  ||
394       (String == NULL)      ||
395       ((ParentNode == NULL) && (NewObjectNode == NULL))) {
396     ASSERT (0);
397     return EFI_INVALID_PARAMETER;
398   }
399 
400   Status = AmlCodeGenString (String, &ObjectNode);
401   if (EFI_ERROR (Status)) {
402     ASSERT (0);
403     return Status;
404   }
405 
406   Status = AmlCodeGenName (
407              NameString,
408              ObjectNode,
409              ParentNode,
410              NewObjectNode
411              );
412   if (EFI_ERROR (Status)) {
413     ASSERT (0);
414     AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
415   }
416 
417   return Status;
418 }
419 
420 /** AML code generation for a Name object node, containing an Integer.
421 
422   AmlCodeGenNameInteger ("_UID", 1, ParentNode, NewObjectNode) is
423   equivalent of the following ASL code:
424     Name(_UID, One)
425 
426   @param  [in] NameString     The new variable name.
427                               Must be a NULL-terminated ASL NameString
428                               e.g.: "DEV0", "DV15.DEV0", etc.
429                               The input string is copied.
430   @param [in]  Integer        Integer to associate to the NameString.
431   @param [in]  ParentNode     If provided, set ParentNode as the parent
432                               of the node created.
433   @param [out] NewObjectNode  If success, contains the created node.
434 
435   @retval EFI_SUCCESS             Success.
436   @retval EFI_INVALID_PARAMETER   Invalid parameter.
437   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
438 **/
439 EFI_STATUS
440 EFIAPI
AmlCodeGenNameInteger(IN CONST CHAR8 * NameString,IN UINT64 Integer,IN AML_NODE_HEADER * ParentNode,OPTIONAL OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL)441 AmlCodeGenNameInteger (
442   IN  CONST CHAR8              * NameString,
443   IN        UINT64               Integer,
444   IN        AML_NODE_HEADER    * ParentNode,     OPTIONAL
445   OUT       AML_OBJECT_NODE   ** NewObjectNode   OPTIONAL
446   )
447 {
448   EFI_STATUS          Status;
449   AML_OBJECT_NODE   * ObjectNode;
450 
451   if ((NameString == NULL)  ||
452       ((ParentNode == NULL) && (NewObjectNode == NULL))) {
453     ASSERT (0);
454     return EFI_INVALID_PARAMETER;
455   }
456 
457   Status = AmlCodeGenInteger (Integer, &ObjectNode);
458   if (EFI_ERROR (Status)) {
459     ASSERT (0);
460     return Status;
461   }
462 
463   Status = AmlCodeGenName (
464              NameString,
465              ObjectNode,
466              ParentNode,
467              NewObjectNode
468              );
469   if (EFI_ERROR (Status)) {
470     ASSERT (0);
471     AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
472   }
473 
474   return Status;
475 }
476 
477 /** AML code generation for a Device object node.
478 
479   AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
480   equivalent of the following ASL code:
481     Device(COM0) {}
482 
483   @param  [in] NameString     The new Device's name.
484                               Must be a NULL-terminated ASL NameString
485                               e.g.: "DEV0", "DV15.DEV0", etc.
486                               The input string is copied.
487   @param [in]  ParentNode     If provided, set ParentNode as the parent
488                               of the node created.
489   @param [out] NewObjectNode  If success, contains the created node.
490 
491   @retval EFI_SUCCESS             Success.
492   @retval EFI_INVALID_PARAMETER   Invalid parameter.
493   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
494 **/
495 EFI_STATUS
496 EFIAPI
AmlCodeGenDevice(IN CONST CHAR8 * NameString,IN AML_NODE_HEADER * ParentNode,OPTIONAL OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL)497 AmlCodeGenDevice (
498   IN  CONST CHAR8              * NameString,
499   IN        AML_NODE_HEADER    * ParentNode,     OPTIONAL
500   OUT       AML_OBJECT_NODE   ** NewObjectNode   OPTIONAL
501   )
502 {
503   EFI_STATUS          Status;
504   AML_OBJECT_NODE   * ObjectNode;
505   AML_DATA_NODE     * DataNode;
506   CHAR8             * AmlNameString;
507   UINT32              AmlNameStringSize;
508 
509   if ((NameString == NULL)  ||
510       ((ParentNode == NULL) && (NewObjectNode == NULL))) {
511     ASSERT (0);
512     return EFI_INVALID_PARAMETER;
513   }
514 
515   ObjectNode = NULL;
516   DataNode = NULL;
517   AmlNameString = NULL;
518 
519   Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
520   if (EFI_ERROR (Status)) {
521     ASSERT (0);
522     return Status;
523   }
524 
525   Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
526   if (EFI_ERROR (Status)) {
527     ASSERT (0);
528     goto error_handler1;
529   }
530 
531   Status = AmlCreateObjectNode (
532              AmlGetByteEncodingByOpCode (AML_EXT_OP, AML_EXT_DEVICE_OP),
533              AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize),
534              &ObjectNode
535              );
536   if (EFI_ERROR (Status)) {
537     ASSERT (0);
538     goto error_handler1;
539   }
540 
541   Status = AmlCreateDataNode (
542              EAmlNodeDataTypeNameString,
543              (UINT8*)AmlNameString,
544              AmlNameStringSize,
545              &DataNode
546              );
547   if (EFI_ERROR (Status)) {
548     ASSERT (0);
549     goto error_handler2;
550   }
551 
552   Status = AmlSetFixedArgument (
553              ObjectNode,
554              EAmlParseIndexTerm0,
555              (AML_NODE_HEADER*)DataNode
556              );
557   if (EFI_ERROR (Status)) {
558     ASSERT (0);
559     AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
560     goto error_handler2;
561   }
562 
563   Status = LinkNode (
564              ObjectNode,
565              ParentNode,
566              NewObjectNode
567              );
568   if (EFI_ERROR (Status)) {
569     ASSERT (0);
570     goto error_handler2;
571   }
572 
573   // Free AmlNameString before returning as it is copied
574   // in the call to AmlCreateDataNode().
575   goto error_handler1;
576 
577 error_handler2:
578   if (ObjectNode != NULL) {
579     AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
580   }
581 
582 error_handler1:
583   if (AmlNameString != NULL) {
584     FreePool (AmlNameString);
585   }
586 
587   return Status;
588 }
589 
590 /** AML code generation for a Scope object node.
591 
592   AmlCodeGenScope ("_SB", ParentNode, NewObjectNode) is
593   equivalent of the following ASL code:
594     Scope(_SB) {}
595 
596   @param  [in] NameString     The new Scope's name.
597                               Must be a NULL-terminated ASL NameString
598                               e.g.: "DEV0", "DV15.DEV0", etc.
599                               The input string is copied.
600   @param [in]  ParentNode     If provided, set ParentNode as the parent
601                               of the node created.
602   @param [out] NewObjectNode  If success, contains the created node.
603 
604   @retval EFI_SUCCESS             Success.
605   @retval EFI_INVALID_PARAMETER   Invalid parameter.
606   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
607 **/
608 EFI_STATUS
609 EFIAPI
AmlCodeGenScope(IN CONST CHAR8 * NameString,IN AML_NODE_HEADER * ParentNode,OPTIONAL OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL)610 AmlCodeGenScope (
611   IN  CONST CHAR8              * NameString,
612   IN        AML_NODE_HEADER    * ParentNode,     OPTIONAL
613   OUT       AML_OBJECT_NODE   ** NewObjectNode   OPTIONAL
614   )
615 {
616   EFI_STATUS          Status;
617   AML_OBJECT_NODE   * ObjectNode;
618   AML_DATA_NODE     * DataNode;
619   CHAR8             * AmlNameString;
620   UINT32              AmlNameStringSize;
621 
622   if ((NameString == NULL)  ||
623       ((ParentNode == NULL) && (NewObjectNode == NULL))) {
624     ASSERT (0);
625     return EFI_INVALID_PARAMETER;
626   }
627 
628   ObjectNode = NULL;
629   DataNode = NULL;
630   AmlNameString = NULL;
631 
632   Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
633   if (EFI_ERROR (Status)) {
634     ASSERT (0);
635     return Status;
636   }
637 
638   Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
639   if (EFI_ERROR (Status)) {
640     ASSERT (0);
641     goto error_handler1;
642   }
643 
644   Status = AmlCreateObjectNode (
645              AmlGetByteEncodingByOpCode (AML_SCOPE_OP, 0),
646              AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize),
647              &ObjectNode
648              );
649   if (EFI_ERROR (Status)) {
650     ASSERT (0);
651     goto error_handler1;
652   }
653 
654   Status = AmlCreateDataNode (
655              EAmlNodeDataTypeNameString,
656              (UINT8*)AmlNameString,
657              AmlNameStringSize,
658              &DataNode
659              );
660   if (EFI_ERROR (Status)) {
661     ASSERT (0);
662     goto error_handler2;
663   }
664 
665   Status = AmlSetFixedArgument (
666              ObjectNode,
667              EAmlParseIndexTerm0,
668              (AML_NODE_HEADER*)DataNode
669              );
670   if (EFI_ERROR (Status)) {
671     ASSERT (0);
672     AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
673     goto error_handler2;
674   }
675 
676   Status = LinkNode (
677              ObjectNode,
678              ParentNode,
679              NewObjectNode
680              );
681   if (EFI_ERROR (Status)) {
682     ASSERT (0);
683     goto error_handler2;
684   }
685 
686   // Free AmlNameString before returning as it is copied
687   // in the call to AmlCreateDataNode().
688   goto error_handler1;
689 
690 error_handler2:
691   if (ObjectNode != NULL) {
692     AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
693   }
694 
695 error_handler1:
696   if (AmlNameString != NULL) {
697     FreePool (AmlNameString);
698   }
699 
700   return Status;
701 }
702