]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
DynamicTablesPkg: AML code generation to Return a NameString
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / CodeGen / AmlCodeGen.c
1 /** @file
2 AML Code Generation.
3
4 Copyright (c) 2020 - 2021, 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 <CodeGen/AmlResourceDataCodeGen.h>
16 #include <Tree/AmlNode.h>
17 #include <Tree/AmlTree.h>
18 #include <String/AmlString.h>
19 #include <Utils/AmlUtility.h>
20
21 /** Utility function to link a node when returning from a CodeGen function.
22
23 @param [in] Node Newly created node.
24 @param [in] ParentNode If provided, set ParentNode as the parent
25 of the node created.
26 @param [out] NewObjectNode If not NULL:
27 - and Success, contains the created Node.
28 - and Error, reset to NULL.
29
30 @retval EFI_SUCCESS The function completed successfully.
31 @retval EFI_INVALID_PARAMETER Invalid parameter.
32 **/
33 STATIC
34 EFI_STATUS
35 EFIAPI
36 LinkNode (
37 IN AML_OBJECT_NODE * Node,
38 IN AML_NODE_HEADER * ParentNode,
39 OUT AML_OBJECT_NODE ** NewObjectNode
40 )
41 {
42 EFI_STATUS Status;
43
44 if (NewObjectNode != NULL) {
45 *NewObjectNode = NULL;
46 }
47
48 // Add RdNode as the last element.
49 if (ParentNode != NULL) {
50 Status = AmlVarListAddTail (ParentNode, (AML_NODE_HEADER*)Node);
51 if (EFI_ERROR (Status)) {
52 ASSERT (0);
53 return Status;
54 }
55 }
56
57 if (NewObjectNode != NULL) {
58 *NewObjectNode = Node;
59 }
60
61 return EFI_SUCCESS;
62 }
63
64 /** AML code generation for DefinitionBlock.
65
66 Create a Root Node handle.
67 It is the caller's responsibility to free the allocated memory
68 with the AmlDeleteTree function.
69
70 AmlCodeGenDefinitionBlock (TableSignature, OemID, TableID, OEMRevision) is
71 equivalent to the following ASL code:
72 DefinitionBlock (AMLFileName, TableSignature, ComplianceRevision,
73 OemID, TableID, OEMRevision) {}
74 with the ComplianceRevision set to 2 and the AMLFileName is ignored.
75
76 @param[in] TableSignature 4-character ACPI signature.
77 Must be 'DSDT' or 'SSDT'.
78 @param[in] OemId 6-character string OEM identifier.
79 @param[in] OemTableId 8-character string OEM table identifier.
80 @param[in] OemRevision OEM revision number.
81 @param[out] NewRootNode Pointer to the root node representing a
82 Definition Block.
83
84 @retval EFI_SUCCESS Success.
85 @retval EFI_INVALID_PARAMETER Invalid parameter.
86 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
87 **/
88 EFI_STATUS
89 EFIAPI
90 AmlCodeGenDefinitionBlock (
91 IN CONST CHAR8 * TableSignature,
92 IN CONST CHAR8 * OemId,
93 IN CONST CHAR8 * OemTableId,
94 IN UINT32 OemRevision,
95 OUT AML_ROOT_NODE ** NewRootNode
96 )
97 {
98 EFI_STATUS Status;
99 EFI_ACPI_DESCRIPTION_HEADER AcpiHeader;
100
101 if ((TableSignature == NULL) ||
102 (OemId == NULL) ||
103 (OemTableId == NULL) ||
104 (NewRootNode == NULL)) {
105 ASSERT (0);
106 return EFI_INVALID_PARAMETER;
107 }
108
109 CopyMem (&AcpiHeader.Signature, TableSignature, 4);
110 AcpiHeader.Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
111 AcpiHeader.Revision = 2;
112 CopyMem (&AcpiHeader.OemId, OemId, 6);
113 CopyMem (&AcpiHeader.OemTableId, OemTableId, 8);
114 AcpiHeader.OemRevision = OemRevision;
115 AcpiHeader.CreatorId = TABLE_GENERATOR_CREATOR_ID_ARM;
116 AcpiHeader.CreatorRevision = CREATE_REVISION (1, 0);
117
118 Status = AmlCreateRootNode (&AcpiHeader, NewRootNode);
119 ASSERT_EFI_ERROR (Status);
120
121 return Status;
122 }
123
124 /** AML code generation for a String object node.
125
126 @param [in] String Pointer to a NULL terminated string.
127 @param [out] NewObjectNode If success, contains the created
128 String object node.
129
130 @retval EFI_SUCCESS Success.
131 @retval EFI_INVALID_PARAMETER Invalid parameter.
132 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
133 **/
134 STATIC
135 EFI_STATUS
136 EFIAPI
137 AmlCodeGenString (
138 IN CHAR8 * String,
139 OUT AML_OBJECT_NODE ** NewObjectNode
140 )
141 {
142 EFI_STATUS Status;
143 AML_OBJECT_NODE * ObjectNode;
144 AML_DATA_NODE * DataNode;
145
146 if ((String == NULL) ||
147 (NewObjectNode == NULL)) {
148 ASSERT (0);
149 return EFI_INVALID_PARAMETER;
150 }
151
152 DataNode = NULL;
153
154 Status = AmlCreateObjectNode (
155 AmlGetByteEncodingByOpCode (AML_STRING_PREFIX, 0),
156 0,
157 &ObjectNode
158 );
159 if (EFI_ERROR (Status)) {
160 ASSERT (0);
161 return Status;
162 }
163
164 Status = AmlCreateDataNode (
165 EAmlNodeDataTypeString,
166 (UINT8*)String,
167 (UINT32)AsciiStrLen (String) + 1,
168 &DataNode
169 );
170 if (EFI_ERROR (Status)) {
171 ASSERT (0);
172 goto error_handler;
173 }
174
175 Status = AmlSetFixedArgument (
176 ObjectNode,
177 EAmlParseIndexTerm0,
178 (AML_NODE_HEADER*)DataNode
179 );
180 if (EFI_ERROR (Status)) {
181 ASSERT (0);
182 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
183 goto error_handler;
184 }
185
186 *NewObjectNode = ObjectNode;
187 return Status;
188
189 error_handler:
190 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
191 return Status;
192 }
193
194 /** AML code generation for an Integer object node.
195
196 @param [in] Integer Integer of the Integer object node.
197 @param [out] NewObjectNode If success, contains the created
198 Integer object node.
199
200 @retval EFI_SUCCESS Success.
201 @retval EFI_INVALID_PARAMETER Invalid parameter.
202 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
203 **/
204 STATIC
205 EFI_STATUS
206 EFIAPI
207 AmlCodeGenInteger (
208 IN UINT64 Integer,
209 OUT AML_OBJECT_NODE ** NewObjectNode
210 )
211 {
212 EFI_STATUS Status;
213 INT8 ValueWidthDiff;
214
215 if (NewObjectNode == NULL) {
216 ASSERT (0);
217 return EFI_INVALID_PARAMETER;
218 }
219
220 // Create an object node containing Zero.
221 Status = AmlCreateObjectNode (
222 AmlGetByteEncodingByOpCode (AML_ZERO_OP, 0),
223 0,
224 NewObjectNode
225 );
226 if (EFI_ERROR (Status)) {
227 ASSERT (0);
228 return Status;
229 }
230
231 // Update the object node with integer value.
232 Status = AmlNodeSetIntegerValue (*NewObjectNode, Integer, &ValueWidthDiff);
233 if (EFI_ERROR (Status)) {
234 ASSERT (0);
235 AmlDeleteTree ((AML_NODE_HEADER*)*NewObjectNode);
236 }
237
238 return Status;
239 }
240
241 /** AML code generation for a Package object node.
242
243 The package generated is empty. New elements can be added via its
244 list of variable arguments.
245
246 @param [out] NewObjectNode If success, contains the created
247 Package object 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
256 AmlCodeGenPackage (
257 OUT AML_OBJECT_NODE ** NewObjectNode
258 )
259 {
260 EFI_STATUS Status;
261 AML_DATA_NODE * DataNode;
262 UINT8 NodeCount;
263
264 if (NewObjectNode == NULL) {
265 ASSERT (0);
266 return EFI_INVALID_PARAMETER;
267 }
268
269 NodeCount = 0;
270
271 // Create an object node.
272 // PkgLen is 2:
273 // - one byte to store the PkgLength
274 // - one byte for the NumElements.
275 // Cf ACPI6.3, s20.2.5 "Term Objects Encoding"
276 // DefPackage := PackageOp PkgLength NumElements PackageElementList
277 // NumElements := ByteData
278 Status = AmlCreateObjectNode (
279 AmlGetByteEncodingByOpCode (AML_PACKAGE_OP, 0),
280 2,
281 NewObjectNode
282 );
283 if (EFI_ERROR (Status)) {
284 ASSERT (0);
285 return Status;
286 }
287
288 // NumElements is a ByteData.
289 Status = AmlCreateDataNode (
290 EAmlNodeDataTypeUInt,
291 &NodeCount,
292 sizeof (NodeCount),
293 &DataNode
294 );
295 if (EFI_ERROR (Status)) {
296 ASSERT (0);
297 goto error_handler;
298 }
299
300 Status = AmlSetFixedArgument (
301 *NewObjectNode,
302 EAmlParseIndexTerm0,
303 (AML_NODE_HEADER*)DataNode
304 );
305 if (EFI_ERROR (Status)) {
306 ASSERT (0);
307 goto error_handler;
308 }
309
310 return Status;
311
312 error_handler:
313 AmlDeleteTree ((AML_NODE_HEADER*)*NewObjectNode);
314 if (DataNode != NULL) {
315 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
316 }
317 return Status;
318 }
319
320 /** AML code generation for a Buffer object node.
321
322 To create a Buffer object node with an empty buffer,
323 call the function with (Buffer=NULL, BufferSize=0).
324
325 @param [in] Buffer Buffer to set for the created Buffer
326 object node. The Buffer's content is copied.
327 NULL if there is no buffer to set for
328 the Buffer node.
329 @param [in] BufferSize Size of the Buffer.
330 0 if there is no buffer to set for
331 the Buffer node.
332 @param [out] NewObjectNode If success, contains the created
333 Buffer object node.
334
335 @retval EFI_SUCCESS Success.
336 @retval EFI_INVALID_PARAMETER Invalid parameter.
337 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
338 **/
339 STATIC
340 EFI_STATUS
341 EFIAPI
342 AmlCodeGenBuffer (
343 IN CONST UINT8 * Buffer, OPTIONAL
344 IN UINT32 BufferSize, OPTIONAL
345 OUT AML_OBJECT_NODE ** NewObjectNode
346 )
347 {
348 EFI_STATUS Status;
349 AML_OBJECT_NODE * BufferNode;
350 AML_OBJECT_NODE * BufferSizeNode;
351 UINT32 BufferSizeNodeSize;
352 AML_DATA_NODE * DataNode;
353 UINT32 PkgLen;
354
355 // Buffer and BufferSize must be either both set, or both clear.
356 if ((NewObjectNode == NULL) ||
357 ((Buffer == NULL) != (BufferSize == 0))) {
358 ASSERT (0);
359 return EFI_INVALID_PARAMETER;
360 }
361
362 BufferNode = NULL;
363 DataNode = NULL;
364
365 // Cf ACPI 6.3 specification, s20.2.5.4 "Type 2 Opcodes Encoding"
366 // DefBuffer := BufferOp PkgLength BufferSize ByteList
367 // BufferOp := 0x11
368 // BufferSize := TermArg => Integer
369
370 Status = AmlCodeGenInteger (BufferSize, &BufferSizeNode);
371 if (EFI_ERROR (Status)) {
372 ASSERT (0);
373 return Status;
374 }
375
376 // Get the number of bytes required to encode the BufferSizeNode.
377 Status = AmlComputeSize (
378 (AML_NODE_HEADER*)BufferSizeNode,
379 &BufferSizeNodeSize
380 );
381 if (EFI_ERROR (Status)) {
382 ASSERT (0);
383 goto error_handler;
384 }
385
386 // Compute the size to write in the PkgLen.
387 Status = AmlComputePkgLength (BufferSizeNodeSize + BufferSize, &PkgLen);
388 if (EFI_ERROR (Status)) {
389 ASSERT (0);
390 goto error_handler;
391 }
392
393 // Create an object node for the buffer.
394 Status = AmlCreateObjectNode (
395 AmlGetByteEncodingByOpCode (AML_BUFFER_OP, 0),
396 PkgLen,
397 &BufferNode
398 );
399 if (EFI_ERROR (Status)) {
400 ASSERT (0);
401 goto error_handler;
402 }
403
404 // Set the BufferSizeNode as a fixed argument of the BufferNode.
405 Status = AmlSetFixedArgument (
406 BufferNode,
407 EAmlParseIndexTerm0,
408 (AML_NODE_HEADER*)BufferSizeNode
409 );
410 if (EFI_ERROR (Status)) {
411 ASSERT (0);
412 goto error_handler;
413 }
414
415 // BufferSizeNode is now attached.
416 BufferSizeNode = NULL;
417
418 // If there is a buffer, create a DataNode and attach it to the BufferNode.
419 if (Buffer != NULL) {
420 Status = AmlCreateDataNode (
421 EAmlNodeDataTypeRaw,
422 Buffer,
423 BufferSize,
424 &DataNode
425 );
426 if (EFI_ERROR (Status)) {
427 ASSERT (0);
428 goto error_handler;
429 }
430
431 Status = AmlVarListAddTail (
432 (AML_NODE_HEADER*)BufferNode,
433 (AML_NODE_HEADER*)DataNode
434 );
435 if (EFI_ERROR (Status)) {
436 ASSERT (0);
437 goto error_handler;
438 }
439 }
440
441 *NewObjectNode = BufferNode;
442 return Status;
443
444 error_handler:
445 if (BufferSizeNode != NULL) {
446 AmlDeleteTree ((AML_NODE_HEADER*)BufferSizeNode);
447 }
448 if (BufferNode != NULL) {
449 AmlDeleteTree ((AML_NODE_HEADER*)BufferNode);
450 }
451 if (DataNode != NULL) {
452 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
453 }
454 return Status;
455 }
456
457 /** AML code generation for a ResourceTemplate.
458
459 "ResourceTemplate" is a macro defined in ACPI 6.3, s19.3.3
460 "ASL Resource Templates". It allows to store resource data elements.
461
462 In AML, a ResourceTemplate is implemented as a Buffer storing resource
463 data elements. An EndTag resource data descriptor must be at the end
464 of the list of resource data elements.
465 This function generates a Buffer node with an EndTag resource data
466 descriptor. It can be seen as an empty list of resource data elements.
467
468 @param [out] NewObjectNode If success, contains the created
469 ResourceTemplate object node.
470
471 @retval EFI_SUCCESS Success.
472 @retval EFI_INVALID_PARAMETER Invalid parameter.
473 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
474 **/
475 STATIC
476 EFI_STATUS
477 EFIAPI
478 AmlCodeGenResourceTemplate (
479 OUT AML_OBJECT_NODE ** NewObjectNode
480 )
481 {
482 EFI_STATUS Status;
483 AML_OBJECT_NODE * BufferNode;
484
485 if (NewObjectNode == NULL) {
486 ASSERT (0);
487 return EFI_INVALID_PARAMETER;
488 }
489
490 // Create a BufferNode with an empty buffer.
491 Status = AmlCodeGenBuffer (NULL, 0, &BufferNode);
492 if (EFI_ERROR (Status)) {
493 ASSERT (0);
494 return Status;
495 }
496
497 // Create an EndTag resource data element and attach it to the Buffer.
498 Status = AmlCodeGenEndTag (0, BufferNode, NULL);
499 if (EFI_ERROR (Status)) {
500 ASSERT (0);
501 AmlDeleteTree ((AML_NODE_HEADER*)BufferNode);
502 return Status;
503 }
504
505 *NewObjectNode = BufferNode;
506 return Status;
507 }
508
509 /** AML code generation for a Name object node.
510
511 @param [in] NameString The new variable name.
512 Must be a NULL-terminated ASL NameString
513 e.g.: "DEV0", "DV15.DEV0", etc.
514 This input string is copied.
515 @param [in] Object Object associated to the NameString.
516 @param [in] ParentNode If provided, set ParentNode as the parent
517 of the node created.
518 @param [out] NewObjectNode If success, contains the created node.
519
520 @retval EFI_SUCCESS Success.
521 @retval EFI_INVALID_PARAMETER Invalid parameter.
522 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
523 **/
524 STATIC
525 EFI_STATUS
526 EFIAPI
527 AmlCodeGenName (
528 IN CONST CHAR8 * NameString,
529 IN AML_OBJECT_NODE * Object,
530 IN AML_NODE_HEADER * ParentNode, OPTIONAL
531 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
532 )
533 {
534 EFI_STATUS Status;
535 AML_OBJECT_NODE * ObjectNode;
536 AML_DATA_NODE * DataNode;
537 CHAR8 * AmlNameString;
538 UINT32 AmlNameStringSize;
539
540 if ((NameString == NULL) ||
541 (Object == NULL) ||
542 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
543 ASSERT (0);
544 return EFI_INVALID_PARAMETER;
545 }
546
547 ObjectNode = NULL;
548 DataNode = NULL;
549 AmlNameString = NULL;
550
551 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
552 if (EFI_ERROR (Status)) {
553 ASSERT (0);
554 return Status;
555 }
556
557 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
558 if (EFI_ERROR (Status)) {
559 ASSERT (0);
560 goto error_handler1;
561 }
562
563 Status = AmlCreateObjectNode (
564 AmlGetByteEncodingByOpCode (AML_NAME_OP, 0),
565 0,
566 &ObjectNode
567 );
568 if (EFI_ERROR (Status)) {
569 ASSERT (0);
570 goto error_handler1;
571 }
572
573 Status = AmlCreateDataNode (
574 EAmlNodeDataTypeNameString,
575 (UINT8*)AmlNameString,
576 AmlNameStringSize,
577 &DataNode
578 );
579 if (EFI_ERROR (Status)) {
580 ASSERT (0);
581 goto error_handler2;
582 }
583
584 Status = AmlSetFixedArgument (
585 ObjectNode,
586 EAmlParseIndexTerm0,
587 (AML_NODE_HEADER*)DataNode
588 );
589 if (EFI_ERROR (Status)) {
590 ASSERT (0);
591 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
592 goto error_handler2;
593 }
594
595 Status = AmlSetFixedArgument (
596 ObjectNode,
597 EAmlParseIndexTerm1,
598 (AML_NODE_HEADER*)Object
599 );
600 if (EFI_ERROR (Status)) {
601 ASSERT (0);
602 goto error_handler2;
603 }
604
605 Status = LinkNode (
606 ObjectNode,
607 ParentNode,
608 NewObjectNode
609 );
610 if (EFI_ERROR (Status)) {
611 ASSERT (0);
612 goto error_handler2;
613 }
614
615 // Free AmlNameString before returning as it is copied
616 // in the call to AmlCreateDataNode().
617 goto error_handler1;
618
619 error_handler2:
620 if (ObjectNode != NULL) {
621 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
622 }
623
624 error_handler1:
625 if (AmlNameString != NULL) {
626 FreePool (AmlNameString);
627 }
628
629 return Status;
630 }
631
632 /** AML code generation for a Name object node, containing a String.
633
634 AmlCodeGenNameString ("_HID", "HID0000", ParentNode, NewObjectNode) is
635 equivalent of the following ASL code:
636 Name(_HID, "HID0000")
637
638 @param [in] NameString The new variable name.
639 Must be a NULL-terminated ASL NameString
640 e.g.: "DEV0", "DV15.DEV0", etc.
641 The input string is copied.
642 @param [in] String NULL terminated String to associate to the
643 NameString.
644 @param [in] ParentNode If provided, set ParentNode as the parent
645 of the node created.
646 @param [out] NewObjectNode If success, contains the created node.
647
648 @retval EFI_SUCCESS Success.
649 @retval EFI_INVALID_PARAMETER Invalid parameter.
650 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
651 **/
652 EFI_STATUS
653 EFIAPI
654 AmlCodeGenNameString (
655 IN CONST CHAR8 * NameString,
656 IN CHAR8 * String,
657 IN AML_NODE_HEADER * ParentNode, OPTIONAL
658 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
659 )
660 {
661 EFI_STATUS Status;
662 AML_OBJECT_NODE * ObjectNode;
663
664 if ((NameString == NULL) ||
665 (String == NULL) ||
666 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
667 ASSERT (0);
668 return EFI_INVALID_PARAMETER;
669 }
670
671 Status = AmlCodeGenString (String, &ObjectNode);
672 if (EFI_ERROR (Status)) {
673 ASSERT (0);
674 return Status;
675 }
676
677 Status = AmlCodeGenName (
678 NameString,
679 ObjectNode,
680 ParentNode,
681 NewObjectNode
682 );
683 if (EFI_ERROR (Status)) {
684 ASSERT (0);
685 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
686 }
687
688 return Status;
689 }
690
691 /** AML code generation for a Name object node, containing an Integer.
692
693 AmlCodeGenNameInteger ("_UID", 1, ParentNode, NewObjectNode) is
694 equivalent of the following ASL code:
695 Name(_UID, One)
696
697 @param [in] NameString The new variable name.
698 Must be a NULL-terminated ASL NameString
699 e.g.: "DEV0", "DV15.DEV0", etc.
700 The input string is copied.
701 @param [in] Integer Integer to associate to the NameString.
702 @param [in] ParentNode If provided, set ParentNode as the parent
703 of the node created.
704 @param [out] NewObjectNode If success, contains the created node.
705
706 @retval EFI_SUCCESS Success.
707 @retval EFI_INVALID_PARAMETER Invalid parameter.
708 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
709 **/
710 EFI_STATUS
711 EFIAPI
712 AmlCodeGenNameInteger (
713 IN CONST CHAR8 * NameString,
714 IN UINT64 Integer,
715 IN AML_NODE_HEADER * ParentNode, OPTIONAL
716 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
717 )
718 {
719 EFI_STATUS Status;
720 AML_OBJECT_NODE * ObjectNode;
721
722 if ((NameString == NULL) ||
723 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
724 ASSERT (0);
725 return EFI_INVALID_PARAMETER;
726 }
727
728 Status = AmlCodeGenInteger (Integer, &ObjectNode);
729 if (EFI_ERROR (Status)) {
730 ASSERT (0);
731 return Status;
732 }
733
734 Status = AmlCodeGenName (
735 NameString,
736 ObjectNode,
737 ParentNode,
738 NewObjectNode
739 );
740 if (EFI_ERROR (Status)) {
741 ASSERT (0);
742 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
743 }
744
745 return Status;
746 }
747
748 /** AML code generation for a Device object node.
749
750 AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
751 equivalent of the following ASL code:
752 Device(COM0) {}
753
754 @param [in] NameString The new Device's name.
755 Must be a NULL-terminated ASL NameString
756 e.g.: "DEV0", "DV15.DEV0", etc.
757 The input string is copied.
758 @param [in] ParentNode If provided, set ParentNode as the parent
759 of the node created.
760 @param [out] NewObjectNode If success, contains the created node.
761
762 @retval EFI_SUCCESS Success.
763 @retval EFI_INVALID_PARAMETER Invalid parameter.
764 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
765 **/
766 EFI_STATUS
767 EFIAPI
768 AmlCodeGenDevice (
769 IN CONST CHAR8 * NameString,
770 IN AML_NODE_HEADER * ParentNode, OPTIONAL
771 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
772 )
773 {
774 EFI_STATUS Status;
775 AML_OBJECT_NODE * ObjectNode;
776 AML_DATA_NODE * DataNode;
777 CHAR8 * AmlNameString;
778 UINT32 AmlNameStringSize;
779
780 if ((NameString == NULL) ||
781 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
782 ASSERT (0);
783 return EFI_INVALID_PARAMETER;
784 }
785
786 ObjectNode = NULL;
787 DataNode = NULL;
788 AmlNameString = NULL;
789
790 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
791 if (EFI_ERROR (Status)) {
792 ASSERT (0);
793 return Status;
794 }
795
796 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
797 if (EFI_ERROR (Status)) {
798 ASSERT (0);
799 goto error_handler1;
800 }
801
802 Status = AmlCreateObjectNode (
803 AmlGetByteEncodingByOpCode (AML_EXT_OP, AML_EXT_DEVICE_OP),
804 AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize),
805 &ObjectNode
806 );
807 if (EFI_ERROR (Status)) {
808 ASSERT (0);
809 goto error_handler1;
810 }
811
812 Status = AmlCreateDataNode (
813 EAmlNodeDataTypeNameString,
814 (UINT8*)AmlNameString,
815 AmlNameStringSize,
816 &DataNode
817 );
818 if (EFI_ERROR (Status)) {
819 ASSERT (0);
820 goto error_handler2;
821 }
822
823 Status = AmlSetFixedArgument (
824 ObjectNode,
825 EAmlParseIndexTerm0,
826 (AML_NODE_HEADER*)DataNode
827 );
828 if (EFI_ERROR (Status)) {
829 ASSERT (0);
830 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
831 goto error_handler2;
832 }
833
834 Status = LinkNode (
835 ObjectNode,
836 ParentNode,
837 NewObjectNode
838 );
839 if (EFI_ERROR (Status)) {
840 ASSERT (0);
841 goto error_handler2;
842 }
843
844 // Free AmlNameString before returning as it is copied
845 // in the call to AmlCreateDataNode().
846 goto error_handler1;
847
848 error_handler2:
849 if (ObjectNode != NULL) {
850 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
851 }
852
853 error_handler1:
854 if (AmlNameString != NULL) {
855 FreePool (AmlNameString);
856 }
857
858 return Status;
859 }
860
861 /** AML code generation for a Scope object node.
862
863 AmlCodeGenScope ("_SB", ParentNode, NewObjectNode) is
864 equivalent of the following ASL code:
865 Scope(_SB) {}
866
867 @param [in] NameString The new Scope's name.
868 Must be a NULL-terminated ASL NameString
869 e.g.: "DEV0", "DV15.DEV0", etc.
870 The input string is copied.
871 @param [in] ParentNode If provided, set ParentNode as the parent
872 of the node created.
873 @param [out] NewObjectNode If success, contains the created node.
874
875 @retval EFI_SUCCESS Success.
876 @retval EFI_INVALID_PARAMETER Invalid parameter.
877 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
878 **/
879 EFI_STATUS
880 EFIAPI
881 AmlCodeGenScope (
882 IN CONST CHAR8 * NameString,
883 IN AML_NODE_HEADER * ParentNode, OPTIONAL
884 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
885 )
886 {
887 EFI_STATUS Status;
888 AML_OBJECT_NODE * ObjectNode;
889 AML_DATA_NODE * DataNode;
890 CHAR8 * AmlNameString;
891 UINT32 AmlNameStringSize;
892
893 if ((NameString == NULL) ||
894 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
895 ASSERT (0);
896 return EFI_INVALID_PARAMETER;
897 }
898
899 ObjectNode = NULL;
900 DataNode = NULL;
901 AmlNameString = NULL;
902
903 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
904 if (EFI_ERROR (Status)) {
905 ASSERT (0);
906 return Status;
907 }
908
909 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
910 if (EFI_ERROR (Status)) {
911 ASSERT (0);
912 goto error_handler1;
913 }
914
915 Status = AmlCreateObjectNode (
916 AmlGetByteEncodingByOpCode (AML_SCOPE_OP, 0),
917 AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize),
918 &ObjectNode
919 );
920 if (EFI_ERROR (Status)) {
921 ASSERT (0);
922 goto error_handler1;
923 }
924
925 Status = AmlCreateDataNode (
926 EAmlNodeDataTypeNameString,
927 (UINT8*)AmlNameString,
928 AmlNameStringSize,
929 &DataNode
930 );
931 if (EFI_ERROR (Status)) {
932 ASSERT (0);
933 goto error_handler2;
934 }
935
936 Status = AmlSetFixedArgument (
937 ObjectNode,
938 EAmlParseIndexTerm0,
939 (AML_NODE_HEADER*)DataNode
940 );
941 if (EFI_ERROR (Status)) {
942 ASSERT (0);
943 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
944 goto error_handler2;
945 }
946
947 Status = LinkNode (
948 ObjectNode,
949 ParentNode,
950 NewObjectNode
951 );
952 if (EFI_ERROR (Status)) {
953 ASSERT (0);
954 goto error_handler2;
955 }
956
957 // Free AmlNameString before returning as it is copied
958 // in the call to AmlCreateDataNode().
959 goto error_handler1;
960
961 error_handler2:
962 if (ObjectNode != NULL) {
963 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
964 }
965
966 error_handler1:
967 if (AmlNameString != NULL) {
968 FreePool (AmlNameString);
969 }
970
971 return Status;
972 }
973
974 /** AML code generation for a Method object node.
975
976 AmlCodeGenMethod ("MET0", 1, TRUE, 3, ParentNode, NewObjectNode) is
977 equivalent of the following ASL code:
978 Method(MET0, 1, Serialized, 3) {}
979
980 ACPI 6.4, s20.2.5.2 "Named Objects Encoding":
981 DefMethod := MethodOp PkgLength NameString MethodFlags TermList
982 MethodOp := 0x14
983
984 The ASL parameters "ReturnType" and "ParameterTypes" are not asked
985 in this function. They are optional parameters in ASL.
986
987 @param [in] NameString The new Method's name.
988 Must be a NULL-terminated ASL NameString
989 e.g.: "MET0", "_SB.MET0", etc.
990 The input string is copied.
991 @param [in] NumArgs Number of arguments.
992 Must be 0 <= NumArgs <= 6.
993 @param [in] IsSerialized TRUE is equivalent to Serialized.
994 FALSE is equivalent to NotSerialized.
995 Default is NotSerialized in ASL spec.
996 @param [in] SyncLevel Synchronization level for the method.
997 Must be 0 <= SyncLevel <= 15.
998 Default is 0 in ASL.
999 @param [in] ParentNode If provided, set ParentNode as the parent
1000 of the node created.
1001 @param [out] NewObjectNode If success, contains the created node.
1002
1003 @retval EFI_SUCCESS Success.
1004 @retval EFI_INVALID_PARAMETER Invalid parameter.
1005 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1006 **/
1007 STATIC
1008 EFI_STATUS
1009 EFIAPI
1010 AmlCodeGenMethod (
1011 IN CONST CHAR8 * NameString,
1012 IN UINT8 NumArgs,
1013 IN BOOLEAN IsSerialized,
1014 IN UINT8 SyncLevel,
1015 IN AML_NODE_HEADER * ParentNode, OPTIONAL
1016 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
1017 )
1018 {
1019 EFI_STATUS Status;
1020 UINT32 PkgLen;
1021 UINT8 Flags;
1022 AML_OBJECT_NODE * ObjectNode;
1023 AML_DATA_NODE * DataNode;
1024 CHAR8 * AmlNameString;
1025 UINT32 AmlNameStringSize;
1026
1027 if ((NameString == NULL) ||
1028 (NumArgs > 6) ||
1029 (SyncLevel > 15) ||
1030 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
1031 ASSERT (0);
1032 return EFI_INVALID_PARAMETER;
1033 }
1034
1035 ObjectNode = NULL;
1036 DataNode = NULL;
1037
1038 // ACPI 6.4, s20.2.5.2 "Named Objects Encoding":
1039 // DefMethod := MethodOp PkgLength NameString MethodFlags TermList
1040 // MethodOp := 0x14
1041 // So:
1042 // 1- Create the NameString
1043 // 2- Compute the size to write in the PkgLen
1044 // 3- Create nodes for the NameString and Method object node
1045 // 4- Set the NameString DataNode as a fixed argument
1046 // 5- Create and link the MethodFlags node
1047
1048 // 1- Create the NameString
1049 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
1050 if (EFI_ERROR (Status)) {
1051 ASSERT (0);
1052 return Status;
1053 }
1054
1055 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
1056 if (EFI_ERROR (Status)) {
1057 ASSERT (0);
1058 goto error_handler1;
1059 }
1060
1061 // 2- Compute the size to write in the PkgLen
1062 // Add 1 byte (ByteData) for MethodFlags.
1063 Status = AmlComputePkgLength (AmlNameStringSize + 1, &PkgLen);
1064 if (EFI_ERROR (Status)) {
1065 ASSERT (0);
1066 goto error_handler1;
1067 }
1068
1069 // 3- Create nodes for the NameString and Method object node
1070 Status = AmlCreateObjectNode (
1071 AmlGetByteEncodingByOpCode (AML_METHOD_OP, 0),
1072 PkgLen,
1073 &ObjectNode
1074 );
1075 if (EFI_ERROR (Status)) {
1076 ASSERT (0);
1077 goto error_handler1;
1078 }
1079
1080 Status = AmlCreateDataNode (
1081 EAmlNodeDataTypeNameString,
1082 (UINT8*)AmlNameString,
1083 AmlNameStringSize,
1084 &DataNode
1085 );
1086 if (EFI_ERROR (Status)) {
1087 ASSERT (0);
1088 goto error_handler2;
1089 }
1090
1091 // 4- Set the NameString DataNode as a fixed argument
1092 Status = AmlSetFixedArgument (
1093 ObjectNode,
1094 EAmlParseIndexTerm0,
1095 (AML_NODE_HEADER*)DataNode
1096 );
1097 if (EFI_ERROR (Status)) {
1098 ASSERT (0);
1099 goto error_handler2;
1100 }
1101
1102 DataNode = NULL;
1103
1104 // 5- Create and link the MethodFlags node
1105 Flags = NumArgs |
1106 (IsSerialized ? BIT3 : 0) |
1107 (SyncLevel << 4);
1108
1109 Status = AmlCreateDataNode (EAmlNodeDataTypeUInt, &Flags, 1, &DataNode);
1110 if (EFI_ERROR (Status)) {
1111 ASSERT (0);
1112 goto error_handler2;
1113 }
1114
1115 Status = AmlSetFixedArgument (
1116 ObjectNode,
1117 EAmlParseIndexTerm1,
1118 (AML_NODE_HEADER*)DataNode
1119 );
1120 if (EFI_ERROR (Status)) {
1121 ASSERT (0);
1122 goto error_handler2;
1123 }
1124
1125 // Data node is attached so set the pointer to
1126 // NULL to ensure correct error handling.
1127 DataNode = NULL;
1128
1129 Status = LinkNode (
1130 ObjectNode,
1131 ParentNode,
1132 NewObjectNode
1133 );
1134 if (EFI_ERROR (Status)) {
1135 ASSERT (0);
1136 goto error_handler2;
1137 }
1138
1139 // Free AmlNameString before returning as it is copied
1140 // in the call to AmlCreateDataNode().
1141 goto error_handler1;
1142
1143 error_handler2:
1144 if (ObjectNode != NULL) {
1145 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
1146 }
1147 if (DataNode != NULL) {
1148 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
1149 }
1150
1151 error_handler1:
1152 if (AmlNameString != NULL) {
1153 FreePool (AmlNameString);
1154 }
1155 return Status;
1156 }
1157
1158 /** AML code generation for a Return object node.
1159
1160 AmlCodeGenReturn (ReturnNode, ParentNode, NewObjectNode) is
1161 equivalent of the following ASL code:
1162 Return([Content of the ReturnNode])
1163
1164 The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
1165 DefReturn := ReturnOp ArgObject
1166 ReturnOp := 0xA4
1167 ArgObject := TermArg => DataRefObject
1168
1169 Thus, the ReturnNode must be evaluated as a DataRefObject. It can
1170 be a NameString referencing an object. As this CodeGen Api doesn't
1171 do semantic checking, it is strongly advised to check the AML bytecode
1172 generated by this function against an ASL compiler.
1173
1174 The ReturnNode must be generated inside a Method body scope.
1175
1176 @param [in] ReturnNode The object returned by the Return ASL statement.
1177 This node is deleted if an error occurs.
1178 @param [in] ParentNode If provided, set ParentNode as the parent
1179 of the node created.
1180 Must be a MethodOp node.
1181 @param [out] NewObjectNode If success, contains the created node.
1182
1183 @retval EFI_SUCCESS Success.
1184 @retval EFI_INVALID_PARAMETER Invalid parameter.
1185 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1186 **/
1187 STATIC
1188 EFI_STATUS
1189 EFIAPI
1190 AmlCodeGenReturn (
1191 IN AML_NODE_HEADER * ReturnNode,
1192 IN AML_NODE_HEADER * ParentNode, OPTIONAL
1193 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
1194 )
1195 {
1196 EFI_STATUS Status;
1197 AML_OBJECT_NODE * ObjectNode;
1198
1199 if ((ReturnNode == NULL) ||
1200 ((ParentNode == NULL) && (NewObjectNode == NULL)) ||
1201 ((ParentNode != NULL) &&
1202 !AmlNodeCompareOpCode (
1203 (AML_OBJECT_NODE*)ParentNode, AML_METHOD_OP, 0))) {
1204 ASSERT (0);
1205 return EFI_INVALID_PARAMETER;
1206 }
1207
1208 Status = AmlCreateObjectNode (
1209 AmlGetByteEncodingByOpCode (AML_RETURN_OP, 0),
1210 0,
1211 &ObjectNode
1212 );
1213 if (EFI_ERROR (Status)) {
1214 ASSERT (0);
1215 goto error_handler;
1216 }
1217
1218 Status = AmlSetFixedArgument (
1219 ObjectNode,
1220 EAmlParseIndexTerm0,
1221 (AML_NODE_HEADER*)ReturnNode
1222 );
1223 if (EFI_ERROR (Status)) {
1224 ASSERT (0);
1225 goto error_handler;
1226 }
1227
1228 ReturnNode = NULL;
1229
1230 Status = LinkNode (
1231 ObjectNode,
1232 ParentNode,
1233 NewObjectNode
1234 );
1235 if (EFI_ERROR (Status)) {
1236 ASSERT (0);
1237 goto error_handler;
1238 }
1239
1240 return Status;
1241
1242 error_handler:
1243 if (ReturnNode != NULL) {
1244 AmlDeleteTree (ReturnNode);
1245 }
1246 if (ObjectNode != NULL) {
1247 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
1248 }
1249 return Status;
1250 }
1251
1252 /** AML code generation for a Return object node,
1253 returning the object as an input NameString.
1254
1255 AmlCodeGenReturn ("NAM1", ParentNode, NewObjectNode) is
1256 equivalent of the following ASL code:
1257 Return(NAM1)
1258
1259 The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
1260 DefReturn := ReturnOp ArgObject
1261 ReturnOp := 0xA4
1262 ArgObject := TermArg => DataRefObject
1263
1264 Thus, the ReturnNode must be evaluated as a DataRefObject. It can
1265 be a NameString referencing an object. As this CodeGen Api doesn't
1266 do semantic checking, it is strongly advised to check the AML bytecode
1267 generated by this function against an ASL compiler.
1268
1269 The ReturnNode must be generated inside a Method body scope.
1270
1271 @param [in] NameString The object referenced by this NameString
1272 is returned by the Return ASL statement.
1273 Must be a NULL-terminated ASL NameString
1274 e.g.: "NAM1", "_SB.NAM1", etc.
1275 The input string is copied.
1276 @param [in] ParentNode If provided, set ParentNode as the parent
1277 of the node created.
1278 Must be a MethodOp node.
1279 @param [out] NewObjectNode If success, contains the created node.
1280
1281 @retval EFI_SUCCESS Success.
1282 @retval EFI_INVALID_PARAMETER Invalid parameter.
1283 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1284 **/
1285 STATIC
1286 EFI_STATUS
1287 EFIAPI
1288 AmlCodeGenReturnNameString (
1289 IN CONST CHAR8 * NameString,
1290 IN AML_NODE_HEADER * ParentNode, OPTIONAL
1291 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
1292 )
1293 {
1294 EFI_STATUS Status;
1295 AML_DATA_NODE * DataNode;
1296 CHAR8 * AmlNameString;
1297 UINT32 AmlNameStringSize;
1298
1299 DataNode = NULL;
1300
1301 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
1302 if (EFI_ERROR (Status)) {
1303 ASSERT (0);
1304 return Status;
1305 }
1306
1307 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
1308 if (EFI_ERROR (Status)) {
1309 ASSERT (0);
1310 goto exit_handler;
1311 }
1312
1313 Status = AmlCreateDataNode (
1314 EAmlNodeDataTypeNameString,
1315 (UINT8*)AmlNameString,
1316 AmlNameStringSize,
1317 &DataNode
1318 );
1319 if (EFI_ERROR (Status)) {
1320 ASSERT (0);
1321 goto exit_handler;
1322 }
1323
1324 // AmlCodeGenReturn() deletes DataNode if error.
1325 Status = AmlCodeGenReturn (
1326 (AML_NODE_HEADER*)DataNode,
1327 ParentNode,
1328 NewObjectNode
1329 );
1330 ASSERT_EFI_ERROR (Status);
1331
1332 exit_handler:
1333 if (AmlNameString != NULL) {
1334 FreePool (AmlNameString);
1335 }
1336 return Status;
1337 }