]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
DynamicTablesPkg: Change OPTIONAL keyword usage style
[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 <Api/AmlApiHelper.h>
16 #include <CodeGen/AmlResourceDataCodeGen.h>
17 #include <Tree/AmlNode.h>
18 #include <Tree/AmlTree.h>
19 #include <String/AmlString.h>
20 #include <Utils/AmlUtility.h>
21
22 /** Utility function to link a node when returning from a CodeGen function.
23
24 @param [in] Node Newly created node.
25 @param [in] ParentNode If provided, set ParentNode as the parent
26 of the node created.
27 @param [out] NewObjectNode If not NULL:
28 - and Success, contains the created Node.
29 - and Error, reset to NULL.
30
31 @retval EFI_SUCCESS The function completed successfully.
32 @retval EFI_INVALID_PARAMETER Invalid parameter.
33 **/
34 STATIC
35 EFI_STATUS
36 EFIAPI
37 LinkNode (
38 IN AML_OBJECT_NODE * Node,
39 IN AML_NODE_HEADER * ParentNode,
40 OUT AML_OBJECT_NODE ** NewObjectNode
41 )
42 {
43 EFI_STATUS Status;
44
45 if (NewObjectNode != NULL) {
46 *NewObjectNode = NULL;
47 }
48
49 // Add RdNode as the last element.
50 if (ParentNode != NULL) {
51 Status = AmlVarListAddTail (ParentNode, (AML_NODE_HEADER*)Node);
52 if (EFI_ERROR (Status)) {
53 ASSERT (0);
54 return Status;
55 }
56 }
57
58 if (NewObjectNode != NULL) {
59 *NewObjectNode = Node;
60 }
61
62 return EFI_SUCCESS;
63 }
64
65 /** AML code generation for DefinitionBlock.
66
67 Create a Root Node handle.
68 It is the caller's responsibility to free the allocated memory
69 with the AmlDeleteTree function.
70
71 AmlCodeGenDefinitionBlock (TableSignature, OemID, TableID, OEMRevision) is
72 equivalent to the following ASL code:
73 DefinitionBlock (AMLFileName, TableSignature, ComplianceRevision,
74 OemID, TableID, OEMRevision) {}
75 with the ComplianceRevision set to 2 and the AMLFileName is ignored.
76
77 @param[in] TableSignature 4-character ACPI signature.
78 Must be 'DSDT' or 'SSDT'.
79 @param[in] OemId 6-character string OEM identifier.
80 @param[in] OemTableId 8-character string OEM table identifier.
81 @param[in] OemRevision OEM revision number.
82 @param[out] NewRootNode Pointer to the root node representing a
83 Definition Block.
84
85 @retval EFI_SUCCESS Success.
86 @retval EFI_INVALID_PARAMETER Invalid parameter.
87 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
88 **/
89 EFI_STATUS
90 EFIAPI
91 AmlCodeGenDefinitionBlock (
92 IN CONST CHAR8 * TableSignature,
93 IN CONST CHAR8 * OemId,
94 IN CONST CHAR8 * OemTableId,
95 IN UINT32 OemRevision,
96 OUT AML_ROOT_NODE ** NewRootNode
97 )
98 {
99 EFI_STATUS Status;
100 EFI_ACPI_DESCRIPTION_HEADER AcpiHeader;
101
102 if ((TableSignature == NULL) ||
103 (OemId == NULL) ||
104 (OemTableId == NULL) ||
105 (NewRootNode == NULL)) {
106 ASSERT (0);
107 return EFI_INVALID_PARAMETER;
108 }
109
110 CopyMem (&AcpiHeader.Signature, TableSignature, 4);
111 AcpiHeader.Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
112 AcpiHeader.Revision = 2;
113 CopyMem (&AcpiHeader.OemId, OemId, 6);
114 CopyMem (&AcpiHeader.OemTableId, OemTableId, 8);
115 AcpiHeader.OemRevision = OemRevision;
116 AcpiHeader.CreatorId = TABLE_GENERATOR_CREATOR_ID_ARM;
117 AcpiHeader.CreatorRevision = CREATE_REVISION (1, 0);
118
119 Status = AmlCreateRootNode (&AcpiHeader, NewRootNode);
120 ASSERT_EFI_ERROR (Status);
121
122 return Status;
123 }
124
125 /** AML code generation for a String object node.
126
127 @param [in] String Pointer to a NULL terminated string.
128 @param [out] NewObjectNode If success, contains the created
129 String object node.
130
131 @retval EFI_SUCCESS Success.
132 @retval EFI_INVALID_PARAMETER Invalid parameter.
133 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
134 **/
135 STATIC
136 EFI_STATUS
137 EFIAPI
138 AmlCodeGenString (
139 IN CHAR8 * String,
140 OUT AML_OBJECT_NODE ** NewObjectNode
141 )
142 {
143 EFI_STATUS Status;
144 AML_OBJECT_NODE * ObjectNode;
145 AML_DATA_NODE * DataNode;
146
147 if ((String == NULL) ||
148 (NewObjectNode == NULL)) {
149 ASSERT (0);
150 return EFI_INVALID_PARAMETER;
151 }
152
153 DataNode = NULL;
154
155 Status = AmlCreateObjectNode (
156 AmlGetByteEncodingByOpCode (AML_STRING_PREFIX, 0),
157 0,
158 &ObjectNode
159 );
160 if (EFI_ERROR (Status)) {
161 ASSERT (0);
162 return Status;
163 }
164
165 Status = AmlCreateDataNode (
166 EAmlNodeDataTypeString,
167 (UINT8*)String,
168 (UINT32)AsciiStrLen (String) + 1,
169 &DataNode
170 );
171 if (EFI_ERROR (Status)) {
172 ASSERT (0);
173 goto error_handler;
174 }
175
176 Status = AmlSetFixedArgument (
177 ObjectNode,
178 EAmlParseIndexTerm0,
179 (AML_NODE_HEADER*)DataNode
180 );
181 if (EFI_ERROR (Status)) {
182 ASSERT (0);
183 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
184 goto error_handler;
185 }
186
187 *NewObjectNode = ObjectNode;
188 return Status;
189
190 error_handler:
191 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
192 return Status;
193 }
194
195 /** AML code generation for an Integer object node.
196
197 @param [in] Integer Integer of the Integer object node.
198 @param [out] NewObjectNode If success, contains the created
199 Integer object node.
200
201 @retval EFI_SUCCESS Success.
202 @retval EFI_INVALID_PARAMETER Invalid parameter.
203 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
204 **/
205 STATIC
206 EFI_STATUS
207 EFIAPI
208 AmlCodeGenInteger (
209 IN UINT64 Integer,
210 OUT AML_OBJECT_NODE ** NewObjectNode
211 )
212 {
213 EFI_STATUS Status;
214 INT8 ValueWidthDiff;
215
216 if (NewObjectNode == NULL) {
217 ASSERT (0);
218 return EFI_INVALID_PARAMETER;
219 }
220
221 // Create an object node containing Zero.
222 Status = AmlCreateObjectNode (
223 AmlGetByteEncodingByOpCode (AML_ZERO_OP, 0),
224 0,
225 NewObjectNode
226 );
227 if (EFI_ERROR (Status)) {
228 ASSERT (0);
229 return Status;
230 }
231
232 // Update the object node with integer value.
233 Status = AmlNodeSetIntegerValue (*NewObjectNode, Integer, &ValueWidthDiff);
234 if (EFI_ERROR (Status)) {
235 ASSERT (0);
236 AmlDeleteTree ((AML_NODE_HEADER*)*NewObjectNode);
237 }
238
239 return Status;
240 }
241
242 /** AML code generation for a Package object node.
243
244 The package generated is empty. New elements can be added via its
245 list of variable arguments.
246
247 @param [out] NewObjectNode If success, contains the created
248 Package object node.
249
250 @retval EFI_SUCCESS Success.
251 @retval EFI_INVALID_PARAMETER Invalid parameter.
252 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
253 **/
254 STATIC
255 EFI_STATUS
256 EFIAPI
257 AmlCodeGenPackage (
258 OUT AML_OBJECT_NODE ** NewObjectNode
259 )
260 {
261 EFI_STATUS Status;
262 AML_DATA_NODE * DataNode;
263 UINT8 NodeCount;
264
265 if (NewObjectNode == NULL) {
266 ASSERT (0);
267 return EFI_INVALID_PARAMETER;
268 }
269
270 NodeCount = 0;
271
272 // Create an object node.
273 // PkgLen is 2:
274 // - one byte to store the PkgLength
275 // - one byte for the NumElements.
276 // Cf ACPI6.3, s20.2.5 "Term Objects Encoding"
277 // DefPackage := PackageOp PkgLength NumElements PackageElementList
278 // NumElements := ByteData
279 Status = AmlCreateObjectNode (
280 AmlGetByteEncodingByOpCode (AML_PACKAGE_OP, 0),
281 2,
282 NewObjectNode
283 );
284 if (EFI_ERROR (Status)) {
285 ASSERT (0);
286 return Status;
287 }
288
289 // NumElements is a ByteData.
290 Status = AmlCreateDataNode (
291 EAmlNodeDataTypeUInt,
292 &NodeCount,
293 sizeof (NodeCount),
294 &DataNode
295 );
296 if (EFI_ERROR (Status)) {
297 ASSERT (0);
298 goto error_handler;
299 }
300
301 Status = AmlSetFixedArgument (
302 *NewObjectNode,
303 EAmlParseIndexTerm0,
304 (AML_NODE_HEADER*)DataNode
305 );
306 if (EFI_ERROR (Status)) {
307 ASSERT (0);
308 goto error_handler;
309 }
310
311 return Status;
312
313 error_handler:
314 AmlDeleteTree ((AML_NODE_HEADER*)*NewObjectNode);
315 if (DataNode != NULL) {
316 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
317 }
318 return Status;
319 }
320
321 /** AML code generation for a Buffer object node.
322
323 To create a Buffer object node with an empty buffer,
324 call the function with (Buffer=NULL, BufferSize=0).
325
326 @param [in] Buffer Buffer to set for the created Buffer
327 object node. The Buffer's content is copied.
328 NULL if there is no buffer to set for
329 the Buffer node.
330 @param [in] BufferSize Size of the Buffer.
331 0 if there is no buffer to set for
332 the Buffer node.
333 @param [out] NewObjectNode If success, contains the created
334 Buffer object node.
335
336 @retval EFI_SUCCESS Success.
337 @retval EFI_INVALID_PARAMETER Invalid parameter.
338 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
339 **/
340 STATIC
341 EFI_STATUS
342 EFIAPI
343 AmlCodeGenBuffer (
344 IN CONST UINT8 * Buffer OPTIONAL,
345 IN UINT32 BufferSize OPTIONAL,
346 OUT AML_OBJECT_NODE ** NewObjectNode
347 )
348 {
349 EFI_STATUS Status;
350 AML_OBJECT_NODE * BufferNode;
351 AML_OBJECT_NODE * BufferSizeNode;
352 UINT32 BufferSizeNodeSize;
353 AML_DATA_NODE * DataNode;
354 UINT32 PkgLen;
355
356 // Buffer and BufferSize must be either both set, or both clear.
357 if ((NewObjectNode == NULL) ||
358 ((Buffer == NULL) != (BufferSize == 0))) {
359 ASSERT (0);
360 return EFI_INVALID_PARAMETER;
361 }
362
363 BufferNode = NULL;
364 DataNode = NULL;
365
366 // Cf ACPI 6.3 specification, s20.2.5.4 "Type 2 Opcodes Encoding"
367 // DefBuffer := BufferOp PkgLength BufferSize ByteList
368 // BufferOp := 0x11
369 // BufferSize := TermArg => Integer
370
371 Status = AmlCodeGenInteger (BufferSize, &BufferSizeNode);
372 if (EFI_ERROR (Status)) {
373 ASSERT (0);
374 return Status;
375 }
376
377 // Get the number of bytes required to encode the BufferSizeNode.
378 Status = AmlComputeSize (
379 (AML_NODE_HEADER*)BufferSizeNode,
380 &BufferSizeNodeSize
381 );
382 if (EFI_ERROR (Status)) {
383 ASSERT (0);
384 goto error_handler;
385 }
386
387 // Compute the size to write in the PkgLen.
388 Status = AmlComputePkgLength (BufferSizeNodeSize + BufferSize, &PkgLen);
389 if (EFI_ERROR (Status)) {
390 ASSERT (0);
391 goto error_handler;
392 }
393
394 // Create an object node for the buffer.
395 Status = AmlCreateObjectNode (
396 AmlGetByteEncodingByOpCode (AML_BUFFER_OP, 0),
397 PkgLen,
398 &BufferNode
399 );
400 if (EFI_ERROR (Status)) {
401 ASSERT (0);
402 goto error_handler;
403 }
404
405 // Set the BufferSizeNode as a fixed argument of the BufferNode.
406 Status = AmlSetFixedArgument (
407 BufferNode,
408 EAmlParseIndexTerm0,
409 (AML_NODE_HEADER*)BufferSizeNode
410 );
411 if (EFI_ERROR (Status)) {
412 ASSERT (0);
413 goto error_handler;
414 }
415
416 // BufferSizeNode is now attached.
417 BufferSizeNode = NULL;
418
419 // If there is a buffer, create a DataNode and attach it to the BufferNode.
420 if (Buffer != NULL) {
421 Status = AmlCreateDataNode (
422 EAmlNodeDataTypeRaw,
423 Buffer,
424 BufferSize,
425 &DataNode
426 );
427 if (EFI_ERROR (Status)) {
428 ASSERT (0);
429 goto error_handler;
430 }
431
432 Status = AmlVarListAddTail (
433 (AML_NODE_HEADER*)BufferNode,
434 (AML_NODE_HEADER*)DataNode
435 );
436 if (EFI_ERROR (Status)) {
437 ASSERT (0);
438 goto error_handler;
439 }
440 }
441
442 *NewObjectNode = BufferNode;
443 return Status;
444
445 error_handler:
446 if (BufferSizeNode != NULL) {
447 AmlDeleteTree ((AML_NODE_HEADER*)BufferSizeNode);
448 }
449 if (BufferNode != NULL) {
450 AmlDeleteTree ((AML_NODE_HEADER*)BufferNode);
451 }
452 if (DataNode != NULL) {
453 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
454 }
455 return Status;
456 }
457
458 /** AML code generation for a ResourceTemplate.
459
460 "ResourceTemplate" is a macro defined in ACPI 6.3, s19.3.3
461 "ASL Resource Templates". It allows to store resource data elements.
462
463 In AML, a ResourceTemplate is implemented as a Buffer storing resource
464 data elements. An EndTag resource data descriptor must be at the end
465 of the list of resource data elements.
466 This function generates a Buffer node with an EndTag resource data
467 descriptor. It can be seen as an empty list of resource data elements.
468
469 @param [out] NewObjectNode If success, contains the created
470 ResourceTemplate object node.
471
472 @retval EFI_SUCCESS Success.
473 @retval EFI_INVALID_PARAMETER Invalid parameter.
474 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
475 **/
476 STATIC
477 EFI_STATUS
478 EFIAPI
479 AmlCodeGenResourceTemplate (
480 OUT AML_OBJECT_NODE ** NewObjectNode
481 )
482 {
483 EFI_STATUS Status;
484 AML_OBJECT_NODE * BufferNode;
485
486 if (NewObjectNode == NULL) {
487 ASSERT (0);
488 return EFI_INVALID_PARAMETER;
489 }
490
491 // Create a BufferNode with an empty buffer.
492 Status = AmlCodeGenBuffer (NULL, 0, &BufferNode);
493 if (EFI_ERROR (Status)) {
494 ASSERT (0);
495 return Status;
496 }
497
498 // Create an EndTag resource data element and attach it to the Buffer.
499 Status = AmlCodeGenEndTag (0, BufferNode, NULL);
500 if (EFI_ERROR (Status)) {
501 ASSERT (0);
502 AmlDeleteTree ((AML_NODE_HEADER*)BufferNode);
503 return Status;
504 }
505
506 *NewObjectNode = BufferNode;
507 return Status;
508 }
509
510 /** AML code generation for a Name object node.
511
512 @param [in] NameString The new variable name.
513 Must be a NULL-terminated ASL NameString
514 e.g.: "DEV0", "DV15.DEV0", etc.
515 This input string is copied.
516 @param [in] Object Object associated to the NameString.
517 @param [in] ParentNode If provided, set ParentNode as the parent
518 of the node created.
519 @param [out] NewObjectNode If success, contains the created node.
520
521 @retval EFI_SUCCESS Success.
522 @retval EFI_INVALID_PARAMETER Invalid parameter.
523 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
524 **/
525 STATIC
526 EFI_STATUS
527 EFIAPI
528 AmlCodeGenName (
529 IN CONST CHAR8 * NameString,
530 IN AML_OBJECT_NODE * Object,
531 IN AML_NODE_HEADER * ParentNode OPTIONAL,
532 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
533 )
534 {
535 EFI_STATUS Status;
536 AML_OBJECT_NODE * ObjectNode;
537 AML_DATA_NODE * DataNode;
538 CHAR8 * AmlNameString;
539 UINT32 AmlNameStringSize;
540
541 if ((NameString == NULL) ||
542 (Object == NULL) ||
543 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
544 ASSERT (0);
545 return EFI_INVALID_PARAMETER;
546 }
547
548 ObjectNode = NULL;
549 DataNode = NULL;
550 AmlNameString = NULL;
551
552 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
553 if (EFI_ERROR (Status)) {
554 ASSERT (0);
555 return Status;
556 }
557
558 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
559 if (EFI_ERROR (Status)) {
560 ASSERT (0);
561 goto error_handler1;
562 }
563
564 Status = AmlCreateObjectNode (
565 AmlGetByteEncodingByOpCode (AML_NAME_OP, 0),
566 0,
567 &ObjectNode
568 );
569 if (EFI_ERROR (Status)) {
570 ASSERT (0);
571 goto error_handler1;
572 }
573
574 Status = AmlCreateDataNode (
575 EAmlNodeDataTypeNameString,
576 (UINT8*)AmlNameString,
577 AmlNameStringSize,
578 &DataNode
579 );
580 if (EFI_ERROR (Status)) {
581 ASSERT (0);
582 goto error_handler2;
583 }
584
585 Status = AmlSetFixedArgument (
586 ObjectNode,
587 EAmlParseIndexTerm0,
588 (AML_NODE_HEADER*)DataNode
589 );
590 if (EFI_ERROR (Status)) {
591 ASSERT (0);
592 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
593 goto error_handler2;
594 }
595
596 Status = AmlSetFixedArgument (
597 ObjectNode,
598 EAmlParseIndexTerm1,
599 (AML_NODE_HEADER*)Object
600 );
601 if (EFI_ERROR (Status)) {
602 ASSERT (0);
603 goto error_handler2;
604 }
605
606 Status = LinkNode (
607 ObjectNode,
608 ParentNode,
609 NewObjectNode
610 );
611 if (EFI_ERROR (Status)) {
612 ASSERT (0);
613 goto error_handler2;
614 }
615
616 // Free AmlNameString before returning as it is copied
617 // in the call to AmlCreateDataNode().
618 goto error_handler1;
619
620 error_handler2:
621 if (ObjectNode != NULL) {
622 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
623 }
624
625 error_handler1:
626 if (AmlNameString != NULL) {
627 FreePool (AmlNameString);
628 }
629
630 return Status;
631 }
632
633 /** AML code generation for a Name object node, containing a String.
634
635 AmlCodeGenNameString ("_HID", "HID0000", ParentNode, NewObjectNode) is
636 equivalent of the following ASL code:
637 Name(_HID, "HID0000")
638
639 @param [in] NameString The new variable name.
640 Must be a NULL-terminated ASL NameString
641 e.g.: "DEV0", "DV15.DEV0", etc.
642 The input string is copied.
643 @param [in] String NULL terminated String to associate to the
644 NameString.
645 @param [in] ParentNode If provided, set ParentNode as the parent
646 of the node created.
647 @param [out] NewObjectNode If success, contains the created node.
648
649 @retval EFI_SUCCESS Success.
650 @retval EFI_INVALID_PARAMETER Invalid parameter.
651 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
652 **/
653 EFI_STATUS
654 EFIAPI
655 AmlCodeGenNameString (
656 IN CONST CHAR8 * NameString,
657 IN CHAR8 * String,
658 IN AML_NODE_HEADER * ParentNode OPTIONAL,
659 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
660 )
661 {
662 EFI_STATUS Status;
663 AML_OBJECT_NODE * ObjectNode;
664
665 if ((NameString == NULL) ||
666 (String == NULL) ||
667 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
668 ASSERT (0);
669 return EFI_INVALID_PARAMETER;
670 }
671
672 Status = AmlCodeGenString (String, &ObjectNode);
673 if (EFI_ERROR (Status)) {
674 ASSERT (0);
675 return Status;
676 }
677
678 Status = AmlCodeGenName (
679 NameString,
680 ObjectNode,
681 ParentNode,
682 NewObjectNode
683 );
684 if (EFI_ERROR (Status)) {
685 ASSERT (0);
686 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
687 }
688
689 return Status;
690 }
691
692 /** AML code generation for a Name object node, containing an Integer.
693
694 AmlCodeGenNameInteger ("_UID", 1, ParentNode, NewObjectNode) is
695 equivalent of the following ASL code:
696 Name(_UID, One)
697
698 @param [in] NameString The new variable name.
699 Must be a NULL-terminated ASL NameString
700 e.g.: "DEV0", "DV15.DEV0", etc.
701 The input string is copied.
702 @param [in] Integer Integer to associate to the NameString.
703 @param [in] ParentNode If provided, set ParentNode as the parent
704 of the node created.
705 @param [out] NewObjectNode If success, contains the created node.
706
707 @retval EFI_SUCCESS Success.
708 @retval EFI_INVALID_PARAMETER Invalid parameter.
709 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
710 **/
711 EFI_STATUS
712 EFIAPI
713 AmlCodeGenNameInteger (
714 IN CONST CHAR8 * NameString,
715 IN UINT64 Integer,
716 IN AML_NODE_HEADER * ParentNode OPTIONAL,
717 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
718 )
719 {
720 EFI_STATUS Status;
721 AML_OBJECT_NODE * ObjectNode;
722
723 if ((NameString == NULL) ||
724 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
725 ASSERT (0);
726 return EFI_INVALID_PARAMETER;
727 }
728
729 Status = AmlCodeGenInteger (Integer, &ObjectNode);
730 if (EFI_ERROR (Status)) {
731 ASSERT (0);
732 return Status;
733 }
734
735 Status = AmlCodeGenName (
736 NameString,
737 ObjectNode,
738 ParentNode,
739 NewObjectNode
740 );
741 if (EFI_ERROR (Status)) {
742 ASSERT (0);
743 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
744 }
745
746 return Status;
747 }
748
749 /** AML code generation for a Device object node.
750
751 AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
752 equivalent of the following ASL code:
753 Device(COM0) {}
754
755 @param [in] NameString The new Device's name.
756 Must be a NULL-terminated ASL NameString
757 e.g.: "DEV0", "DV15.DEV0", etc.
758 The input string is copied.
759 @param [in] ParentNode If provided, set ParentNode as the parent
760 of the node created.
761 @param [out] NewObjectNode If success, contains the created node.
762
763 @retval EFI_SUCCESS Success.
764 @retval EFI_INVALID_PARAMETER Invalid parameter.
765 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
766 **/
767 EFI_STATUS
768 EFIAPI
769 AmlCodeGenDevice (
770 IN CONST CHAR8 * NameString,
771 IN AML_NODE_HEADER * ParentNode OPTIONAL,
772 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
773 )
774 {
775 EFI_STATUS Status;
776 AML_OBJECT_NODE * ObjectNode;
777 AML_DATA_NODE * DataNode;
778 CHAR8 * AmlNameString;
779 UINT32 AmlNameStringSize;
780
781 if ((NameString == NULL) ||
782 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
783 ASSERT (0);
784 return EFI_INVALID_PARAMETER;
785 }
786
787 ObjectNode = NULL;
788 DataNode = NULL;
789 AmlNameString = NULL;
790
791 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
792 if (EFI_ERROR (Status)) {
793 ASSERT (0);
794 return Status;
795 }
796
797 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
798 if (EFI_ERROR (Status)) {
799 ASSERT (0);
800 goto error_handler1;
801 }
802
803 Status = AmlCreateObjectNode (
804 AmlGetByteEncodingByOpCode (AML_EXT_OP, AML_EXT_DEVICE_OP),
805 AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize),
806 &ObjectNode
807 );
808 if (EFI_ERROR (Status)) {
809 ASSERT (0);
810 goto error_handler1;
811 }
812
813 Status = AmlCreateDataNode (
814 EAmlNodeDataTypeNameString,
815 (UINT8*)AmlNameString,
816 AmlNameStringSize,
817 &DataNode
818 );
819 if (EFI_ERROR (Status)) {
820 ASSERT (0);
821 goto error_handler2;
822 }
823
824 Status = AmlSetFixedArgument (
825 ObjectNode,
826 EAmlParseIndexTerm0,
827 (AML_NODE_HEADER*)DataNode
828 );
829 if (EFI_ERROR (Status)) {
830 ASSERT (0);
831 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
832 goto error_handler2;
833 }
834
835 Status = LinkNode (
836 ObjectNode,
837 ParentNode,
838 NewObjectNode
839 );
840 if (EFI_ERROR (Status)) {
841 ASSERT (0);
842 goto error_handler2;
843 }
844
845 // Free AmlNameString before returning as it is copied
846 // in the call to AmlCreateDataNode().
847 goto error_handler1;
848
849 error_handler2:
850 if (ObjectNode != NULL) {
851 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
852 }
853
854 error_handler1:
855 if (AmlNameString != NULL) {
856 FreePool (AmlNameString);
857 }
858
859 return Status;
860 }
861
862 /** AML code generation for a Scope object node.
863
864 AmlCodeGenScope ("_SB", ParentNode, NewObjectNode) is
865 equivalent of the following ASL code:
866 Scope(_SB) {}
867
868 @param [in] NameString The new Scope's name.
869 Must be a NULL-terminated ASL NameString
870 e.g.: "DEV0", "DV15.DEV0", etc.
871 The input string is copied.
872 @param [in] ParentNode If provided, set ParentNode as the parent
873 of the node created.
874 @param [out] NewObjectNode If success, contains the created node.
875
876 @retval EFI_SUCCESS Success.
877 @retval EFI_INVALID_PARAMETER Invalid parameter.
878 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
879 **/
880 EFI_STATUS
881 EFIAPI
882 AmlCodeGenScope (
883 IN CONST CHAR8 * NameString,
884 IN AML_NODE_HEADER * ParentNode OPTIONAL,
885 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
886 )
887 {
888 EFI_STATUS Status;
889 AML_OBJECT_NODE * ObjectNode;
890 AML_DATA_NODE * DataNode;
891 CHAR8 * AmlNameString;
892 UINT32 AmlNameStringSize;
893
894 if ((NameString == NULL) ||
895 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
896 ASSERT (0);
897 return EFI_INVALID_PARAMETER;
898 }
899
900 ObjectNode = NULL;
901 DataNode = NULL;
902 AmlNameString = NULL;
903
904 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
905 if (EFI_ERROR (Status)) {
906 ASSERT (0);
907 return Status;
908 }
909
910 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
911 if (EFI_ERROR (Status)) {
912 ASSERT (0);
913 goto error_handler1;
914 }
915
916 Status = AmlCreateObjectNode (
917 AmlGetByteEncodingByOpCode (AML_SCOPE_OP, 0),
918 AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize),
919 &ObjectNode
920 );
921 if (EFI_ERROR (Status)) {
922 ASSERT (0);
923 goto error_handler1;
924 }
925
926 Status = AmlCreateDataNode (
927 EAmlNodeDataTypeNameString,
928 (UINT8*)AmlNameString,
929 AmlNameStringSize,
930 &DataNode
931 );
932 if (EFI_ERROR (Status)) {
933 ASSERT (0);
934 goto error_handler2;
935 }
936
937 Status = AmlSetFixedArgument (
938 ObjectNode,
939 EAmlParseIndexTerm0,
940 (AML_NODE_HEADER*)DataNode
941 );
942 if (EFI_ERROR (Status)) {
943 ASSERT (0);
944 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
945 goto error_handler2;
946 }
947
948 Status = LinkNode (
949 ObjectNode,
950 ParentNode,
951 NewObjectNode
952 );
953 if (EFI_ERROR (Status)) {
954 ASSERT (0);
955 goto error_handler2;
956 }
957
958 // Free AmlNameString before returning as it is copied
959 // in the call to AmlCreateDataNode().
960 goto error_handler1;
961
962 error_handler2:
963 if (ObjectNode != NULL) {
964 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
965 }
966
967 error_handler1:
968 if (AmlNameString != NULL) {
969 FreePool (AmlNameString);
970 }
971
972 return Status;
973 }
974
975 /** AML code generation for a Method object node.
976
977 AmlCodeGenMethod ("MET0", 1, TRUE, 3, ParentNode, NewObjectNode) is
978 equivalent of the following ASL code:
979 Method(MET0, 1, Serialized, 3) {}
980
981 ACPI 6.4, s20.2.5.2 "Named Objects Encoding":
982 DefMethod := MethodOp PkgLength NameString MethodFlags TermList
983 MethodOp := 0x14
984
985 The ASL parameters "ReturnType" and "ParameterTypes" are not asked
986 in this function. They are optional parameters in ASL.
987
988 @param [in] NameString The new Method's name.
989 Must be a NULL-terminated ASL NameString
990 e.g.: "MET0", "_SB.MET0", etc.
991 The input string is copied.
992 @param [in] NumArgs Number of arguments.
993 Must be 0 <= NumArgs <= 6.
994 @param [in] IsSerialized TRUE is equivalent to Serialized.
995 FALSE is equivalent to NotSerialized.
996 Default is NotSerialized in ASL spec.
997 @param [in] SyncLevel Synchronization level for the method.
998 Must be 0 <= SyncLevel <= 15.
999 Default is 0 in ASL.
1000 @param [in] ParentNode If provided, set ParentNode as the parent
1001 of the node created.
1002 @param [out] NewObjectNode If success, contains the created node.
1003
1004 @retval EFI_SUCCESS Success.
1005 @retval EFI_INVALID_PARAMETER Invalid parameter.
1006 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1007 **/
1008 STATIC
1009 EFI_STATUS
1010 EFIAPI
1011 AmlCodeGenMethod (
1012 IN CONST CHAR8 * NameString,
1013 IN UINT8 NumArgs,
1014 IN BOOLEAN IsSerialized,
1015 IN UINT8 SyncLevel,
1016 IN AML_NODE_HEADER * ParentNode OPTIONAL,
1017 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
1018 )
1019 {
1020 EFI_STATUS Status;
1021 UINT32 PkgLen;
1022 UINT8 Flags;
1023 AML_OBJECT_NODE * ObjectNode;
1024 AML_DATA_NODE * DataNode;
1025 CHAR8 * AmlNameString;
1026 UINT32 AmlNameStringSize;
1027
1028 if ((NameString == NULL) ||
1029 (NumArgs > 6) ||
1030 (SyncLevel > 15) ||
1031 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
1032 ASSERT (0);
1033 return EFI_INVALID_PARAMETER;
1034 }
1035
1036 ObjectNode = NULL;
1037 DataNode = NULL;
1038
1039 // ACPI 6.4, s20.2.5.2 "Named Objects Encoding":
1040 // DefMethod := MethodOp PkgLength NameString MethodFlags TermList
1041 // MethodOp := 0x14
1042 // So:
1043 // 1- Create the NameString
1044 // 2- Compute the size to write in the PkgLen
1045 // 3- Create nodes for the NameString and Method object node
1046 // 4- Set the NameString DataNode as a fixed argument
1047 // 5- Create and link the MethodFlags node
1048
1049 // 1- Create the NameString
1050 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
1051 if (EFI_ERROR (Status)) {
1052 ASSERT (0);
1053 return Status;
1054 }
1055
1056 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
1057 if (EFI_ERROR (Status)) {
1058 ASSERT (0);
1059 goto error_handler1;
1060 }
1061
1062 // 2- Compute the size to write in the PkgLen
1063 // Add 1 byte (ByteData) for MethodFlags.
1064 Status = AmlComputePkgLength (AmlNameStringSize + 1, &PkgLen);
1065 if (EFI_ERROR (Status)) {
1066 ASSERT (0);
1067 goto error_handler1;
1068 }
1069
1070 // 3- Create nodes for the NameString and Method object node
1071 Status = AmlCreateObjectNode (
1072 AmlGetByteEncodingByOpCode (AML_METHOD_OP, 0),
1073 PkgLen,
1074 &ObjectNode
1075 );
1076 if (EFI_ERROR (Status)) {
1077 ASSERT (0);
1078 goto error_handler1;
1079 }
1080
1081 Status = AmlCreateDataNode (
1082 EAmlNodeDataTypeNameString,
1083 (UINT8*)AmlNameString,
1084 AmlNameStringSize,
1085 &DataNode
1086 );
1087 if (EFI_ERROR (Status)) {
1088 ASSERT (0);
1089 goto error_handler2;
1090 }
1091
1092 // 4- Set the NameString DataNode as a fixed argument
1093 Status = AmlSetFixedArgument (
1094 ObjectNode,
1095 EAmlParseIndexTerm0,
1096 (AML_NODE_HEADER*)DataNode
1097 );
1098 if (EFI_ERROR (Status)) {
1099 ASSERT (0);
1100 goto error_handler2;
1101 }
1102
1103 DataNode = NULL;
1104
1105 // 5- Create and link the MethodFlags node
1106 Flags = NumArgs |
1107 (IsSerialized ? BIT3 : 0) |
1108 (SyncLevel << 4);
1109
1110 Status = AmlCreateDataNode (EAmlNodeDataTypeUInt, &Flags, 1, &DataNode);
1111 if (EFI_ERROR (Status)) {
1112 ASSERT (0);
1113 goto error_handler2;
1114 }
1115
1116 Status = AmlSetFixedArgument (
1117 ObjectNode,
1118 EAmlParseIndexTerm1,
1119 (AML_NODE_HEADER*)DataNode
1120 );
1121 if (EFI_ERROR (Status)) {
1122 ASSERT (0);
1123 goto error_handler2;
1124 }
1125
1126 // Data node is attached so set the pointer to
1127 // NULL to ensure correct error handling.
1128 DataNode = NULL;
1129
1130 Status = LinkNode (
1131 ObjectNode,
1132 ParentNode,
1133 NewObjectNode
1134 );
1135 if (EFI_ERROR (Status)) {
1136 ASSERT (0);
1137 goto error_handler2;
1138 }
1139
1140 // Free AmlNameString before returning as it is copied
1141 // in the call to AmlCreateDataNode().
1142 goto error_handler1;
1143
1144 error_handler2:
1145 if (ObjectNode != NULL) {
1146 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
1147 }
1148 if (DataNode != NULL) {
1149 AmlDeleteTree ((AML_NODE_HEADER*)DataNode);
1150 }
1151
1152 error_handler1:
1153 if (AmlNameString != NULL) {
1154 FreePool (AmlNameString);
1155 }
1156 return Status;
1157 }
1158
1159 /** AML code generation for a Return object node.
1160
1161 AmlCodeGenReturn (ReturnNode, ParentNode, NewObjectNode) is
1162 equivalent of the following ASL code:
1163 Return([Content of the ReturnNode])
1164
1165 The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
1166 DefReturn := ReturnOp ArgObject
1167 ReturnOp := 0xA4
1168 ArgObject := TermArg => DataRefObject
1169
1170 Thus, the ReturnNode must be evaluated as a DataRefObject. It can
1171 be a NameString referencing an object. As this CodeGen Api doesn't
1172 do semantic checking, it is strongly advised to check the AML bytecode
1173 generated by this function against an ASL compiler.
1174
1175 The ReturnNode must be generated inside a Method body scope.
1176
1177 @param [in] ReturnNode The object returned by the Return ASL statement.
1178 This node is deleted if an error occurs.
1179 @param [in] ParentNode If provided, set ParentNode as the parent
1180 of the node created.
1181 Must be a MethodOp node.
1182 @param [out] NewObjectNode If success, contains the created node.
1183
1184 @retval EFI_SUCCESS Success.
1185 @retval EFI_INVALID_PARAMETER Invalid parameter.
1186 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1187 **/
1188 STATIC
1189 EFI_STATUS
1190 EFIAPI
1191 AmlCodeGenReturn (
1192 IN AML_NODE_HEADER * ReturnNode,
1193 IN AML_NODE_HEADER * ParentNode OPTIONAL,
1194 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
1195 )
1196 {
1197 EFI_STATUS Status;
1198 AML_OBJECT_NODE * ObjectNode;
1199
1200 if ((ReturnNode == NULL) ||
1201 ((ParentNode == NULL) && (NewObjectNode == NULL)) ||
1202 ((ParentNode != NULL) &&
1203 !AmlNodeCompareOpCode (
1204 (AML_OBJECT_NODE*)ParentNode, AML_METHOD_OP, 0))) {
1205 ASSERT (0);
1206 return EFI_INVALID_PARAMETER;
1207 }
1208
1209 Status = AmlCreateObjectNode (
1210 AmlGetByteEncodingByOpCode (AML_RETURN_OP, 0),
1211 0,
1212 &ObjectNode
1213 );
1214 if (EFI_ERROR (Status)) {
1215 ASSERT (0);
1216 goto error_handler;
1217 }
1218
1219 Status = AmlSetFixedArgument (
1220 ObjectNode,
1221 EAmlParseIndexTerm0,
1222 (AML_NODE_HEADER*)ReturnNode
1223 );
1224 if (EFI_ERROR (Status)) {
1225 ASSERT (0);
1226 goto error_handler;
1227 }
1228
1229 ReturnNode = NULL;
1230
1231 Status = LinkNode (
1232 ObjectNode,
1233 ParentNode,
1234 NewObjectNode
1235 );
1236 if (EFI_ERROR (Status)) {
1237 ASSERT (0);
1238 goto error_handler;
1239 }
1240
1241 return Status;
1242
1243 error_handler:
1244 if (ReturnNode != NULL) {
1245 AmlDeleteTree (ReturnNode);
1246 }
1247 if (ObjectNode != NULL) {
1248 AmlDeleteTree ((AML_NODE_HEADER*)ObjectNode);
1249 }
1250 return Status;
1251 }
1252
1253 /** AML code generation for a Return object node,
1254 returning the object as an input NameString.
1255
1256 AmlCodeGenReturn ("NAM1", ParentNode, NewObjectNode) is
1257 equivalent of the following ASL code:
1258 Return(NAM1)
1259
1260 The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
1261 DefReturn := ReturnOp ArgObject
1262 ReturnOp := 0xA4
1263 ArgObject := TermArg => DataRefObject
1264
1265 Thus, the ReturnNode must be evaluated as a DataRefObject. It can
1266 be a NameString referencing an object. As this CodeGen Api doesn't
1267 do semantic checking, it is strongly advised to check the AML bytecode
1268 generated by this function against an ASL compiler.
1269
1270 The ReturnNode must be generated inside a Method body scope.
1271
1272 @param [in] NameString The object referenced by this NameString
1273 is returned by the Return ASL statement.
1274 Must be a NULL-terminated ASL NameString
1275 e.g.: "NAM1", "_SB.NAM1", etc.
1276 The input string is copied.
1277 @param [in] ParentNode If provided, set ParentNode as the parent
1278 of the node created.
1279 Must be a MethodOp node.
1280 @param [out] NewObjectNode If success, contains the created node.
1281
1282 @retval EFI_SUCCESS Success.
1283 @retval EFI_INVALID_PARAMETER Invalid parameter.
1284 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1285 **/
1286 STATIC
1287 EFI_STATUS
1288 EFIAPI
1289 AmlCodeGenReturnNameString (
1290 IN CONST CHAR8 * NameString,
1291 IN AML_NODE_HEADER * ParentNode OPTIONAL,
1292 OUT AML_OBJECT_NODE ** NewObjectNode OPTIONAL
1293 )
1294 {
1295 EFI_STATUS Status;
1296 AML_DATA_NODE * DataNode;
1297 CHAR8 * AmlNameString;
1298 UINT32 AmlNameStringSize;
1299
1300 DataNode = NULL;
1301
1302 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
1303 if (EFI_ERROR (Status)) {
1304 ASSERT (0);
1305 return Status;
1306 }
1307
1308 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
1309 if (EFI_ERROR (Status)) {
1310 ASSERT (0);
1311 goto exit_handler;
1312 }
1313
1314 Status = AmlCreateDataNode (
1315 EAmlNodeDataTypeNameString,
1316 (UINT8*)AmlNameString,
1317 AmlNameStringSize,
1318 &DataNode
1319 );
1320 if (EFI_ERROR (Status)) {
1321 ASSERT (0);
1322 goto exit_handler;
1323 }
1324
1325 // AmlCodeGenReturn() deletes DataNode if error.
1326 Status = AmlCodeGenReturn (
1327 (AML_NODE_HEADER*)DataNode,
1328 ParentNode,
1329 NewObjectNode
1330 );
1331 ASSERT_EFI_ERROR (Status);
1332
1333 exit_handler:
1334 if (AmlNameString != NULL) {
1335 FreePool (AmlNameString);
1336 }
1337 return Status;
1338 }
1339
1340 /** AML code generation for a method returning a NameString.
1341
1342 AmlCodeGenMethodRetNameString (
1343 "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
1344 );
1345 is equivalent of the following ASL code:
1346 Method(MET0, 1, Serialized, 3) {
1347 Return (_CRS)
1348 }
1349
1350 The ASL parameters "ReturnType" and "ParameterTypes" are not asked
1351 in this function. They are optional parameters in ASL.
1352
1353 @param [in] MethodNameString The new Method's name.
1354 Must be a NULL-terminated ASL NameString
1355 e.g.: "MET0", "_SB.MET0", etc.
1356 The input string is copied.
1357 @param [in] ReturnedNameString The name of the object returned by the
1358 method. Optional parameter, can be:
1359 - NULL (ignored).
1360 - A NULL-terminated ASL NameString.
1361 e.g.: "MET0", "_SB.MET0", etc.
1362 The input string is copied.
1363 @param [in] NumArgs Number of arguments.
1364 Must be 0 <= NumArgs <= 6.
1365 @param [in] IsSerialized TRUE is equivalent to Serialized.
1366 FALSE is equivalent to NotSerialized.
1367 Default is NotSerialized in ASL spec.
1368 @param [in] SyncLevel Synchronization level for the method.
1369 Must be 0 <= SyncLevel <= 15.
1370 Default is 0 in ASL.
1371 @param [in] ParentNode If provided, set ParentNode as the parent
1372 of the node created.
1373 @param [out] NewObjectNode If success, contains the created node.
1374
1375 @retval EFI_SUCCESS Success.
1376 @retval EFI_INVALID_PARAMETER Invalid parameter.
1377 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1378 **/
1379 EFI_STATUS
1380 EFIAPI
1381 AmlCodeGenMethodRetNameString (
1382 IN CONST CHAR8 * MethodNameString,
1383 IN CONST CHAR8 * ReturnedNameString OPTIONAL,
1384 IN UINT8 NumArgs,
1385 IN BOOLEAN IsSerialized,
1386 IN UINT8 SyncLevel,
1387 IN AML_NODE_HANDLE ParentNode OPTIONAL,
1388 OUT AML_OBJECT_NODE_HANDLE * NewObjectNode OPTIONAL
1389 )
1390 {
1391 EFI_STATUS Status;
1392 AML_OBJECT_NODE_HANDLE MethodNode;
1393
1394 if ((MethodNameString == NULL) ||
1395 ((ParentNode == NULL) && (NewObjectNode == NULL))) {
1396 ASSERT (0);
1397 return EFI_INVALID_PARAMETER;
1398 }
1399
1400 // Create a Method named MethodNameString.
1401 Status = AmlCodeGenMethod (
1402 MethodNameString,
1403 NumArgs,
1404 IsSerialized,
1405 SyncLevel,
1406 NULL,
1407 &MethodNode
1408 );
1409 if (EFI_ERROR (Status)) {
1410 ASSERT (0);
1411 return Status;
1412 }
1413
1414 // Return ReturnedNameString if provided.
1415 if (ReturnedNameString != NULL) {
1416 Status = AmlCodeGenReturnNameString (
1417 ReturnedNameString,
1418 (AML_NODE_HANDLE)MethodNode,
1419 NULL
1420 );
1421 if (EFI_ERROR (Status)) {
1422 ASSERT (0);
1423 goto error_handler;
1424 }
1425 }
1426
1427 Status = LinkNode (
1428 MethodNode,
1429 ParentNode,
1430 NewObjectNode
1431 );
1432 if (EFI_ERROR (Status)) {
1433 ASSERT (0);
1434 goto error_handler;
1435 }
1436
1437 return Status;
1438
1439 error_handler:
1440 if (MethodNode != NULL) {
1441 AmlDeleteTree ((AML_NODE_HANDLE)MethodNode);
1442 }
1443 return Status;
1444 }
1445
1446 /** Create a _LPI name.
1447
1448 AmlCreateLpiNode ("_LPI", 0, 1, ParentNode, &LpiNode) is
1449 equivalent of the following ASL code:
1450 Name (_LPI, Package (
1451 0, // Revision
1452 1, // LevelId
1453 0 // Count
1454 ))
1455
1456 This function doesn't define any LPI state. As shown above, the count
1457 of _LPI state is set to 0.
1458 The AmlAddLpiState () function allows to add LPI states.
1459
1460 Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
1461
1462 @param [in] LpiNameString The new LPI 's object name.
1463 Must be a NULL-terminated ASL NameString
1464 e.g.: "_LPI", "DEV0.PLPI", etc.
1465 The input string is copied.
1466 @param [in] Revision Revision number of the _LPI states.
1467 @param [in] LevelId A platform defined number that identifies the
1468 level of hierarchy of the processor node to
1469 which the LPI states apply.
1470 @param [in] ParentNode If provided, set ParentNode as the parent
1471 of the node created.
1472 @param [out] NewLpiNode If success, contains the created node.
1473
1474 @retval EFI_SUCCESS The function completed successfully.
1475 @retval EFI_INVALID_PARAMETER Invalid parameter.
1476 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1477 **/
1478 EFI_STATUS
1479 EFIAPI
1480 AmlCreateLpiNode (
1481 IN CONST CHAR8 * LpiNameString,
1482 IN UINT16 Revision,
1483 IN UINT64 LevelId,
1484 IN AML_NODE_HANDLE ParentNode OPTIONAL,
1485 OUT AML_OBJECT_NODE_HANDLE * NewLpiNode OPTIONAL
1486 )
1487 {
1488 EFI_STATUS Status;
1489 AML_OBJECT_NODE_HANDLE PackageNode;
1490 AML_OBJECT_NODE_HANDLE IntegerNode;
1491
1492 if ((LpiNameString == NULL) ||
1493 ((ParentNode == NULL) && (NewLpiNode == NULL))) {
1494 ASSERT (0);
1495 return EFI_INVALID_PARAMETER;
1496 }
1497
1498 IntegerNode = NULL;
1499
1500 Status = AmlCodeGenPackage (&PackageNode);
1501 if (EFI_ERROR (Status)) {
1502 ASSERT (0);
1503 return Status;
1504 }
1505
1506 // Create and attach Revision
1507 Status = AmlCodeGenInteger (Revision, &IntegerNode);
1508 if (EFI_ERROR (Status)) {
1509 ASSERT (0);
1510 IntegerNode = NULL;
1511 goto error_handler;
1512 }
1513
1514 Status = AmlVarListAddTail (
1515 (AML_NODE_HANDLE)PackageNode,
1516 (AML_NODE_HANDLE)IntegerNode
1517 );
1518 if (EFI_ERROR (Status)) {
1519 ASSERT (0);
1520 goto error_handler;
1521 }
1522
1523 IntegerNode = NULL;
1524
1525 // Create and attach LevelId
1526 Status = AmlCodeGenInteger (LevelId, &IntegerNode);
1527 if (EFI_ERROR (Status)) {
1528 ASSERT (0);
1529 IntegerNode = NULL;
1530 goto error_handler;
1531 }
1532
1533 Status = AmlVarListAddTail (
1534 (AML_NODE_HANDLE)PackageNode,
1535 (AML_NODE_HANDLE)IntegerNode
1536 );
1537 if (EFI_ERROR (Status)) {
1538 ASSERT (0);
1539 goto error_handler;
1540 }
1541
1542 IntegerNode = NULL;
1543
1544 // Create and attach Count. No LPI state is added, so 0.
1545 Status = AmlCodeGenInteger (0, &IntegerNode);
1546 if (EFI_ERROR (Status)) {
1547 ASSERT (0);
1548 IntegerNode = NULL;
1549 goto error_handler;
1550 }
1551
1552 Status = AmlVarListAddTail (
1553 (AML_NODE_HANDLE)PackageNode,
1554 (AML_NODE_HANDLE)IntegerNode
1555 );
1556 if (EFI_ERROR (Status)) {
1557 ASSERT (0);
1558 goto error_handler;
1559 }
1560
1561 IntegerNode = NULL;
1562
1563 Status = AmlCodeGenName (LpiNameString, PackageNode, ParentNode, NewLpiNode);
1564 if (EFI_ERROR (Status)) {
1565 ASSERT (0);
1566 goto error_handler;
1567 }
1568
1569 return Status;
1570
1571 error_handler:
1572 AmlDeleteTree ((AML_NODE_HANDLE)PackageNode);
1573 if (IntegerNode != NULL) {
1574 AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode);
1575 }
1576 return Status;
1577 }
1578
1579 /** Add an _LPI state to a LPI node created using AmlCreateLpiNode.
1580
1581 AmlAddLpiState increments the Count of LPI states in the LPI node by one,
1582 and adds the following package:
1583 Package() {
1584 MinResidency,
1585 WorstCaseWakeLatency,
1586 Flags,
1587 ArchFlags,
1588 ResCntFreq,
1589 EnableParentState,
1590 (GenericRegisterDescriptor != NULL) ? // Entry method. If a
1591 ResourceTemplate(GenericRegisterDescriptor) : // Register is given,
1592 Integer, // use it. Use the
1593 // Integer otherwise.
1594 ResourceTemplate() { // NULL Residency Counter
1595 Register (SystemMemory, 0, 0, 0, 0)
1596 },
1597 ResourceTemplate() { // NULL Usage Counter
1598 Register (SystemMemory, 0, 0, 0, 0)
1599 },
1600 "" // NULL State Name
1601 },
1602
1603 Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
1604
1605 @param [in] MinResidency Minimum Residency.
1606 @param [in] WorstCaseWakeLatency Worst case wake-up latency.
1607 @param [in] Flags Flags.
1608 @param [in] ArchFlags Architectural flags.
1609 @param [in] ResCntFreq Residency Counter Frequency.
1610 @param [in] EnableParentState Enabled Parent State.
1611 @param [in] GenericRegisterDescriptor Entry Method.
1612 If not NULL, use this Register to
1613 describe the entry method address.
1614 @param [in] Integer Entry Method.
1615 If GenericRegisterDescriptor is NULL,
1616 take this value.
1617 @param [in] ResidencyCounterRegister If not NULL, use it to populate the
1618 residency counter register.
1619 @param [in] UsageCounterRegister If not NULL, use it to populate the
1620 usage counter register.
1621 @param [in] StateName If not NULL, use it to populate the
1622 state name.
1623 @param [in] LpiNode Lpi node created with the function
1624 AmlCreateLpiNode to which the new LPI
1625 state is appended.
1626
1627 @retval EFI_SUCCESS The function completed successfully.
1628 @retval EFI_INVALID_PARAMETER Invalid parameter.
1629 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1630 **/
1631 EFI_STATUS
1632 EFIAPI
1633 AmlAddLpiState (
1634 IN UINT32 MinResidency,
1635 IN UINT32 WorstCaseWakeLatency,
1636 IN UINT32 Flags,
1637 IN UINT32 ArchFlags,
1638 IN UINT32 ResCntFreq,
1639 IN UINT32 EnableParentState,
1640 IN EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE * GenericRegisterDescriptor OPTIONAL,
1641 IN UINT64 Integer OPTIONAL,
1642 IN EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE * ResidencyCounterRegister OPTIONAL,
1643 IN EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE * UsageCounterRegister OPTIONAL,
1644 IN CHAR8 * StateName OPTIONAL,
1645 IN AML_OBJECT_NODE_HANDLE LpiNode
1646 )
1647 {
1648 EFI_STATUS Status;
1649 AML_DATA_NODE_HANDLE RdNode;
1650 AML_OBJECT_NODE_HANDLE PackageNode;
1651 AML_OBJECT_NODE_HANDLE IntegerNode;
1652 AML_OBJECT_NODE_HANDLE StringNode;
1653 AML_OBJECT_NODE_HANDLE NewLpiPackageNode;
1654 AML_OBJECT_NODE_HANDLE ResourceTemplateNode;
1655
1656 UINT32 Index;
1657 AML_OBJECT_NODE_HANDLE CountNode;
1658 UINT64 Count;
1659
1660 if ((LpiNode == NULL) ||
1661 (AmlGetNodeType ((AML_NODE_HANDLE)LpiNode) != EAmlNodeObject) ||
1662 (!AmlNodeHasOpCode (LpiNode, AML_NAME_OP, 0))) {
1663 ASSERT (0);
1664 return EFI_INVALID_PARAMETER;
1665 }
1666
1667 RdNode = 0;
1668 StringNode = NULL;
1669 IntegerNode = NULL;
1670 ResourceTemplateNode = NULL;
1671
1672 // AmlCreateLpiNode () created a LPI container such as:
1673 // Name (_LPI, Package (
1674 // 0, // Revision
1675 // 1, // LevelId
1676 // 0 // Count
1677 // ))
1678 // Get the LPI container, a PackageOp object node stored as the 2nd fixed
1679 // argument (i.e. index 1) of LpiNode.
1680 PackageNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
1681 LpiNode,
1682 EAmlParseIndexTerm1
1683 );
1684 if ((PackageNode == NULL) ||
1685 (AmlGetNodeType ((AML_NODE_HANDLE)PackageNode) != EAmlNodeObject) ||
1686 (!AmlNodeHasOpCode (PackageNode, AML_PACKAGE_OP, 0))) {
1687 ASSERT (0);
1688 return EFI_INVALID_PARAMETER;
1689 }
1690
1691 CountNode = NULL;
1692 // The third variable argument is the LPI Count node.
1693 for (Index = 0; Index < 3; Index++) {
1694 CountNode = (AML_OBJECT_NODE_HANDLE)AmlGetNextVariableArgument (
1695 (AML_NODE_HANDLE)PackageNode,
1696 (AML_NODE_HANDLE)CountNode
1697 );
1698 if (CountNode == NULL) {
1699 ASSERT (0);
1700 return EFI_INVALID_PARAMETER;
1701 }
1702 }
1703
1704 Status = AmlNodeGetIntegerValue (CountNode, &Count);
1705 if (EFI_ERROR (Status)) {
1706 ASSERT (0);
1707 return Status;
1708 }
1709 Status = AmlUpdateInteger (CountNode, Count + 1);
1710 if (EFI_ERROR (Status)) {
1711 ASSERT (0);
1712 return Status;
1713 }
1714
1715 Status = AmlCodeGenPackage (&NewLpiPackageNode);
1716 if (EFI_ERROR (Status)) {
1717 ASSERT (0);
1718 return Status;
1719 }
1720
1721 // MinResidency
1722 Status = AmlCodeGenInteger (MinResidency, &IntegerNode);
1723 if (EFI_ERROR (Status)) {
1724 ASSERT (0);
1725 IntegerNode = NULL;
1726 goto error_handler;
1727 }
1728 Status = AmlVarListAddTail (
1729 (AML_NODE_HANDLE)NewLpiPackageNode,
1730 (AML_NODE_HANDLE)IntegerNode
1731 );
1732 if (EFI_ERROR (Status)) {
1733 ASSERT (0);
1734 goto error_handler;
1735 }
1736 IntegerNode = NULL;
1737
1738 // WorstCaseWakeLatency
1739 Status = AmlCodeGenInteger (WorstCaseWakeLatency, &IntegerNode);
1740 if (EFI_ERROR (Status)) {
1741 ASSERT (0);
1742 IntegerNode = NULL;
1743 goto error_handler;
1744 }
1745 Status = AmlVarListAddTail (
1746 (AML_NODE_HANDLE)NewLpiPackageNode,
1747 (AML_NODE_HANDLE)IntegerNode
1748 );
1749 if (EFI_ERROR (Status)) {
1750 ASSERT (0);
1751 goto error_handler;
1752 }
1753 IntegerNode = NULL;
1754
1755 // Flags
1756 Status = AmlCodeGenInteger (Flags, &IntegerNode);
1757 if (EFI_ERROR (Status)) {
1758 ASSERT (0);
1759 IntegerNode = NULL;
1760 goto error_handler;
1761 }
1762 Status = AmlVarListAddTail (
1763 (AML_NODE_HANDLE)NewLpiPackageNode,
1764 (AML_NODE_HANDLE)IntegerNode
1765 );
1766 if (EFI_ERROR (Status)) {
1767 ASSERT (0);
1768 goto error_handler;
1769 }
1770 IntegerNode = NULL;
1771
1772 // ArchFlags
1773 Status = AmlCodeGenInteger (ArchFlags, &IntegerNode);
1774 if (EFI_ERROR (Status)) {
1775 ASSERT (0);
1776 IntegerNode = NULL;
1777 goto error_handler;
1778 }
1779 Status = AmlVarListAddTail (
1780 (AML_NODE_HANDLE)NewLpiPackageNode,
1781 (AML_NODE_HANDLE)IntegerNode
1782 );
1783 if (EFI_ERROR (Status)) {
1784 ASSERT (0);
1785 goto error_handler;
1786 }
1787 IntegerNode = NULL;
1788
1789 // ResCntFreq
1790 Status = AmlCodeGenInteger (ResCntFreq, &IntegerNode);
1791 if (EFI_ERROR (Status)) {
1792 ASSERT (0);
1793 IntegerNode = NULL;
1794 goto error_handler;
1795 }
1796 Status = AmlVarListAddTail (
1797 (AML_NODE_HANDLE)NewLpiPackageNode,
1798 (AML_NODE_HANDLE)IntegerNode
1799 );
1800 if (EFI_ERROR (Status)) {
1801 ASSERT (0);
1802 goto error_handler;
1803 }
1804 IntegerNode = NULL;
1805
1806 // EnableParentState
1807 Status = AmlCodeGenInteger (EnableParentState, &IntegerNode);
1808 if (EFI_ERROR (Status)) {
1809 ASSERT (0);
1810 IntegerNode = NULL;
1811 goto error_handler;
1812 }
1813 Status = AmlVarListAddTail (
1814 (AML_NODE_HANDLE)NewLpiPackageNode,
1815 (AML_NODE_HANDLE)IntegerNode
1816 );
1817 if (EFI_ERROR (Status)) {
1818 ASSERT (0);
1819 goto error_handler;
1820 }
1821 IntegerNode = NULL;
1822
1823 // Entry Method
1824 if (GenericRegisterDescriptor != NULL) {
1825 // Entry Method: As a Register resource data
1826 Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
1827 if (EFI_ERROR (Status)) {
1828 ASSERT (0);
1829 ResourceTemplateNode = NULL;
1830 goto error_handler;
1831 }
1832 Status = AmlCodeGenRdRegister (
1833 GenericRegisterDescriptor->AddressSpaceId,
1834 GenericRegisterDescriptor->RegisterBitWidth,
1835 GenericRegisterDescriptor->RegisterBitOffset,
1836 GenericRegisterDescriptor->Address,
1837 GenericRegisterDescriptor->AccessSize,
1838 NULL,
1839 &RdNode
1840 );
1841 if (EFI_ERROR (Status)) {
1842 ASSERT (0);
1843 RdNode = NULL;
1844 goto error_handler;
1845 }
1846
1847 Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
1848 if (EFI_ERROR (Status)) {
1849 ASSERT (0);
1850 goto error_handler;
1851 }
1852 RdNode = NULL;
1853
1854 Status = AmlVarListAddTail (
1855 (AML_NODE_HANDLE)NewLpiPackageNode,
1856 (AML_NODE_HANDLE)ResourceTemplateNode
1857 );
1858 if (EFI_ERROR (Status)) {
1859 ASSERT (0);
1860 goto error_handler;
1861 }
1862 ResourceTemplateNode = NULL;
1863 } else {
1864 // Entry Method: As an integer
1865 Status = AmlCodeGenInteger (Integer, &IntegerNode);
1866 if (EFI_ERROR (Status)) {
1867 ASSERT (0);
1868 IntegerNode = NULL;
1869 goto error_handler;
1870 }
1871 Status = AmlVarListAddTail (
1872 (AML_NODE_HANDLE)NewLpiPackageNode,
1873 (AML_NODE_HANDLE)IntegerNode
1874 );
1875 if (EFI_ERROR (Status)) {
1876 ASSERT (0);
1877 goto error_handler;
1878 }
1879 IntegerNode = NULL;
1880 }
1881
1882 // Residency Counter Register.
1883 Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
1884 if (EFI_ERROR (Status)) {
1885 ASSERT (0);
1886 ResourceTemplateNode = NULL;
1887 goto error_handler;
1888 }
1889 if (ResidencyCounterRegister != NULL) {
1890 Status = AmlCodeGenRdRegister (
1891 ResidencyCounterRegister->AddressSpaceId,
1892 ResidencyCounterRegister->RegisterBitWidth,
1893 ResidencyCounterRegister->RegisterBitOffset,
1894 ResidencyCounterRegister->Address,
1895 ResidencyCounterRegister->AccessSize,
1896 NULL,
1897 &RdNode
1898 );
1899 } else {
1900 Status = AmlCodeGenRdRegister (
1901 EFI_ACPI_6_4_SYSTEM_MEMORY,
1902 0,
1903 0,
1904 0,
1905 0,
1906 NULL,
1907 &RdNode
1908 );
1909 }
1910 if (EFI_ERROR (Status)) {
1911 ASSERT (0);
1912 RdNode = NULL;
1913 goto error_handler;
1914 }
1915
1916 Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
1917 if (EFI_ERROR (Status)) {
1918 ASSERT (0);
1919 goto error_handler;
1920 }
1921 RdNode = NULL;
1922
1923 Status = AmlVarListAddTail (
1924 (AML_NODE_HANDLE)NewLpiPackageNode,
1925 (AML_NODE_HANDLE)ResourceTemplateNode
1926 );
1927 if (EFI_ERROR (Status)) {
1928 ASSERT (0);
1929 goto error_handler;
1930 }
1931 ResourceTemplateNode = NULL;
1932
1933 // Usage Counter Register.
1934 Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
1935 if (EFI_ERROR (Status)) {
1936 ASSERT (0);
1937 ResourceTemplateNode = NULL;
1938 goto error_handler;
1939 }
1940 if (UsageCounterRegister != NULL) {
1941 Status = AmlCodeGenRdRegister (
1942 UsageCounterRegister->AddressSpaceId,
1943 UsageCounterRegister->RegisterBitWidth,
1944 UsageCounterRegister->RegisterBitOffset,
1945 UsageCounterRegister->Address,
1946 UsageCounterRegister->AccessSize,
1947 NULL,
1948 &RdNode
1949 );
1950 } else {
1951 Status = AmlCodeGenRdRegister (
1952 EFI_ACPI_6_4_SYSTEM_MEMORY,
1953 0,
1954 0,
1955 0,
1956 0,
1957 NULL,
1958 &RdNode
1959 );
1960 }
1961 if (EFI_ERROR (Status)) {
1962 ASSERT (0);
1963 RdNode = NULL;
1964 goto error_handler;
1965 }
1966
1967 Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
1968 if (EFI_ERROR (Status)) {
1969 ASSERT (0);
1970 goto error_handler;
1971 }
1972 RdNode = NULL;
1973
1974 Status = AmlVarListAddTail (
1975 (AML_NODE_HANDLE)NewLpiPackageNode,
1976 (AML_NODE_HANDLE)ResourceTemplateNode
1977 );
1978 if (EFI_ERROR (Status)) {
1979 ASSERT (0);
1980 goto error_handler;
1981 }
1982 ResourceTemplateNode = NULL;
1983
1984 // State name.
1985 if (UsageCounterRegister != NULL) {
1986 Status = AmlCodeGenString (StateName, &StringNode);
1987 } else {
1988 Status = AmlCodeGenString ("", &StringNode);
1989 }
1990 if (EFI_ERROR (Status)) {
1991 ASSERT (0);
1992 StringNode = NULL;
1993 goto error_handler;
1994 }
1995 Status = AmlVarListAddTail (
1996 (AML_NODE_HANDLE)NewLpiPackageNode,
1997 (AML_NODE_HANDLE)StringNode
1998 );
1999 if (EFI_ERROR (Status)) {
2000 ASSERT (0);
2001 goto error_handler;
2002 }
2003 StringNode = NULL;
2004
2005 // Add the new LPI state to the LpiNode.
2006 Status = AmlVarListAddTail (
2007 (AML_NODE_HANDLE)PackageNode,
2008 (AML_NODE_HANDLE)NewLpiPackageNode
2009 );
2010 if (EFI_ERROR (Status)) {
2011 ASSERT (0);
2012 goto error_handler;
2013 }
2014
2015 return Status;
2016
2017 error_handler:
2018 if (RdNode != NULL) {
2019 AmlDeleteTree ((AML_NODE_HANDLE)RdNode);
2020 }
2021 if (NewLpiPackageNode != NULL) {
2022 AmlDeleteTree ((AML_NODE_HANDLE)NewLpiPackageNode);
2023 }
2024 if (StringNode != NULL) {
2025 AmlDeleteTree ((AML_NODE_HANDLE)StringNode);
2026 }
2027 if (IntegerNode != NULL) {
2028 AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode);
2029 }
2030 if (ResourceTemplateNode != NULL) {
2031 AmlDeleteTree ((AML_NODE_HANDLE)ResourceTemplateNode);
2032 }
2033
2034 return Status;
2035 }