]> git.proxmox.com Git - mirror_edk2.git/blob - DynamicTablesPkg/Library/Common/AmlLib/CodeGen/AmlCodeGen.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / AmlLib / CodeGen / AmlCodeGen.c
1 /** @file
2 AML Code Generation.
3
4 Copyright (c) 2020 - 2022, 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 <AmlCpcInfo.h>
15 #include <AmlEncoding/Aml.h>
16 #include <Api/AmlApiHelper.h>
17 #include <CodeGen/AmlResourceDataCodeGen.h>
18 #include <Tree/AmlNode.h>
19 #include <Tree/AmlTree.h>
20 #include <String/AmlString.h>
21 #include <Utils/AmlUtility.h>
22
23 /** Utility function to link a node when returning from a CodeGen function.
24
25 @param [in] Node Newly created node.
26 @param [in] ParentNode If provided, set ParentNode as the parent
27 of the node created.
28 @param [out] NewObjectNode If not NULL:
29 - and Success, contains the created Node.
30 - and Error, reset to NULL.
31
32 @retval EFI_SUCCESS The function completed successfully.
33 @retval EFI_INVALID_PARAMETER Invalid parameter.
34 **/
35 STATIC
36 EFI_STATUS
37 EFIAPI
38 LinkNode (
39 IN AML_OBJECT_NODE *Node,
40 IN AML_NODE_HEADER *ParentNode,
41 OUT AML_OBJECT_NODE **NewObjectNode
42 )
43 {
44 EFI_STATUS Status;
45
46 if (NewObjectNode != NULL) {
47 *NewObjectNode = NULL;
48 }
49
50 // Add RdNode as the last element.
51 if (ParentNode != NULL) {
52 Status = AmlVarListAddTail (ParentNode, (AML_NODE_HEADER *)Node);
53 if (EFI_ERROR (Status)) {
54 ASSERT (0);
55 return Status;
56 }
57 }
58
59 if (NewObjectNode != NULL) {
60 *NewObjectNode = Node;
61 }
62
63 return EFI_SUCCESS;
64 }
65
66 /** AML code generation for DefinitionBlock.
67
68 Create a Root Node handle.
69 It is the caller's responsibility to free the allocated memory
70 with the AmlDeleteTree function.
71
72 AmlCodeGenDefinitionBlock (TableSignature, OemID, TableID, OEMRevision) is
73 equivalent to the following ASL code:
74 DefinitionBlock (AMLFileName, TableSignature, ComplianceRevision,
75 OemID, TableID, OEMRevision) {}
76 with the ComplianceRevision set to 2 and the AMLFileName is ignored.
77
78 @param[in] TableSignature 4-character ACPI signature.
79 Must be 'DSDT' or 'SSDT'.
80 @param[in] OemId 6-character string OEM identifier.
81 @param[in] OemTableId 8-character string OEM table identifier.
82 @param[in] OemRevision OEM revision number.
83 @param[out] NewRootNode Pointer to the root node representing a
84 Definition Block.
85
86 @retval EFI_SUCCESS Success.
87 @retval EFI_INVALID_PARAMETER Invalid parameter.
88 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
89 **/
90 EFI_STATUS
91 EFIAPI
92 AmlCodeGenDefinitionBlock (
93 IN CONST CHAR8 *TableSignature,
94 IN CONST CHAR8 *OemId,
95 IN CONST CHAR8 *OemTableId,
96 IN UINT32 OemRevision,
97 OUT AML_ROOT_NODE **NewRootNode
98 )
99 {
100 EFI_STATUS Status;
101 EFI_ACPI_DESCRIPTION_HEADER AcpiHeader;
102
103 if ((TableSignature == NULL) ||
104 (OemId == NULL) ||
105 (OemTableId == NULL) ||
106 (NewRootNode == NULL))
107 {
108 ASSERT (0);
109 return EFI_INVALID_PARAMETER;
110 }
111
112 CopyMem (&AcpiHeader.Signature, TableSignature, 4);
113 AcpiHeader.Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
114 AcpiHeader.Revision = 2;
115 CopyMem (&AcpiHeader.OemId, OemId, 6);
116 CopyMem (&AcpiHeader.OemTableId, OemTableId, 8);
117 AcpiHeader.OemRevision = OemRevision;
118 AcpiHeader.CreatorId = TABLE_GENERATOR_CREATOR_ID_ARM;
119 AcpiHeader.CreatorRevision = CREATE_REVISION (1, 0);
120
121 Status = AmlCreateRootNode (&AcpiHeader, NewRootNode);
122 ASSERT_EFI_ERROR (Status);
123
124 return Status;
125 }
126
127 /** AML code generation for a String object node.
128
129 @param [in] String Pointer to a NULL terminated string.
130 @param [out] NewObjectNode If success, contains the created
131 String object node.
132
133 @retval EFI_SUCCESS Success.
134 @retval EFI_INVALID_PARAMETER Invalid parameter.
135 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
136 **/
137 STATIC
138 EFI_STATUS
139 EFIAPI
140 AmlCodeGenString (
141 IN CHAR8 *String,
142 OUT AML_OBJECT_NODE **NewObjectNode
143 )
144 {
145 EFI_STATUS Status;
146 AML_OBJECT_NODE *ObjectNode;
147 AML_DATA_NODE *DataNode;
148
149 if ((String == NULL) ||
150 (NewObjectNode == NULL))
151 {
152 ASSERT (0);
153 return EFI_INVALID_PARAMETER;
154 }
155
156 DataNode = NULL;
157
158 Status = AmlCreateObjectNode (
159 AmlGetByteEncodingByOpCode (AML_STRING_PREFIX, 0),
160 0,
161 &ObjectNode
162 );
163 if (EFI_ERROR (Status)) {
164 ASSERT (0);
165 return Status;
166 }
167
168 Status = AmlCreateDataNode (
169 EAmlNodeDataTypeString,
170 (UINT8 *)String,
171 (UINT32)AsciiStrLen (String) + 1,
172 &DataNode
173 );
174 if (EFI_ERROR (Status)) {
175 ASSERT (0);
176 goto error_handler;
177 }
178
179 Status = AmlSetFixedArgument (
180 ObjectNode,
181 EAmlParseIndexTerm0,
182 (AML_NODE_HEADER *)DataNode
183 );
184 if (EFI_ERROR (Status)) {
185 ASSERT (0);
186 AmlDeleteTree ((AML_NODE_HEADER *)DataNode);
187 goto error_handler;
188 }
189
190 *NewObjectNode = ObjectNode;
191 return Status;
192
193 error_handler:
194 AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode);
195 return Status;
196 }
197
198 /** AML code generation for an Integer object node.
199
200 @param [in] Integer Integer of the Integer object node.
201 @param [out] NewObjectNode If success, contains the created
202 Integer object node.
203
204 @retval EFI_SUCCESS Success.
205 @retval EFI_INVALID_PARAMETER Invalid parameter.
206 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
207 **/
208 STATIC
209 EFI_STATUS
210 EFIAPI
211 AmlCodeGenInteger (
212 IN UINT64 Integer,
213 OUT AML_OBJECT_NODE **NewObjectNode
214 )
215 {
216 EFI_STATUS Status;
217 INT8 ValueWidthDiff;
218
219 if (NewObjectNode == NULL) {
220 ASSERT (0);
221 return EFI_INVALID_PARAMETER;
222 }
223
224 // Create an object node containing Zero.
225 Status = AmlCreateObjectNode (
226 AmlGetByteEncodingByOpCode (AML_ZERO_OP, 0),
227 0,
228 NewObjectNode
229 );
230 if (EFI_ERROR (Status)) {
231 ASSERT (0);
232 return Status;
233 }
234
235 // Update the object node with integer value.
236 Status = AmlNodeSetIntegerValue (*NewObjectNode, Integer, &ValueWidthDiff);
237 if (EFI_ERROR (Status)) {
238 ASSERT (0);
239 AmlDeleteTree ((AML_NODE_HEADER *)*NewObjectNode);
240 }
241
242 return Status;
243 }
244
245 /** AML code generation for a Package object node.
246
247 The package generated is empty. New elements can be added via its
248 list of variable arguments.
249
250 @param [out] NewObjectNode If success, contains the created
251 Package object node.
252
253 @retval EFI_SUCCESS Success.
254 @retval EFI_INVALID_PARAMETER Invalid parameter.
255 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
256 **/
257 STATIC
258 EFI_STATUS
259 EFIAPI
260 AmlCodeGenPackage (
261 OUT AML_OBJECT_NODE **NewObjectNode
262 )
263 {
264 EFI_STATUS Status;
265 AML_DATA_NODE *DataNode;
266 UINT8 NodeCount;
267
268 if (NewObjectNode == NULL) {
269 ASSERT (0);
270 return EFI_INVALID_PARAMETER;
271 }
272
273 NodeCount = 0;
274
275 // Create an object node.
276 // PkgLen is 2:
277 // - one byte to store the PkgLength
278 // - one byte for the NumElements.
279 // Cf ACPI6.3, s20.2.5 "Term Objects Encoding"
280 // DefPackage := PackageOp PkgLength NumElements PackageElementList
281 // NumElements := ByteData
282 Status = AmlCreateObjectNode (
283 AmlGetByteEncodingByOpCode (AML_PACKAGE_OP, 0),
284 2,
285 NewObjectNode
286 );
287 if (EFI_ERROR (Status)) {
288 ASSERT (0);
289 return Status;
290 }
291
292 // NumElements is a ByteData.
293 Status = AmlCreateDataNode (
294 EAmlNodeDataTypeUInt,
295 &NodeCount,
296 sizeof (NodeCount),
297 &DataNode
298 );
299 if (EFI_ERROR (Status)) {
300 ASSERT (0);
301 goto error_handler;
302 }
303
304 Status = AmlSetFixedArgument (
305 *NewObjectNode,
306 EAmlParseIndexTerm0,
307 (AML_NODE_HEADER *)DataNode
308 );
309 if (EFI_ERROR (Status)) {
310 ASSERT (0);
311 goto error_handler;
312 }
313
314 return Status;
315
316 error_handler:
317 AmlDeleteTree ((AML_NODE_HEADER *)*NewObjectNode);
318 if (DataNode != NULL) {
319 AmlDeleteTree ((AML_NODE_HEADER *)DataNode);
320 }
321
322 return Status;
323 }
324
325 /** AML code generation for a Buffer object node.
326
327 To create a Buffer object node with an empty buffer,
328 call the function with (Buffer=NULL, BufferSize=0).
329
330 @param [in] Buffer Buffer to set for the created Buffer
331 object node. The Buffer's content is copied.
332 NULL if there is no buffer to set for
333 the Buffer node.
334 @param [in] BufferSize Size of the Buffer.
335 0 if there is no buffer to set for
336 the Buffer node.
337 @param [out] NewObjectNode If success, contains the created
338 Buffer object node.
339
340 @retval EFI_SUCCESS Success.
341 @retval EFI_INVALID_PARAMETER Invalid parameter.
342 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
343 **/
344 STATIC
345 EFI_STATUS
346 EFIAPI
347 AmlCodeGenBuffer (
348 IN CONST UINT8 *Buffer OPTIONAL,
349 IN UINT32 BufferSize OPTIONAL,
350 OUT AML_OBJECT_NODE **NewObjectNode
351 )
352 {
353 EFI_STATUS Status;
354 AML_OBJECT_NODE *BufferNode;
355 AML_OBJECT_NODE *BufferSizeNode;
356 UINT32 BufferSizeNodeSize;
357 AML_DATA_NODE *DataNode;
358 UINT32 PkgLen;
359
360 // Buffer and BufferSize must be either both set, or both clear.
361 if ((NewObjectNode == NULL) ||
362 ((Buffer == NULL) != (BufferSize == 0)))
363 {
364 ASSERT (0);
365 return EFI_INVALID_PARAMETER;
366 }
367
368 BufferNode = NULL;
369 DataNode = NULL;
370
371 // Cf ACPI 6.3 specification, s20.2.5.4 "Type 2 Opcodes Encoding"
372 // DefBuffer := BufferOp PkgLength BufferSize ByteList
373 // BufferOp := 0x11
374 // BufferSize := TermArg => Integer
375
376 Status = AmlCodeGenInteger (BufferSize, &BufferSizeNode);
377 if (EFI_ERROR (Status)) {
378 ASSERT (0);
379 return Status;
380 }
381
382 // Get the number of bytes required to encode the BufferSizeNode.
383 Status = AmlComputeSize (
384 (AML_NODE_HEADER *)BufferSizeNode,
385 &BufferSizeNodeSize
386 );
387 if (EFI_ERROR (Status)) {
388 ASSERT (0);
389 goto error_handler;
390 }
391
392 // Compute the size to write in the PkgLen.
393 Status = AmlComputePkgLength (BufferSizeNodeSize + BufferSize, &PkgLen);
394 if (EFI_ERROR (Status)) {
395 ASSERT (0);
396 goto error_handler;
397 }
398
399 // Create an object node for the buffer.
400 Status = AmlCreateObjectNode (
401 AmlGetByteEncodingByOpCode (AML_BUFFER_OP, 0),
402 PkgLen,
403 &BufferNode
404 );
405 if (EFI_ERROR (Status)) {
406 ASSERT (0);
407 goto error_handler;
408 }
409
410 // Set the BufferSizeNode as a fixed argument of the BufferNode.
411 Status = AmlSetFixedArgument (
412 BufferNode,
413 EAmlParseIndexTerm0,
414 (AML_NODE_HEADER *)BufferSizeNode
415 );
416 if (EFI_ERROR (Status)) {
417 ASSERT (0);
418 goto error_handler;
419 }
420
421 // BufferSizeNode is now attached.
422 BufferSizeNode = NULL;
423
424 // If there is a buffer, create a DataNode and attach it to the BufferNode.
425 if (Buffer != NULL) {
426 Status = AmlCreateDataNode (
427 EAmlNodeDataTypeRaw,
428 Buffer,
429 BufferSize,
430 &DataNode
431 );
432 if (EFI_ERROR (Status)) {
433 ASSERT (0);
434 goto error_handler;
435 }
436
437 Status = AmlVarListAddTail (
438 (AML_NODE_HEADER *)BufferNode,
439 (AML_NODE_HEADER *)DataNode
440 );
441 if (EFI_ERROR (Status)) {
442 ASSERT (0);
443 goto error_handler;
444 }
445 }
446
447 *NewObjectNode = BufferNode;
448 return Status;
449
450 error_handler:
451 if (BufferSizeNode != NULL) {
452 AmlDeleteTree ((AML_NODE_HEADER *)BufferSizeNode);
453 }
454
455 if (BufferNode != NULL) {
456 AmlDeleteTree ((AML_NODE_HEADER *)BufferNode);
457 }
458
459 if (DataNode != NULL) {
460 AmlDeleteTree ((AML_NODE_HEADER *)DataNode);
461 }
462
463 return Status;
464 }
465
466 /** AML code generation for a ResourceTemplate.
467
468 "ResourceTemplate" is a macro defined in ACPI 6.3, s19.3.3
469 "ASL Resource Templates". It allows to store resource data elements.
470
471 In AML, a ResourceTemplate is implemented as a Buffer storing resource
472 data elements. An EndTag resource data descriptor must be at the end
473 of the list of resource data elements.
474 This function generates a Buffer node with an EndTag resource data
475 descriptor. It can be seen as an empty list of resource data elements.
476
477 @param [out] NewObjectNode If success, contains the created
478 ResourceTemplate object node.
479
480 @retval EFI_SUCCESS Success.
481 @retval EFI_INVALID_PARAMETER Invalid parameter.
482 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
483 **/
484 STATIC
485 EFI_STATUS
486 EFIAPI
487 AmlCodeGenResourceTemplate (
488 OUT AML_OBJECT_NODE **NewObjectNode
489 )
490 {
491 EFI_STATUS Status;
492 AML_OBJECT_NODE *BufferNode;
493
494 if (NewObjectNode == NULL) {
495 ASSERT (0);
496 return EFI_INVALID_PARAMETER;
497 }
498
499 // Create a BufferNode with an empty buffer.
500 Status = AmlCodeGenBuffer (NULL, 0, &BufferNode);
501 if (EFI_ERROR (Status)) {
502 ASSERT (0);
503 return Status;
504 }
505
506 // Create an EndTag resource data element and attach it to the Buffer.
507 Status = AmlCodeGenEndTag (0, BufferNode, NULL);
508 if (EFI_ERROR (Status)) {
509 ASSERT (0);
510 AmlDeleteTree ((AML_NODE_HEADER *)BufferNode);
511 return Status;
512 }
513
514 *NewObjectNode = BufferNode;
515 return Status;
516 }
517
518 /** AML code generation for a Name object node.
519
520 @param [in] NameString The new variable name.
521 Must be a NULL-terminated ASL NameString
522 e.g.: "DEV0", "DV15.DEV0", etc.
523 This input string is copied.
524 @param [in] Object Object associated to the NameString.
525 @param [in] ParentNode If provided, set ParentNode as the parent
526 of the node created.
527 @param [out] NewObjectNode If success, contains the created node.
528
529 @retval EFI_SUCCESS Success.
530 @retval EFI_INVALID_PARAMETER Invalid parameter.
531 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
532 **/
533 STATIC
534 EFI_STATUS
535 EFIAPI
536 AmlCodeGenName (
537 IN CONST CHAR8 *NameString,
538 IN AML_OBJECT_NODE *Object,
539 IN AML_NODE_HEADER *ParentNode OPTIONAL,
540 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
541 )
542 {
543 EFI_STATUS Status;
544 AML_OBJECT_NODE *ObjectNode;
545 AML_DATA_NODE *DataNode;
546 CHAR8 *AmlNameString;
547 UINT32 AmlNameStringSize;
548
549 if ((NameString == NULL) ||
550 (Object == NULL) ||
551 ((ParentNode == NULL) && (NewObjectNode == NULL)))
552 {
553 ASSERT (0);
554 return EFI_INVALID_PARAMETER;
555 }
556
557 ObjectNode = NULL;
558 DataNode = NULL;
559 AmlNameString = NULL;
560
561 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
562 if (EFI_ERROR (Status)) {
563 ASSERT (0);
564 return Status;
565 }
566
567 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
568 if (EFI_ERROR (Status)) {
569 ASSERT (0);
570 goto error_handler1;
571 }
572
573 Status = AmlCreateObjectNode (
574 AmlGetByteEncodingByOpCode (AML_NAME_OP, 0),
575 0,
576 &ObjectNode
577 );
578 if (EFI_ERROR (Status)) {
579 ASSERT (0);
580 goto error_handler1;
581 }
582
583 Status = AmlCreateDataNode (
584 EAmlNodeDataTypeNameString,
585 (UINT8 *)AmlNameString,
586 AmlNameStringSize,
587 &DataNode
588 );
589 if (EFI_ERROR (Status)) {
590 ASSERT (0);
591 goto error_handler2;
592 }
593
594 Status = AmlSetFixedArgument (
595 ObjectNode,
596 EAmlParseIndexTerm0,
597 (AML_NODE_HEADER *)DataNode
598 );
599 if (EFI_ERROR (Status)) {
600 ASSERT (0);
601 AmlDeleteTree ((AML_NODE_HEADER *)DataNode);
602 goto error_handler2;
603 }
604
605 Status = AmlSetFixedArgument (
606 ObjectNode,
607 EAmlParseIndexTerm1,
608 (AML_NODE_HEADER *)Object
609 );
610 if (EFI_ERROR (Status)) {
611 ASSERT (0);
612 goto error_handler2;
613 }
614
615 Status = LinkNode (
616 ObjectNode,
617 ParentNode,
618 NewObjectNode
619 );
620 if (EFI_ERROR (Status)) {
621 ASSERT (0);
622 goto error_handler2;
623 }
624
625 // Free AmlNameString before returning as it is copied
626 // in the call to AmlCreateDataNode().
627 goto error_handler1;
628
629 error_handler2:
630 if (ObjectNode != NULL) {
631 AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode);
632 }
633
634 error_handler1:
635 if (AmlNameString != NULL) {
636 FreePool (AmlNameString);
637 }
638
639 return Status;
640 }
641
642 /** AML code generation for a Name object node, containing a String.
643
644 AmlCodeGenNameString ("_HID", "HID0000", ParentNode, NewObjectNode) is
645 equivalent of the following ASL code:
646 Name(_HID, "HID0000")
647
648 @param [in] NameString The new variable name.
649 Must be a NULL-terminated ASL NameString
650 e.g.: "DEV0", "DV15.DEV0", etc.
651 The input string is copied.
652 @param [in] String NULL terminated String to associate to the
653 NameString.
654 @param [in] ParentNode If provided, set ParentNode as the parent
655 of the node created.
656 @param [out] NewObjectNode If success, contains the created node.
657
658 @retval EFI_SUCCESS Success.
659 @retval EFI_INVALID_PARAMETER Invalid parameter.
660 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
661 **/
662 EFI_STATUS
663 EFIAPI
664 AmlCodeGenNameString (
665 IN CONST CHAR8 *NameString,
666 IN CHAR8 *String,
667 IN AML_NODE_HEADER *ParentNode OPTIONAL,
668 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
669 )
670 {
671 EFI_STATUS Status;
672 AML_OBJECT_NODE *ObjectNode;
673
674 if ((NameString == NULL) ||
675 (String == NULL) ||
676 ((ParentNode == NULL) && (NewObjectNode == NULL)))
677 {
678 ASSERT (0);
679 return EFI_INVALID_PARAMETER;
680 }
681
682 Status = AmlCodeGenString (String, &ObjectNode);
683 if (EFI_ERROR (Status)) {
684 ASSERT (0);
685 return Status;
686 }
687
688 Status = AmlCodeGenName (
689 NameString,
690 ObjectNode,
691 ParentNode,
692 NewObjectNode
693 );
694 if (EFI_ERROR (Status)) {
695 ASSERT (0);
696 AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode);
697 }
698
699 return Status;
700 }
701
702 /** AML code generation for a Name object node, containing an Integer.
703
704 AmlCodeGenNameInteger ("_UID", 1, ParentNode, NewObjectNode) is
705 equivalent of the following ASL code:
706 Name(_UID, One)
707
708 @param [in] NameString The new variable name.
709 Must be a NULL-terminated ASL NameString
710 e.g.: "DEV0", "DV15.DEV0", etc.
711 The input string is copied.
712 @param [in] Integer Integer to associate to the NameString.
713 @param [in] ParentNode If provided, set ParentNode as the parent
714 of the node created.
715 @param [out] NewObjectNode If success, contains the created node.
716
717 @retval EFI_SUCCESS Success.
718 @retval EFI_INVALID_PARAMETER Invalid parameter.
719 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
720 **/
721 EFI_STATUS
722 EFIAPI
723 AmlCodeGenNameInteger (
724 IN CONST CHAR8 *NameString,
725 IN UINT64 Integer,
726 IN AML_NODE_HEADER *ParentNode OPTIONAL,
727 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
728 )
729 {
730 EFI_STATUS Status;
731 AML_OBJECT_NODE *ObjectNode;
732
733 if ((NameString == NULL) ||
734 ((ParentNode == NULL) && (NewObjectNode == NULL)))
735 {
736 ASSERT (0);
737 return EFI_INVALID_PARAMETER;
738 }
739
740 Status = AmlCodeGenInteger (Integer, &ObjectNode);
741 if (EFI_ERROR (Status)) {
742 ASSERT (0);
743 return Status;
744 }
745
746 Status = AmlCodeGenName (
747 NameString,
748 ObjectNode,
749 ParentNode,
750 NewObjectNode
751 );
752 if (EFI_ERROR (Status)) {
753 ASSERT (0);
754 AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode);
755 }
756
757 return Status;
758 }
759
760 /** AML code generation for a Name object node, containing a Package.
761
762 AmlCodeGenNamePackage ("PKG0", ParentNode, NewObjectNode) is
763 equivalent of the following ASL code:
764 Name(PKG0, Package () {})
765
766 @param [in] NameString The new variable name.
767 Must be a NULL-terminated ASL NameString
768 e.g.: "DEV0", "DV15.DEV0", etc.
769 The input string is copied.
770 @param [in] ParentNode If provided, set ParentNode as the parent
771 of the node created.
772 @param [out] NewObjectNode If success, contains the created node.
773
774 @retval EFI_SUCCESS Success.
775 @retval EFI_INVALID_PARAMETER Invalid parameter.
776 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
777 **/
778 EFI_STATUS
779 EFIAPI
780 AmlCodeGenNamePackage (
781 IN CONST CHAR8 *NameString,
782 IN AML_NODE_HEADER *ParentNode, OPTIONAL
783 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
784 )
785 {
786 EFI_STATUS Status;
787 AML_OBJECT_NODE *PackageNode;
788
789 if ((NameString == NULL) ||
790 ((ParentNode == NULL) && (NewObjectNode == NULL)))
791 {
792 ASSERT (0);
793 return EFI_INVALID_PARAMETER;
794 }
795
796 Status = AmlCodeGenPackage (&PackageNode);
797 if (EFI_ERROR (Status)) {
798 ASSERT (0);
799 return Status;
800 }
801
802 Status = AmlCodeGenName (
803 NameString,
804 PackageNode,
805 ParentNode,
806 NewObjectNode
807 );
808 if (EFI_ERROR (Status)) {
809 ASSERT (0);
810 AmlDeleteTree ((AML_NODE_HEADER *)PackageNode);
811 }
812
813 return Status;
814 }
815
816 /** AML code generation for a Name object node, containing a ResourceTemplate.
817
818 AmlCodeGenNameResourceTemplate ("PRS0", ParentNode, NewObjectNode) is
819 equivalent of the following ASL code:
820 Name(PRS0, ResourceTemplate () {})
821
822 @param [in] NameString The new variable name.
823 Must be a NULL-terminated ASL NameString
824 e.g.: "DEV0", "DV15.DEV0", etc.
825 The input string is copied.
826 @param [in] ParentNode If provided, set ParentNode as the parent
827 of the node created.
828 @param [out] NewObjectNode If success, contains the created node.
829
830 @retval EFI_SUCCESS Success.
831 @retval EFI_INVALID_PARAMETER Invalid parameter.
832 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
833 **/
834 EFI_STATUS
835 EFIAPI
836 AmlCodeGenNameResourceTemplate (
837 IN CONST CHAR8 *NameString,
838 IN AML_NODE_HEADER *ParentNode, OPTIONAL
839 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
840 )
841 {
842 EFI_STATUS Status;
843 AML_OBJECT_NODE *ResourceTemplateNode;
844
845 if ((NameString == NULL) ||
846 ((ParentNode == NULL) && (NewObjectNode == NULL)))
847 {
848 ASSERT (0);
849 return EFI_INVALID_PARAMETER;
850 }
851
852 Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
853 if (EFI_ERROR (Status)) {
854 ASSERT (0);
855 return Status;
856 }
857
858 Status = AmlCodeGenName (
859 NameString,
860 ResourceTemplateNode,
861 ParentNode,
862 NewObjectNode
863 );
864 if (EFI_ERROR (Status)) {
865 ASSERT (0);
866 AmlDeleteTree ((AML_NODE_HEADER *)ResourceTemplateNode);
867 }
868
869 return Status;
870 }
871
872 /** Add a _PRT entry.
873
874 AmlCodeGenPrtEntry (0x0FFFF, 0, "LNKA", 0, PrtNameNode) is
875 equivalent of the following ASL code:
876 Package (4) {
877 0x0FFFF, // Address: Device address (([Device Id] << 16) | 0xFFFF).
878 0, // Pin: PCI pin number of the device (0-INTA, ...).
879 LNKA // Source: Name of the device that allocates the interrupt
880 // to which the above pin is connected.
881 0 // Source Index: Source is assumed to only describe one
882 // interrupt, so let it to index 0.
883 }
884
885 The 2 models described in ACPI 6.4, s6.2.13 "_PRT (PCI Routing Table)" can
886 be generated by this function. The example above matches the first model.
887
888 The package is added at the tail of the list of the input _PRT node
889 name:
890 Name (_PRT, Package () {
891 [Pre-existing _PRT entries],
892 [Newly created _PRT entry]
893 })
894
895 Cf. ACPI 6.4 specification:
896 - s6.2.13 "_PRT (PCI Routing Table)"
897 - s6.1.1 "_ADR (Address)"
898
899 @param [in] Address Address. Cf ACPI 6.4 specification, Table 6.2:
900 "ADR Object Address Encodings":
901 High word-Device #, Low word-Function #. (for
902 example, device 3, function 2 is 0x00030002).
903 To refer to all the functions on a device #,
904 use a function number of FFFF).
905 @param [in] Pin PCI pin number of the device (0-INTA ... 3-INTD).
906 Must be between 0-3.
907 @param [in] LinkName Link Name, i.e. device in the AML NameSpace
908 describing the interrupt used. The input string
909 is copied.
910 If NULL, generate 0 in the 'Source' field (cf.
911 second model, using GSIV).
912 @param [in] SourceIndex Source index or GSIV.
913 @param [in] PrtNameNode Prt Named node to add the object to ....
914
915 @retval EFI_SUCCESS Success.
916 @retval EFI_INVALID_PARAMETER Invalid parameter.
917 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
918 **/
919 EFI_STATUS
920 EFIAPI
921 AmlAddPrtEntry (
922 IN UINT32 Address,
923 IN UINT8 Pin,
924 IN CONST CHAR8 *LinkName,
925 IN UINT32 SourceIndex,
926 IN AML_OBJECT_NODE_HANDLE PrtNameNode
927 )
928 {
929 EFI_STATUS Status;
930 AML_OBJECT_NODE *PrtEntryList;
931 AML_OBJECT_NODE *PackageNode;
932 AML_OBJECT_NODE *NewElementNode;
933
934 CHAR8 *AmlNameString;
935 UINT32 AmlNameStringSize;
936 AML_DATA_NODE *DataNode;
937
938 if ((Pin > 3) ||
939 (PrtNameNode == NULL) ||
940 (AmlGetNodeType ((AML_NODE_HANDLE)PrtNameNode) != EAmlNodeObject) ||
941 (!AmlNodeHasOpCode (PrtNameNode, AML_NAME_OP, 0)) ||
942 !AmlNameOpCompareName (PrtNameNode, "_PRT"))
943 {
944 ASSERT (0);
945 return EFI_INVALID_PARAMETER;
946 }
947
948 NewElementNode = NULL;
949 AmlNameString = NULL;
950 DataNode = NULL;
951
952 // Get the Package object node of the _PRT node,
953 // which is the 2nd fixed argument (i.e. index 1).
954 PrtEntryList = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
955 PrtNameNode,
956 EAmlParseIndexTerm1
957 );
958 if ((PrtEntryList == NULL) ||
959 (AmlGetNodeType ((AML_NODE_HANDLE)PrtEntryList) != EAmlNodeObject) ||
960 (!AmlNodeHasOpCode (PrtEntryList, AML_PACKAGE_OP, 0)))
961 {
962 ASSERT (0);
963 return EFI_INVALID_PARAMETER;
964 }
965
966 // The new _PRT entry.
967 Status = AmlCodeGenPackage (&PackageNode);
968 if (EFI_ERROR (Status)) {
969 ASSERT (0);
970 return Status;
971 }
972
973 Status = AmlCodeGenInteger (Address, &NewElementNode);
974 if (EFI_ERROR (Status)) {
975 ASSERT (0);
976 goto error_handler;
977 }
978
979 Status = AmlVarListAddTail (
980 (AML_NODE_HANDLE)PackageNode,
981 (AML_NODE_HANDLE)NewElementNode
982 );
983 if (EFI_ERROR (Status)) {
984 ASSERT (0);
985 goto error_handler;
986 }
987
988 NewElementNode = NULL;
989
990 Status = AmlCodeGenInteger (Pin, &NewElementNode);
991 if (EFI_ERROR (Status)) {
992 ASSERT (0);
993 goto error_handler;
994 }
995
996 Status = AmlVarListAddTail (
997 (AML_NODE_HANDLE)PackageNode,
998 (AML_NODE_HANDLE)NewElementNode
999 );
1000 if (EFI_ERROR (Status)) {
1001 ASSERT (0);
1002 goto error_handler;
1003 }
1004
1005 NewElementNode = NULL;
1006
1007 if (LinkName != NULL) {
1008 Status = ConvertAslNameToAmlName (LinkName, &AmlNameString);
1009 if (EFI_ERROR (Status)) {
1010 ASSERT_EFI_ERROR (Status);
1011 goto error_handler;
1012 }
1013
1014 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
1015 if (EFI_ERROR (Status)) {
1016 ASSERT_EFI_ERROR (Status);
1017 goto error_handler;
1018 }
1019
1020 Status = AmlCreateDataNode (
1021 EAmlNodeDataTypeNameString,
1022 (UINT8 *)AmlNameString,
1023 AmlNameStringSize,
1024 &DataNode
1025 );
1026 if (EFI_ERROR (Status)) {
1027 ASSERT_EFI_ERROR (Status);
1028 goto error_handler;
1029 }
1030
1031 // AmlNameString will be freed be fore returning.
1032
1033 Status = AmlVarListAddTail (
1034 (AML_NODE_HANDLE)PackageNode,
1035 (AML_NODE_HANDLE)DataNode
1036 );
1037 if (EFI_ERROR (Status)) {
1038 ASSERT_EFI_ERROR (Status);
1039 goto error_handler;
1040 }
1041
1042 DataNode = NULL;
1043 } else {
1044 Status = AmlCodeGenInteger (0, &NewElementNode);
1045 if (EFI_ERROR (Status)) {
1046 ASSERT_EFI_ERROR (Status);
1047 goto error_handler;
1048 }
1049
1050 Status = AmlVarListAddTail (
1051 (AML_NODE_HANDLE)PackageNode,
1052 (AML_NODE_HANDLE)NewElementNode
1053 );
1054 if (EFI_ERROR (Status)) {
1055 ASSERT_EFI_ERROR (Status);
1056 goto error_handler;
1057 }
1058 }
1059
1060 Status = AmlCodeGenInteger (SourceIndex, &NewElementNode);
1061 if (EFI_ERROR (Status)) {
1062 ASSERT (0);
1063 goto error_handler;
1064 }
1065
1066 Status = AmlVarListAddTail (
1067 (AML_NODE_HANDLE)PackageNode,
1068 (AML_NODE_HANDLE)NewElementNode
1069 );
1070 if (EFI_ERROR (Status)) {
1071 ASSERT (0);
1072 goto error_handler;
1073 }
1074
1075 // Append to the list of _PRT entries.
1076 Status = AmlVarListAddTail (
1077 (AML_NODE_HANDLE)PrtEntryList,
1078 (AML_NODE_HANDLE)PackageNode
1079 );
1080 if (EFI_ERROR (Status)) {
1081 ASSERT (0);
1082 goto error_handler;
1083 }
1084
1085 // Free AmlNameString before returning as it is copied
1086 // in the call to AmlCreateDataNode().
1087 goto exit_handler;
1088
1089 error_handler:
1090 AmlDeleteTree ((AML_NODE_HANDLE)PackageNode);
1091 if (NewElementNode != NULL) {
1092 AmlDeleteTree ((AML_NODE_HANDLE)NewElementNode);
1093 }
1094
1095 if (DataNode != NULL) {
1096 AmlDeleteTree ((AML_NODE_HANDLE)DataNode);
1097 }
1098
1099 exit_handler:
1100 if (AmlNameString != NULL) {
1101 FreePool (AmlNameString);
1102 }
1103
1104 return Status;
1105 }
1106
1107 /** AML code generation for a Device object node.
1108
1109 AmlCodeGenDevice ("COM0", ParentNode, NewObjectNode) is
1110 equivalent of the following ASL code:
1111 Device(COM0) {}
1112
1113 @param [in] NameString The new Device's name.
1114 Must be a NULL-terminated ASL NameString
1115 e.g.: "DEV0", "DV15.DEV0", etc.
1116 The input string is copied.
1117 @param [in] ParentNode If provided, set ParentNode as the parent
1118 of the node created.
1119 @param [out] NewObjectNode If success, contains the created node.
1120
1121 @retval EFI_SUCCESS Success.
1122 @retval EFI_INVALID_PARAMETER Invalid parameter.
1123 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1124 **/
1125 EFI_STATUS
1126 EFIAPI
1127 AmlCodeGenDevice (
1128 IN CONST CHAR8 *NameString,
1129 IN AML_NODE_HEADER *ParentNode OPTIONAL,
1130 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
1131 )
1132 {
1133 EFI_STATUS Status;
1134 AML_OBJECT_NODE *ObjectNode;
1135 AML_DATA_NODE *DataNode;
1136 CHAR8 *AmlNameString;
1137 UINT32 AmlNameStringSize;
1138
1139 if ((NameString == NULL) ||
1140 ((ParentNode == NULL) && (NewObjectNode == NULL)))
1141 {
1142 ASSERT (0);
1143 return EFI_INVALID_PARAMETER;
1144 }
1145
1146 ObjectNode = NULL;
1147 DataNode = NULL;
1148 AmlNameString = NULL;
1149
1150 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
1151 if (EFI_ERROR (Status)) {
1152 ASSERT (0);
1153 return Status;
1154 }
1155
1156 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
1157 if (EFI_ERROR (Status)) {
1158 ASSERT (0);
1159 goto error_handler1;
1160 }
1161
1162 Status = AmlCreateObjectNode (
1163 AmlGetByteEncodingByOpCode (AML_EXT_OP, AML_EXT_DEVICE_OP),
1164 AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize),
1165 &ObjectNode
1166 );
1167 if (EFI_ERROR (Status)) {
1168 ASSERT (0);
1169 goto error_handler1;
1170 }
1171
1172 Status = AmlCreateDataNode (
1173 EAmlNodeDataTypeNameString,
1174 (UINT8 *)AmlNameString,
1175 AmlNameStringSize,
1176 &DataNode
1177 );
1178 if (EFI_ERROR (Status)) {
1179 ASSERT (0);
1180 goto error_handler2;
1181 }
1182
1183 Status = AmlSetFixedArgument (
1184 ObjectNode,
1185 EAmlParseIndexTerm0,
1186 (AML_NODE_HEADER *)DataNode
1187 );
1188 if (EFI_ERROR (Status)) {
1189 ASSERT (0);
1190 AmlDeleteTree ((AML_NODE_HEADER *)DataNode);
1191 goto error_handler2;
1192 }
1193
1194 Status = LinkNode (
1195 ObjectNode,
1196 ParentNode,
1197 NewObjectNode
1198 );
1199 if (EFI_ERROR (Status)) {
1200 ASSERT (0);
1201 goto error_handler2;
1202 }
1203
1204 // Free AmlNameString before returning as it is copied
1205 // in the call to AmlCreateDataNode().
1206 goto error_handler1;
1207
1208 error_handler2:
1209 if (ObjectNode != NULL) {
1210 AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode);
1211 }
1212
1213 error_handler1:
1214 if (AmlNameString != NULL) {
1215 FreePool (AmlNameString);
1216 }
1217
1218 return Status;
1219 }
1220
1221 /** AML code generation for a Scope object node.
1222
1223 AmlCodeGenScope ("_SB", ParentNode, NewObjectNode) is
1224 equivalent of the following ASL code:
1225 Scope(_SB) {}
1226
1227 @param [in] NameString The new Scope's name.
1228 Must be a NULL-terminated ASL NameString
1229 e.g.: "DEV0", "DV15.DEV0", etc.
1230 The input string is copied.
1231 @param [in] ParentNode If provided, set ParentNode as the parent
1232 of the node created.
1233 @param [out] NewObjectNode If success, contains the created node.
1234
1235 @retval EFI_SUCCESS Success.
1236 @retval EFI_INVALID_PARAMETER Invalid parameter.
1237 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1238 **/
1239 EFI_STATUS
1240 EFIAPI
1241 AmlCodeGenScope (
1242 IN CONST CHAR8 *NameString,
1243 IN AML_NODE_HEADER *ParentNode OPTIONAL,
1244 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
1245 )
1246 {
1247 EFI_STATUS Status;
1248 AML_OBJECT_NODE *ObjectNode;
1249 AML_DATA_NODE *DataNode;
1250 CHAR8 *AmlNameString;
1251 UINT32 AmlNameStringSize;
1252
1253 if ((NameString == NULL) ||
1254 ((ParentNode == NULL) && (NewObjectNode == NULL)))
1255 {
1256 ASSERT (0);
1257 return EFI_INVALID_PARAMETER;
1258 }
1259
1260 ObjectNode = NULL;
1261 DataNode = NULL;
1262 AmlNameString = NULL;
1263
1264 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
1265 if (EFI_ERROR (Status)) {
1266 ASSERT (0);
1267 return Status;
1268 }
1269
1270 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
1271 if (EFI_ERROR (Status)) {
1272 ASSERT (0);
1273 goto error_handler1;
1274 }
1275
1276 Status = AmlCreateObjectNode (
1277 AmlGetByteEncodingByOpCode (AML_SCOPE_OP, 0),
1278 AmlNameStringSize + AmlComputePkgLengthWidth (AmlNameStringSize),
1279 &ObjectNode
1280 );
1281 if (EFI_ERROR (Status)) {
1282 ASSERT (0);
1283 goto error_handler1;
1284 }
1285
1286 Status = AmlCreateDataNode (
1287 EAmlNodeDataTypeNameString,
1288 (UINT8 *)AmlNameString,
1289 AmlNameStringSize,
1290 &DataNode
1291 );
1292 if (EFI_ERROR (Status)) {
1293 ASSERT (0);
1294 goto error_handler2;
1295 }
1296
1297 Status = AmlSetFixedArgument (
1298 ObjectNode,
1299 EAmlParseIndexTerm0,
1300 (AML_NODE_HEADER *)DataNode
1301 );
1302 if (EFI_ERROR (Status)) {
1303 ASSERT (0);
1304 AmlDeleteTree ((AML_NODE_HEADER *)DataNode);
1305 goto error_handler2;
1306 }
1307
1308 Status = LinkNode (
1309 ObjectNode,
1310 ParentNode,
1311 NewObjectNode
1312 );
1313 if (EFI_ERROR (Status)) {
1314 ASSERT (0);
1315 goto error_handler2;
1316 }
1317
1318 // Free AmlNameString before returning as it is copied
1319 // in the call to AmlCreateDataNode().
1320 goto error_handler1;
1321
1322 error_handler2:
1323 if (ObjectNode != NULL) {
1324 AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode);
1325 }
1326
1327 error_handler1:
1328 if (AmlNameString != NULL) {
1329 FreePool (AmlNameString);
1330 }
1331
1332 return Status;
1333 }
1334
1335 /** AML code generation for a Method object node.
1336
1337 AmlCodeGenMethod ("MET0", 1, TRUE, 3, ParentNode, NewObjectNode) is
1338 equivalent of the following ASL code:
1339 Method(MET0, 1, Serialized, 3) {}
1340
1341 ACPI 6.4, s20.2.5.2 "Named Objects Encoding":
1342 DefMethod := MethodOp PkgLength NameString MethodFlags TermList
1343 MethodOp := 0x14
1344
1345 The ASL parameters "ReturnType" and "ParameterTypes" are not asked
1346 in this function. They are optional parameters in ASL.
1347
1348 @param [in] NameString The new Method's name.
1349 Must be a NULL-terminated ASL NameString
1350 e.g.: "MET0", "_SB.MET0", etc.
1351 The input string is copied.
1352 @param [in] NumArgs Number of arguments.
1353 Must be 0 <= NumArgs <= 6.
1354 @param [in] IsSerialized TRUE is equivalent to Serialized.
1355 FALSE is equivalent to NotSerialized.
1356 Default is NotSerialized in ASL spec.
1357 @param [in] SyncLevel Synchronization level for the method.
1358 Must be 0 <= SyncLevel <= 15.
1359 Default is 0 in ASL.
1360 @param [in] ParentNode If provided, set ParentNode as the parent
1361 of the node created.
1362 @param [out] NewObjectNode If success, contains the created node.
1363
1364 @retval EFI_SUCCESS Success.
1365 @retval EFI_INVALID_PARAMETER Invalid parameter.
1366 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1367 **/
1368 STATIC
1369 EFI_STATUS
1370 EFIAPI
1371 AmlCodeGenMethod (
1372 IN CONST CHAR8 *NameString,
1373 IN UINT8 NumArgs,
1374 IN BOOLEAN IsSerialized,
1375 IN UINT8 SyncLevel,
1376 IN AML_NODE_HEADER *ParentNode OPTIONAL,
1377 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
1378 )
1379 {
1380 EFI_STATUS Status;
1381 UINT32 PkgLen;
1382 UINT8 Flags;
1383 AML_OBJECT_NODE *ObjectNode;
1384 AML_DATA_NODE *DataNode;
1385 CHAR8 *AmlNameString;
1386 UINT32 AmlNameStringSize;
1387
1388 if ((NameString == NULL) ||
1389 (NumArgs > 6) ||
1390 (SyncLevel > 15) ||
1391 ((ParentNode == NULL) && (NewObjectNode == NULL)))
1392 {
1393 ASSERT (0);
1394 return EFI_INVALID_PARAMETER;
1395 }
1396
1397 ObjectNode = NULL;
1398 DataNode = NULL;
1399
1400 // ACPI 6.4, s20.2.5.2 "Named Objects Encoding":
1401 // DefMethod := MethodOp PkgLength NameString MethodFlags TermList
1402 // MethodOp := 0x14
1403 // So:
1404 // 1- Create the NameString
1405 // 2- Compute the size to write in the PkgLen
1406 // 3- Create nodes for the NameString and Method object node
1407 // 4- Set the NameString DataNode as a fixed argument
1408 // 5- Create and link the MethodFlags node
1409
1410 // 1- Create the NameString
1411 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
1412 if (EFI_ERROR (Status)) {
1413 ASSERT (0);
1414 return Status;
1415 }
1416
1417 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
1418 if (EFI_ERROR (Status)) {
1419 ASSERT (0);
1420 goto error_handler1;
1421 }
1422
1423 // 2- Compute the size to write in the PkgLen
1424 // Add 1 byte (ByteData) for MethodFlags.
1425 Status = AmlComputePkgLength (AmlNameStringSize + 1, &PkgLen);
1426 if (EFI_ERROR (Status)) {
1427 ASSERT (0);
1428 goto error_handler1;
1429 }
1430
1431 // 3- Create nodes for the NameString and Method object node
1432 Status = AmlCreateObjectNode (
1433 AmlGetByteEncodingByOpCode (AML_METHOD_OP, 0),
1434 PkgLen,
1435 &ObjectNode
1436 );
1437 if (EFI_ERROR (Status)) {
1438 ASSERT (0);
1439 goto error_handler1;
1440 }
1441
1442 Status = AmlCreateDataNode (
1443 EAmlNodeDataTypeNameString,
1444 (UINT8 *)AmlNameString,
1445 AmlNameStringSize,
1446 &DataNode
1447 );
1448 if (EFI_ERROR (Status)) {
1449 ASSERT (0);
1450 goto error_handler2;
1451 }
1452
1453 // 4- Set the NameString DataNode as a fixed argument
1454 Status = AmlSetFixedArgument (
1455 ObjectNode,
1456 EAmlParseIndexTerm0,
1457 (AML_NODE_HEADER *)DataNode
1458 );
1459 if (EFI_ERROR (Status)) {
1460 ASSERT (0);
1461 goto error_handler2;
1462 }
1463
1464 DataNode = NULL;
1465
1466 // 5- Create and link the MethodFlags node
1467 Flags = NumArgs |
1468 (IsSerialized ? BIT3 : 0) |
1469 (SyncLevel << 4);
1470
1471 Status = AmlCreateDataNode (EAmlNodeDataTypeUInt, &Flags, 1, &DataNode);
1472 if (EFI_ERROR (Status)) {
1473 ASSERT (0);
1474 goto error_handler2;
1475 }
1476
1477 Status = AmlSetFixedArgument (
1478 ObjectNode,
1479 EAmlParseIndexTerm1,
1480 (AML_NODE_HEADER *)DataNode
1481 );
1482 if (EFI_ERROR (Status)) {
1483 ASSERT (0);
1484 goto error_handler2;
1485 }
1486
1487 // Data node is attached so set the pointer to
1488 // NULL to ensure correct error handling.
1489 DataNode = NULL;
1490
1491 Status = LinkNode (
1492 ObjectNode,
1493 ParentNode,
1494 NewObjectNode
1495 );
1496 if (EFI_ERROR (Status)) {
1497 ASSERT (0);
1498 goto error_handler2;
1499 }
1500
1501 // Free AmlNameString before returning as it is copied
1502 // in the call to AmlCreateDataNode().
1503 goto error_handler1;
1504
1505 error_handler2:
1506 if (ObjectNode != NULL) {
1507 AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode);
1508 }
1509
1510 if (DataNode != NULL) {
1511 AmlDeleteTree ((AML_NODE_HEADER *)DataNode);
1512 }
1513
1514 error_handler1:
1515 if (AmlNameString != NULL) {
1516 FreePool (AmlNameString);
1517 }
1518
1519 return Status;
1520 }
1521
1522 /** AML code generation for a Return object node.
1523
1524 AmlCodeGenReturn (ReturnNode, ParentNode, NewObjectNode) is
1525 equivalent of the following ASL code:
1526 Return([Content of the ReturnNode])
1527
1528 The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
1529 DefReturn := ReturnOp ArgObject
1530 ReturnOp := 0xA4
1531 ArgObject := TermArg => DataRefObject
1532
1533 Thus, the ReturnNode must be evaluated as a DataRefObject. It can
1534 be a NameString referencing an object. As this CodeGen Api doesn't
1535 do semantic checking, it is strongly advised to check the AML bytecode
1536 generated by this function against an ASL compiler.
1537
1538 The ReturnNode must be generated inside a Method body scope.
1539
1540 @param [in] ReturnNode The object returned by the Return ASL statement.
1541 This node is deleted if an error occurs.
1542 @param [in] ParentNode If provided, set ParentNode as the parent
1543 of the node created.
1544 Must be a MethodOp node.
1545 @param [out] NewObjectNode If success, contains the created node.
1546
1547 @retval EFI_SUCCESS Success.
1548 @retval EFI_INVALID_PARAMETER Invalid parameter.
1549 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1550 **/
1551 STATIC
1552 EFI_STATUS
1553 EFIAPI
1554 AmlCodeGenReturn (
1555 IN AML_NODE_HEADER *ReturnNode,
1556 IN AML_NODE_HEADER *ParentNode OPTIONAL,
1557 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
1558 )
1559 {
1560 EFI_STATUS Status;
1561 AML_OBJECT_NODE *ObjectNode;
1562
1563 if ((ReturnNode == NULL) ||
1564 ((ParentNode == NULL) && (NewObjectNode == NULL)) ||
1565 ((ParentNode != NULL) &&
1566 !AmlNodeCompareOpCode (
1567 (AML_OBJECT_NODE *)ParentNode,
1568 AML_METHOD_OP,
1569 0
1570 )))
1571 {
1572 ASSERT (0);
1573 return EFI_INVALID_PARAMETER;
1574 }
1575
1576 Status = AmlCreateObjectNode (
1577 AmlGetByteEncodingByOpCode (AML_RETURN_OP, 0),
1578 0,
1579 &ObjectNode
1580 );
1581 if (EFI_ERROR (Status)) {
1582 ASSERT (0);
1583 goto error_handler;
1584 }
1585
1586 Status = AmlSetFixedArgument (
1587 ObjectNode,
1588 EAmlParseIndexTerm0,
1589 ReturnNode
1590 );
1591 if (EFI_ERROR (Status)) {
1592 ASSERT (0);
1593 goto error_handler;
1594 }
1595
1596 ReturnNode = NULL;
1597
1598 Status = LinkNode (
1599 ObjectNode,
1600 ParentNode,
1601 NewObjectNode
1602 );
1603 if (EFI_ERROR (Status)) {
1604 ASSERT (0);
1605 goto error_handler;
1606 }
1607
1608 return Status;
1609
1610 error_handler:
1611 if (ReturnNode != NULL) {
1612 AmlDeleteTree (ReturnNode);
1613 }
1614
1615 if (ObjectNode != NULL) {
1616 AmlDeleteTree ((AML_NODE_HEADER *)ObjectNode);
1617 }
1618
1619 return Status;
1620 }
1621
1622 /** AML code generation for a Return object node,
1623 returning the object as an input NameString.
1624
1625 AmlCodeGenReturn ("NAM1", ParentNode, NewObjectNode) is
1626 equivalent of the following ASL code:
1627 Return(NAM1)
1628
1629 The ACPI 6.3 specification, s20.2.5.3 "Type 1 Opcodes Encoding" states:
1630 DefReturn := ReturnOp ArgObject
1631 ReturnOp := 0xA4
1632 ArgObject := TermArg => DataRefObject
1633
1634 Thus, the ReturnNode must be evaluated as a DataRefObject. It can
1635 be a NameString referencing an object. As this CodeGen Api doesn't
1636 do semantic checking, it is strongly advised to check the AML bytecode
1637 generated by this function against an ASL compiler.
1638
1639 The ReturnNode must be generated inside a Method body scope.
1640
1641 @param [in] NameString The object referenced by this NameString
1642 is returned by the Return ASL statement.
1643 Must be a NULL-terminated ASL NameString
1644 e.g.: "NAM1", "_SB.NAM1", etc.
1645 The input string is copied.
1646 @param [in] ParentNode If provided, set ParentNode as the parent
1647 of the node created.
1648 Must be a MethodOp node.
1649 @param [out] NewObjectNode If success, contains the created node.
1650
1651 @retval EFI_SUCCESS Success.
1652 @retval EFI_INVALID_PARAMETER Invalid parameter.
1653 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1654 **/
1655 STATIC
1656 EFI_STATUS
1657 EFIAPI
1658 AmlCodeGenReturnNameString (
1659 IN CONST CHAR8 *NameString,
1660 IN AML_NODE_HEADER *ParentNode OPTIONAL,
1661 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
1662 )
1663 {
1664 EFI_STATUS Status;
1665 AML_DATA_NODE *DataNode;
1666 CHAR8 *AmlNameString;
1667 UINT32 AmlNameStringSize;
1668
1669 DataNode = NULL;
1670
1671 Status = ConvertAslNameToAmlName (NameString, &AmlNameString);
1672 if (EFI_ERROR (Status)) {
1673 ASSERT (0);
1674 return Status;
1675 }
1676
1677 Status = AmlGetNameStringSize (AmlNameString, &AmlNameStringSize);
1678 if (EFI_ERROR (Status)) {
1679 ASSERT (0);
1680 goto exit_handler;
1681 }
1682
1683 Status = AmlCreateDataNode (
1684 EAmlNodeDataTypeNameString,
1685 (UINT8 *)AmlNameString,
1686 AmlNameStringSize,
1687 &DataNode
1688 );
1689 if (EFI_ERROR (Status)) {
1690 ASSERT (0);
1691 goto exit_handler;
1692 }
1693
1694 // AmlCodeGenReturn() deletes DataNode if error.
1695 Status = AmlCodeGenReturn (
1696 (AML_NODE_HEADER *)DataNode,
1697 ParentNode,
1698 NewObjectNode
1699 );
1700 ASSERT_EFI_ERROR (Status);
1701
1702 exit_handler:
1703 if (AmlNameString != NULL) {
1704 FreePool (AmlNameString);
1705 }
1706
1707 return Status;
1708 }
1709
1710 /** AML code generation for a Return object node,
1711 returning an Integer.
1712
1713 AmlCodeGenReturn (0), ParentNode, NewObjectNode) is
1714 equivalent of the following ASL code:
1715 Return (0)
1716
1717 The ACPI 6.3 specification, 20.2.8 "Statement Opcodes Encoding" states:
1718 DefReturn := ReturnOp ArgObject
1719 ReturnOp := 0xA4
1720 ArgObject := TermArg => DataRefObject
1721
1722 Thus, the ReturnNode must be evaluated as a DataRefObject.
1723
1724 The ReturnNode must be generated inside a Method body scope.
1725
1726 @param [in] Integer The integer is returned by the Return
1727 ASL statement.
1728 @param [in] ParentNode If provided, set ParentNode as the parent
1729 of the node created.
1730 Must be a MethodOp node.
1731 @param [out] NewObjectNode If success, contains the created node.
1732
1733 @retval EFI_SUCCESS Success.
1734 @retval EFI_INVALID_PARAMETER Invalid parameter.
1735 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1736 **/
1737 STATIC
1738 EFI_STATUS
1739 EFIAPI
1740 AmlCodeGenReturnInteger (
1741 IN UINT64 Integer,
1742 IN AML_NODE_HEADER *ParentNode OPTIONAL,
1743 OUT AML_OBJECT_NODE **NewObjectNode OPTIONAL
1744 )
1745 {
1746 EFI_STATUS Status;
1747 AML_OBJECT_NODE *IntNode;
1748
1749 IntNode = NULL;
1750
1751 Status = AmlCodeGenInteger (Integer, &IntNode);
1752 if (EFI_ERROR (Status)) {
1753 ASSERT (0);
1754 return Status;
1755 }
1756
1757 // AmlCodeGenReturn() deletes DataNode if error.
1758 Status = AmlCodeGenReturn (
1759 (AML_NODE_HEADER *)IntNode,
1760 ParentNode,
1761 NewObjectNode
1762 );
1763 ASSERT_EFI_ERROR (Status);
1764
1765 return Status;
1766 }
1767
1768 /** AML code generation for a method returning a NameString.
1769
1770 AmlCodeGenMethodRetNameString (
1771 "MET0", "_CRS", 1, TRUE, 3, ParentNode, NewObjectNode
1772 );
1773 is equivalent of the following ASL code:
1774 Method(MET0, 1, Serialized, 3) {
1775 Return (_CRS)
1776 }
1777
1778 The ASL parameters "ReturnType" and "ParameterTypes" are not asked
1779 in this function. They are optional parameters in ASL.
1780
1781 @param [in] MethodNameString The new Method's name.
1782 Must be a NULL-terminated ASL NameString
1783 e.g.: "MET0", "_SB.MET0", etc.
1784 The input string is copied.
1785 @param [in] ReturnedNameString The name of the object returned by the
1786 method. Optional parameter, can be:
1787 - NULL (ignored).
1788 - A NULL-terminated ASL NameString.
1789 e.g.: "MET0", "_SB.MET0", etc.
1790 The input string is copied.
1791 @param [in] NumArgs Number of arguments.
1792 Must be 0 <= NumArgs <= 6.
1793 @param [in] IsSerialized TRUE is equivalent to Serialized.
1794 FALSE is equivalent to NotSerialized.
1795 Default is NotSerialized in ASL spec.
1796 @param [in] SyncLevel Synchronization level for the method.
1797 Must be 0 <= SyncLevel <= 15.
1798 Default is 0 in ASL.
1799 @param [in] ParentNode If provided, set ParentNode as the parent
1800 of the node created.
1801 @param [out] NewObjectNode If success, contains the created node.
1802
1803 @retval EFI_SUCCESS Success.
1804 @retval EFI_INVALID_PARAMETER Invalid parameter.
1805 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1806 **/
1807 EFI_STATUS
1808 EFIAPI
1809 AmlCodeGenMethodRetNameString (
1810 IN CONST CHAR8 *MethodNameString,
1811 IN CONST CHAR8 *ReturnedNameString OPTIONAL,
1812 IN UINT8 NumArgs,
1813 IN BOOLEAN IsSerialized,
1814 IN UINT8 SyncLevel,
1815 IN AML_NODE_HANDLE ParentNode OPTIONAL,
1816 OUT AML_OBJECT_NODE_HANDLE *NewObjectNode OPTIONAL
1817 )
1818 {
1819 EFI_STATUS Status;
1820 AML_OBJECT_NODE_HANDLE MethodNode;
1821
1822 if ((MethodNameString == NULL) ||
1823 ((ParentNode == NULL) && (NewObjectNode == NULL)))
1824 {
1825 ASSERT (0);
1826 return EFI_INVALID_PARAMETER;
1827 }
1828
1829 // Create a Method named MethodNameString.
1830 Status = AmlCodeGenMethod (
1831 MethodNameString,
1832 NumArgs,
1833 IsSerialized,
1834 SyncLevel,
1835 NULL,
1836 &MethodNode
1837 );
1838 if (EFI_ERROR (Status)) {
1839 ASSERT (0);
1840 return Status;
1841 }
1842
1843 // Return ReturnedNameString if provided.
1844 if (ReturnedNameString != NULL) {
1845 Status = AmlCodeGenReturnNameString (
1846 ReturnedNameString,
1847 (AML_NODE_HANDLE)MethodNode,
1848 NULL
1849 );
1850 if (EFI_ERROR (Status)) {
1851 ASSERT (0);
1852 goto error_handler;
1853 }
1854 }
1855
1856 Status = LinkNode (
1857 MethodNode,
1858 ParentNode,
1859 NewObjectNode
1860 );
1861 if (EFI_ERROR (Status)) {
1862 ASSERT (0);
1863 goto error_handler;
1864 }
1865
1866 return Status;
1867
1868 error_handler:
1869 if (MethodNode != NULL) {
1870 AmlDeleteTree ((AML_NODE_HANDLE)MethodNode);
1871 }
1872
1873 return Status;
1874 }
1875
1876 /** AML code generation for a method returning an Integer.
1877
1878 AmlCodeGenMethodRetInteger (
1879 "_CBA", 0, 1, TRUE, 3, ParentNode, NewObjectNode
1880 );
1881 is equivalent of the following ASL code:
1882 Method(_CBA, 1, Serialized, 3) {
1883 Return (0)
1884 }
1885
1886 The ASL parameters "ReturnType" and "ParameterTypes" are not asked
1887 in this function. They are optional parameters in ASL.
1888
1889 @param [in] MethodNameString The new Method's name.
1890 Must be a NULL-terminated ASL NameString
1891 e.g.: "MET0", "_SB.MET0", etc.
1892 The input string is copied.
1893 @param [in] ReturnedInteger The value of the integer returned by the
1894 method.
1895 @param [in] NumArgs Number of arguments.
1896 Must be 0 <= NumArgs <= 6.
1897 @param [in] IsSerialized TRUE is equivalent to Serialized.
1898 FALSE is equivalent to NotSerialized.
1899 Default is NotSerialized in ASL spec.
1900 @param [in] SyncLevel Synchronization level for the method.
1901 Must be 0 <= SyncLevel <= 15.
1902 Default is 0 in ASL.
1903 @param [in] ParentNode If provided, set ParentNode as the parent
1904 of the node created.
1905 @param [out] NewObjectNode If success, contains the created node.
1906
1907 @retval EFI_SUCCESS Success.
1908 @retval EFI_INVALID_PARAMETER Invalid parameter.
1909 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1910 **/
1911 EFI_STATUS
1912 EFIAPI
1913 AmlCodeGenMethodRetInteger (
1914 IN CONST CHAR8 *MethodNameString,
1915 IN UINT64 ReturnedInteger,
1916 IN UINT8 NumArgs,
1917 IN BOOLEAN IsSerialized,
1918 IN UINT8 SyncLevel,
1919 IN AML_NODE_HANDLE ParentNode OPTIONAL,
1920 OUT AML_OBJECT_NODE_HANDLE *NewObjectNode OPTIONAL
1921 )
1922 {
1923 EFI_STATUS Status;
1924 AML_OBJECT_NODE_HANDLE MethodNode;
1925
1926 if ((MethodNameString == NULL) ||
1927 ((ParentNode == NULL) && (NewObjectNode == NULL)))
1928 {
1929 ASSERT (0);
1930 return EFI_INVALID_PARAMETER;
1931 }
1932
1933 // Create a Method named MethodNameString.
1934 Status = AmlCodeGenMethod (
1935 MethodNameString,
1936 NumArgs,
1937 IsSerialized,
1938 SyncLevel,
1939 NULL,
1940 &MethodNode
1941 );
1942 if (EFI_ERROR (Status)) {
1943 ASSERT (0);
1944 return Status;
1945 }
1946
1947 Status = AmlCodeGenReturnInteger (
1948 ReturnedInteger,
1949 (AML_NODE_HANDLE)MethodNode,
1950 NULL
1951 );
1952 if (EFI_ERROR (Status)) {
1953 ASSERT (0);
1954 goto error_handler;
1955 }
1956
1957 Status = LinkNode (
1958 MethodNode,
1959 ParentNode,
1960 NewObjectNode
1961 );
1962 if (EFI_ERROR (Status)) {
1963 ASSERT (0);
1964 goto error_handler;
1965 }
1966
1967 return Status;
1968
1969 error_handler:
1970 if (MethodNode != NULL) {
1971 AmlDeleteTree ((AML_NODE_HANDLE)MethodNode);
1972 }
1973
1974 return Status;
1975 }
1976
1977 /** Create a _LPI name.
1978
1979 AmlCreateLpiNode ("_LPI", 0, 1, ParentNode, &LpiNode) is
1980 equivalent of the following ASL code:
1981 Name (_LPI, Package (
1982 0, // Revision
1983 1, // LevelId
1984 0 // Count
1985 ))
1986
1987 This function doesn't define any LPI state. As shown above, the count
1988 of _LPI state is set to 0.
1989 The AmlAddLpiState () function allows to add LPI states.
1990
1991 Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
1992
1993 @param [in] LpiNameString The new LPI 's object name.
1994 Must be a NULL-terminated ASL NameString
1995 e.g.: "_LPI", "DEV0.PLPI", etc.
1996 The input string is copied.
1997 @param [in] Revision Revision number of the _LPI states.
1998 @param [in] LevelId A platform defined number that identifies the
1999 level of hierarchy of the processor node to
2000 which the LPI states apply.
2001 @param [in] ParentNode If provided, set ParentNode as the parent
2002 of the node created.
2003 @param [out] NewLpiNode If success, contains the created node.
2004
2005 @retval EFI_SUCCESS The function completed successfully.
2006 @retval EFI_INVALID_PARAMETER Invalid parameter.
2007 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
2008 **/
2009 EFI_STATUS
2010 EFIAPI
2011 AmlCreateLpiNode (
2012 IN CONST CHAR8 *LpiNameString,
2013 IN UINT16 Revision,
2014 IN UINT64 LevelId,
2015 IN AML_NODE_HANDLE ParentNode OPTIONAL,
2016 OUT AML_OBJECT_NODE_HANDLE *NewLpiNode OPTIONAL
2017 )
2018 {
2019 EFI_STATUS Status;
2020 AML_OBJECT_NODE_HANDLE PackageNode;
2021 AML_OBJECT_NODE_HANDLE IntegerNode;
2022
2023 if ((LpiNameString == NULL) ||
2024 ((ParentNode == NULL) && (NewLpiNode == NULL)))
2025 {
2026 ASSERT (0);
2027 return EFI_INVALID_PARAMETER;
2028 }
2029
2030 IntegerNode = NULL;
2031
2032 Status = AmlCodeGenPackage (&PackageNode);
2033 if (EFI_ERROR (Status)) {
2034 ASSERT (0);
2035 return Status;
2036 }
2037
2038 // Create and attach Revision
2039 Status = AmlCodeGenInteger (Revision, &IntegerNode);
2040 if (EFI_ERROR (Status)) {
2041 ASSERT (0);
2042 IntegerNode = NULL;
2043 goto error_handler;
2044 }
2045
2046 Status = AmlVarListAddTail (
2047 (AML_NODE_HANDLE)PackageNode,
2048 (AML_NODE_HANDLE)IntegerNode
2049 );
2050 if (EFI_ERROR (Status)) {
2051 ASSERT (0);
2052 goto error_handler;
2053 }
2054
2055 IntegerNode = NULL;
2056
2057 // Create and attach LevelId
2058 Status = AmlCodeGenInteger (LevelId, &IntegerNode);
2059 if (EFI_ERROR (Status)) {
2060 ASSERT (0);
2061 IntegerNode = NULL;
2062 goto error_handler;
2063 }
2064
2065 Status = AmlVarListAddTail (
2066 (AML_NODE_HANDLE)PackageNode,
2067 (AML_NODE_HANDLE)IntegerNode
2068 );
2069 if (EFI_ERROR (Status)) {
2070 ASSERT (0);
2071 goto error_handler;
2072 }
2073
2074 IntegerNode = NULL;
2075
2076 // Create and attach Count. No LPI state is added, so 0.
2077 Status = AmlCodeGenInteger (0, &IntegerNode);
2078 if (EFI_ERROR (Status)) {
2079 ASSERT (0);
2080 IntegerNode = NULL;
2081 goto error_handler;
2082 }
2083
2084 Status = AmlVarListAddTail (
2085 (AML_NODE_HANDLE)PackageNode,
2086 (AML_NODE_HANDLE)IntegerNode
2087 );
2088 if (EFI_ERROR (Status)) {
2089 ASSERT (0);
2090 goto error_handler;
2091 }
2092
2093 IntegerNode = NULL;
2094
2095 Status = AmlCodeGenName (LpiNameString, PackageNode, ParentNode, NewLpiNode);
2096 if (EFI_ERROR (Status)) {
2097 ASSERT (0);
2098 goto error_handler;
2099 }
2100
2101 return Status;
2102
2103 error_handler:
2104 AmlDeleteTree ((AML_NODE_HANDLE)PackageNode);
2105 if (IntegerNode != NULL) {
2106 AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode);
2107 }
2108
2109 return Status;
2110 }
2111
2112 /** Add an _LPI state to a LPI node created using AmlCreateLpiNode.
2113
2114 AmlAddLpiState increments the Count of LPI states in the LPI node by one,
2115 and adds the following package:
2116 Package() {
2117 MinResidency,
2118 WorstCaseWakeLatency,
2119 Flags,
2120 ArchFlags,
2121 ResCntFreq,
2122 EnableParentState,
2123 (GenericRegisterDescriptor != NULL) ? // Entry method. If a
2124 ResourceTemplate(GenericRegisterDescriptor) : // Register is given,
2125 Integer, // use it. Use the
2126 // Integer otherwise.
2127 ResourceTemplate() { // NULL Residency Counter
2128 Register (SystemMemory, 0, 0, 0, 0)
2129 },
2130 ResourceTemplate() { // NULL Usage Counter
2131 Register (SystemMemory, 0, 0, 0, 0)
2132 },
2133 "" // NULL State Name
2134 },
2135
2136 Cf ACPI 6.3 specification, s8.4.4 "Lower Power Idle States".
2137
2138 @param [in] MinResidency Minimum Residency.
2139 @param [in] WorstCaseWakeLatency Worst case wake-up latency.
2140 @param [in] Flags Flags.
2141 @param [in] ArchFlags Architectural flags.
2142 @param [in] ResCntFreq Residency Counter Frequency.
2143 @param [in] EnableParentState Enabled Parent State.
2144 @param [in] GenericRegisterDescriptor Entry Method.
2145 If not NULL, use this Register to
2146 describe the entry method address.
2147 @param [in] Integer Entry Method.
2148 If GenericRegisterDescriptor is NULL,
2149 take this value.
2150 @param [in] ResidencyCounterRegister If not NULL, use it to populate the
2151 residency counter register.
2152 @param [in] UsageCounterRegister If not NULL, use it to populate the
2153 usage counter register.
2154 @param [in] StateName If not NULL, use it to populate the
2155 state name.
2156 @param [in] LpiNode Lpi node created with the function
2157 AmlCreateLpiNode to which the new LPI
2158 state is appended.
2159
2160 @retval EFI_SUCCESS The function completed successfully.
2161 @retval EFI_INVALID_PARAMETER Invalid parameter.
2162 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
2163 **/
2164 EFI_STATUS
2165 EFIAPI
2166 AmlAddLpiState (
2167 IN UINT32 MinResidency,
2168 IN UINT32 WorstCaseWakeLatency,
2169 IN UINT32 Flags,
2170 IN UINT32 ArchFlags,
2171 IN UINT32 ResCntFreq,
2172 IN UINT32 EnableParentState,
2173 IN EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *GenericRegisterDescriptor OPTIONAL,
2174 IN UINT64 Integer OPTIONAL,
2175 IN EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *ResidencyCounterRegister OPTIONAL,
2176 IN EFI_ACPI_6_3_GENERIC_ADDRESS_STRUCTURE *UsageCounterRegister OPTIONAL,
2177 IN CHAR8 *StateName OPTIONAL,
2178 IN AML_OBJECT_NODE_HANDLE LpiNode
2179 )
2180 {
2181 EFI_STATUS Status;
2182 AML_DATA_NODE_HANDLE RdNode;
2183 AML_OBJECT_NODE_HANDLE PackageNode;
2184 AML_OBJECT_NODE_HANDLE IntegerNode;
2185 AML_OBJECT_NODE_HANDLE StringNode;
2186 AML_OBJECT_NODE_HANDLE NewLpiPackageNode;
2187 AML_OBJECT_NODE_HANDLE ResourceTemplateNode;
2188
2189 UINT32 Index;
2190 AML_OBJECT_NODE_HANDLE CountNode;
2191 UINT64 Count;
2192
2193 if ((LpiNode == NULL) ||
2194 (AmlGetNodeType ((AML_NODE_HANDLE)LpiNode) != EAmlNodeObject) ||
2195 (!AmlNodeHasOpCode (LpiNode, AML_NAME_OP, 0)))
2196 {
2197 ASSERT (0);
2198 return EFI_INVALID_PARAMETER;
2199 }
2200
2201 RdNode = 0;
2202 StringNode = NULL;
2203 IntegerNode = NULL;
2204 ResourceTemplateNode = NULL;
2205
2206 // AmlCreateLpiNode () created a LPI container such as:
2207 // Name (_LPI, Package (
2208 // 0, // Revision
2209 // 1, // LevelId
2210 // 0 // Count
2211 // ))
2212 // Get the LPI container, a PackageOp object node stored as the 2nd fixed
2213 // argument (i.e. index 1) of LpiNode.
2214 PackageNode = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
2215 LpiNode,
2216 EAmlParseIndexTerm1
2217 );
2218 if ((PackageNode == NULL) ||
2219 (AmlGetNodeType ((AML_NODE_HANDLE)PackageNode) != EAmlNodeObject) ||
2220 (!AmlNodeHasOpCode (PackageNode, AML_PACKAGE_OP, 0)))
2221 {
2222 ASSERT (0);
2223 return EFI_INVALID_PARAMETER;
2224 }
2225
2226 CountNode = NULL;
2227 // The third variable argument is the LPI Count node.
2228 for (Index = 0; Index < 3; Index++) {
2229 CountNode = (AML_OBJECT_NODE_HANDLE)AmlGetNextVariableArgument (
2230 (AML_NODE_HANDLE)PackageNode,
2231 (AML_NODE_HANDLE)CountNode
2232 );
2233 if (CountNode == NULL) {
2234 ASSERT (0);
2235 return EFI_INVALID_PARAMETER;
2236 }
2237 }
2238
2239 Status = AmlNodeGetIntegerValue (CountNode, &Count);
2240 if (EFI_ERROR (Status)) {
2241 ASSERT (0);
2242 return Status;
2243 }
2244
2245 Status = AmlUpdateInteger (CountNode, Count + 1);
2246 if (EFI_ERROR (Status)) {
2247 ASSERT (0);
2248 return Status;
2249 }
2250
2251 Status = AmlCodeGenPackage (&NewLpiPackageNode);
2252 if (EFI_ERROR (Status)) {
2253 ASSERT (0);
2254 return Status;
2255 }
2256
2257 // MinResidency
2258 Status = AmlCodeGenInteger (MinResidency, &IntegerNode);
2259 if (EFI_ERROR (Status)) {
2260 ASSERT (0);
2261 IntegerNode = NULL;
2262 goto error_handler;
2263 }
2264
2265 Status = AmlVarListAddTail (
2266 (AML_NODE_HANDLE)NewLpiPackageNode,
2267 (AML_NODE_HANDLE)IntegerNode
2268 );
2269 if (EFI_ERROR (Status)) {
2270 ASSERT (0);
2271 goto error_handler;
2272 }
2273
2274 IntegerNode = NULL;
2275
2276 // WorstCaseWakeLatency
2277 Status = AmlCodeGenInteger (WorstCaseWakeLatency, &IntegerNode);
2278 if (EFI_ERROR (Status)) {
2279 ASSERT (0);
2280 IntegerNode = NULL;
2281 goto error_handler;
2282 }
2283
2284 Status = AmlVarListAddTail (
2285 (AML_NODE_HANDLE)NewLpiPackageNode,
2286 (AML_NODE_HANDLE)IntegerNode
2287 );
2288 if (EFI_ERROR (Status)) {
2289 ASSERT (0);
2290 goto error_handler;
2291 }
2292
2293 IntegerNode = NULL;
2294
2295 // Flags
2296 Status = AmlCodeGenInteger (Flags, &IntegerNode);
2297 if (EFI_ERROR (Status)) {
2298 ASSERT (0);
2299 IntegerNode = NULL;
2300 goto error_handler;
2301 }
2302
2303 Status = AmlVarListAddTail (
2304 (AML_NODE_HANDLE)NewLpiPackageNode,
2305 (AML_NODE_HANDLE)IntegerNode
2306 );
2307 if (EFI_ERROR (Status)) {
2308 ASSERT (0);
2309 goto error_handler;
2310 }
2311
2312 IntegerNode = NULL;
2313
2314 // ArchFlags
2315 Status = AmlCodeGenInteger (ArchFlags, &IntegerNode);
2316 if (EFI_ERROR (Status)) {
2317 ASSERT (0);
2318 IntegerNode = NULL;
2319 goto error_handler;
2320 }
2321
2322 Status = AmlVarListAddTail (
2323 (AML_NODE_HANDLE)NewLpiPackageNode,
2324 (AML_NODE_HANDLE)IntegerNode
2325 );
2326 if (EFI_ERROR (Status)) {
2327 ASSERT (0);
2328 goto error_handler;
2329 }
2330
2331 IntegerNode = NULL;
2332
2333 // ResCntFreq
2334 Status = AmlCodeGenInteger (ResCntFreq, &IntegerNode);
2335 if (EFI_ERROR (Status)) {
2336 ASSERT (0);
2337 IntegerNode = NULL;
2338 goto error_handler;
2339 }
2340
2341 Status = AmlVarListAddTail (
2342 (AML_NODE_HANDLE)NewLpiPackageNode,
2343 (AML_NODE_HANDLE)IntegerNode
2344 );
2345 if (EFI_ERROR (Status)) {
2346 ASSERT (0);
2347 goto error_handler;
2348 }
2349
2350 IntegerNode = NULL;
2351
2352 // EnableParentState
2353 Status = AmlCodeGenInteger (EnableParentState, &IntegerNode);
2354 if (EFI_ERROR (Status)) {
2355 ASSERT (0);
2356 IntegerNode = NULL;
2357 goto error_handler;
2358 }
2359
2360 Status = AmlVarListAddTail (
2361 (AML_NODE_HANDLE)NewLpiPackageNode,
2362 (AML_NODE_HANDLE)IntegerNode
2363 );
2364 if (EFI_ERROR (Status)) {
2365 ASSERT (0);
2366 goto error_handler;
2367 }
2368
2369 IntegerNode = NULL;
2370
2371 // Entry Method
2372 if (GenericRegisterDescriptor != NULL) {
2373 // Entry Method: As a Register resource data
2374 Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
2375 if (EFI_ERROR (Status)) {
2376 ASSERT (0);
2377 ResourceTemplateNode = NULL;
2378 goto error_handler;
2379 }
2380
2381 Status = AmlCodeGenRdRegister (
2382 GenericRegisterDescriptor->AddressSpaceId,
2383 GenericRegisterDescriptor->RegisterBitWidth,
2384 GenericRegisterDescriptor->RegisterBitOffset,
2385 GenericRegisterDescriptor->Address,
2386 GenericRegisterDescriptor->AccessSize,
2387 NULL,
2388 &RdNode
2389 );
2390 if (EFI_ERROR (Status)) {
2391 ASSERT (0);
2392 RdNode = NULL;
2393 goto error_handler;
2394 }
2395
2396 Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
2397 if (EFI_ERROR (Status)) {
2398 ASSERT (0);
2399 goto error_handler;
2400 }
2401
2402 RdNode = NULL;
2403
2404 Status = AmlVarListAddTail (
2405 (AML_NODE_HANDLE)NewLpiPackageNode,
2406 (AML_NODE_HANDLE)ResourceTemplateNode
2407 );
2408 if (EFI_ERROR (Status)) {
2409 ASSERT (0);
2410 goto error_handler;
2411 }
2412
2413 ResourceTemplateNode = NULL;
2414 } else {
2415 // Entry Method: As an integer
2416 Status = AmlCodeGenInteger (Integer, &IntegerNode);
2417 if (EFI_ERROR (Status)) {
2418 ASSERT (0);
2419 IntegerNode = NULL;
2420 goto error_handler;
2421 }
2422
2423 Status = AmlVarListAddTail (
2424 (AML_NODE_HANDLE)NewLpiPackageNode,
2425 (AML_NODE_HANDLE)IntegerNode
2426 );
2427 if (EFI_ERROR (Status)) {
2428 ASSERT (0);
2429 goto error_handler;
2430 }
2431
2432 IntegerNode = NULL;
2433 }
2434
2435 // Residency Counter Register.
2436 Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
2437 if (EFI_ERROR (Status)) {
2438 ASSERT (0);
2439 ResourceTemplateNode = NULL;
2440 goto error_handler;
2441 }
2442
2443 if (ResidencyCounterRegister != NULL) {
2444 Status = AmlCodeGenRdRegister (
2445 ResidencyCounterRegister->AddressSpaceId,
2446 ResidencyCounterRegister->RegisterBitWidth,
2447 ResidencyCounterRegister->RegisterBitOffset,
2448 ResidencyCounterRegister->Address,
2449 ResidencyCounterRegister->AccessSize,
2450 NULL,
2451 &RdNode
2452 );
2453 } else {
2454 Status = AmlCodeGenRdRegister (
2455 EFI_ACPI_6_4_SYSTEM_MEMORY,
2456 0,
2457 0,
2458 0,
2459 0,
2460 NULL,
2461 &RdNode
2462 );
2463 }
2464
2465 if (EFI_ERROR (Status)) {
2466 ASSERT (0);
2467 RdNode = NULL;
2468 goto error_handler;
2469 }
2470
2471 Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
2472 if (EFI_ERROR (Status)) {
2473 ASSERT (0);
2474 goto error_handler;
2475 }
2476
2477 RdNode = NULL;
2478
2479 Status = AmlVarListAddTail (
2480 (AML_NODE_HANDLE)NewLpiPackageNode,
2481 (AML_NODE_HANDLE)ResourceTemplateNode
2482 );
2483 if (EFI_ERROR (Status)) {
2484 ASSERT (0);
2485 goto error_handler;
2486 }
2487
2488 ResourceTemplateNode = NULL;
2489
2490 // Usage Counter Register.
2491 Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
2492 if (EFI_ERROR (Status)) {
2493 ASSERT (0);
2494 ResourceTemplateNode = NULL;
2495 goto error_handler;
2496 }
2497
2498 if (UsageCounterRegister != NULL) {
2499 Status = AmlCodeGenRdRegister (
2500 UsageCounterRegister->AddressSpaceId,
2501 UsageCounterRegister->RegisterBitWidth,
2502 UsageCounterRegister->RegisterBitOffset,
2503 UsageCounterRegister->Address,
2504 UsageCounterRegister->AccessSize,
2505 NULL,
2506 &RdNode
2507 );
2508 } else {
2509 Status = AmlCodeGenRdRegister (
2510 EFI_ACPI_6_4_SYSTEM_MEMORY,
2511 0,
2512 0,
2513 0,
2514 0,
2515 NULL,
2516 &RdNode
2517 );
2518 }
2519
2520 if (EFI_ERROR (Status)) {
2521 ASSERT (0);
2522 RdNode = NULL;
2523 goto error_handler;
2524 }
2525
2526 Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
2527 if (EFI_ERROR (Status)) {
2528 ASSERT (0);
2529 goto error_handler;
2530 }
2531
2532 RdNode = NULL;
2533
2534 Status = AmlVarListAddTail (
2535 (AML_NODE_HANDLE)NewLpiPackageNode,
2536 (AML_NODE_HANDLE)ResourceTemplateNode
2537 );
2538 if (EFI_ERROR (Status)) {
2539 ASSERT (0);
2540 goto error_handler;
2541 }
2542
2543 ResourceTemplateNode = NULL;
2544
2545 // State name.
2546 if (UsageCounterRegister != NULL) {
2547 Status = AmlCodeGenString (StateName, &StringNode);
2548 } else {
2549 Status = AmlCodeGenString ("", &StringNode);
2550 }
2551
2552 if (EFI_ERROR (Status)) {
2553 ASSERT (0);
2554 StringNode = NULL;
2555 goto error_handler;
2556 }
2557
2558 Status = AmlVarListAddTail (
2559 (AML_NODE_HANDLE)NewLpiPackageNode,
2560 (AML_NODE_HANDLE)StringNode
2561 );
2562 if (EFI_ERROR (Status)) {
2563 ASSERT (0);
2564 goto error_handler;
2565 }
2566
2567 StringNode = NULL;
2568
2569 // Add the new LPI state to the LpiNode.
2570 Status = AmlVarListAddTail (
2571 (AML_NODE_HANDLE)PackageNode,
2572 (AML_NODE_HANDLE)NewLpiPackageNode
2573 );
2574 if (EFI_ERROR (Status)) {
2575 ASSERT (0);
2576 goto error_handler;
2577 }
2578
2579 return Status;
2580
2581 error_handler:
2582 if (RdNode != NULL) {
2583 AmlDeleteTree ((AML_NODE_HANDLE)RdNode);
2584 }
2585
2586 if (NewLpiPackageNode != NULL) {
2587 AmlDeleteTree ((AML_NODE_HANDLE)NewLpiPackageNode);
2588 }
2589
2590 if (StringNode != NULL) {
2591 AmlDeleteTree ((AML_NODE_HANDLE)StringNode);
2592 }
2593
2594 if (IntegerNode != NULL) {
2595 AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode);
2596 }
2597
2598 if (ResourceTemplateNode != NULL) {
2599 AmlDeleteTree ((AML_NODE_HANDLE)ResourceTemplateNode);
2600 }
2601
2602 return Status;
2603 }
2604
2605 /** AML code generation for a _DSD device data object.
2606
2607 AmlAddDeviceDataDescriptorPackage (Uuid, DsdNode, PackageNode) is
2608 equivalent of the following ASL code:
2609 ToUUID(Uuid),
2610 Package () {}
2611
2612 Cf ACPI 6.4 specification, s6.2.5 "_DSD (Device Specific Data)".
2613
2614 _DSD (Device Specific Data) Implementation Guide
2615 https://github.com/UEFI/DSD-Guide
2616 Per s3. "'Well-Known _DSD UUIDs and Data Structure Formats'"
2617 If creating a Device Properties data then UUID daffd814-6eba-4d8c-8a91-bc9bbf4aa301 should be used.
2618
2619 @param [in] Uuid The Uuid of the descriptor to be created
2620 @param [in] DsdNode Node of the DSD Package.
2621 @param [out] PackageNode If success, contains the created package node.
2622
2623 @retval EFI_SUCCESS Success.
2624 @retval EFI_INVALID_PARAMETER Invalid parameter.
2625 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
2626 **/
2627 EFI_STATUS
2628 EFIAPI
2629 AmlAddDeviceDataDescriptorPackage (
2630 IN CONST EFI_GUID *Uuid,
2631 IN AML_OBJECT_NODE_HANDLE DsdNode,
2632 OUT AML_OBJECT_NODE_HANDLE *PackageNode
2633 )
2634 {
2635 EFI_STATUS Status;
2636 AML_OBJECT_NODE *UuidNode;
2637 AML_DATA_NODE *UuidDataNode;
2638 AML_OBJECT_NODE_HANDLE DsdEntryList;
2639
2640 if ((Uuid == NULL) ||
2641 (PackageNode == NULL) ||
2642 (AmlGetNodeType ((AML_NODE_HANDLE)DsdNode) != EAmlNodeObject) ||
2643 (!AmlNodeHasOpCode (DsdNode, AML_NAME_OP, 0)) ||
2644 !AmlNameOpCompareName (DsdNode, "_DSD"))
2645 {
2646 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
2647 return EFI_INVALID_PARAMETER;
2648 }
2649
2650 // Get the Package object node of the _DSD node,
2651 // which is the 2nd fixed argument (i.e. index 1).
2652 DsdEntryList = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
2653 DsdNode,
2654 EAmlParseIndexTerm1
2655 );
2656 if ((DsdEntryList == NULL) ||
2657 (AmlGetNodeType ((AML_NODE_HANDLE)DsdEntryList) != EAmlNodeObject) ||
2658 (!AmlNodeHasOpCode (DsdEntryList, AML_PACKAGE_OP, 0)))
2659 {
2660 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
2661 return EFI_INVALID_PARAMETER;
2662 }
2663
2664 *PackageNode = NULL;
2665 UuidDataNode = NULL;
2666
2667 Status = AmlCodeGenBuffer (NULL, 0, &UuidNode);
2668 if (EFI_ERROR (Status)) {
2669 ASSERT_EFI_ERROR (Status);
2670 return Status;
2671 }
2672
2673 Status = AmlCreateDataNode (
2674 EAmlNodeDataTypeRaw,
2675 (CONST UINT8 *)Uuid,
2676 sizeof (EFI_GUID),
2677 &UuidDataNode
2678 );
2679 if (EFI_ERROR (Status)) {
2680 ASSERT_EFI_ERROR (Status);
2681 goto error_handler;
2682 }
2683
2684 Status = AmlVarListAddTail (
2685 (AML_NODE_HEADER *)UuidNode,
2686 (AML_NODE_HEADER *)UuidDataNode
2687 );
2688 if (EFI_ERROR (Status)) {
2689 ASSERT_EFI_ERROR (Status);
2690 goto error_handler;
2691 }
2692
2693 UuidDataNode = NULL;
2694
2695 // Append to the list of _DSD entries.
2696 Status = AmlVarListAddTail (
2697 (AML_NODE_HANDLE)DsdEntryList,
2698 (AML_NODE_HANDLE)UuidNode
2699 );
2700 if (EFI_ERROR (Status)) {
2701 ASSERT_EFI_ERROR (Status);
2702 goto error_handler;
2703 }
2704
2705 Status = AmlCodeGenPackage (PackageNode);
2706 if (EFI_ERROR (Status)) {
2707 ASSERT_EFI_ERROR (Status);
2708 goto error_handler_detach;
2709 }
2710
2711 // Append to the list of _DSD entries.
2712 Status = AmlVarListAddTail (
2713 (AML_NODE_HANDLE)DsdEntryList,
2714 (AML_NODE_HANDLE)*PackageNode
2715 );
2716 if (EFI_ERROR (Status)) {
2717 ASSERT_EFI_ERROR (Status);
2718 goto error_handler_detach;
2719 }
2720
2721 return Status;
2722
2723 error_handler_detach:
2724 if (UuidNode != NULL) {
2725 AmlDetachNode ((AML_NODE_HANDLE)UuidNode);
2726 }
2727
2728 error_handler:
2729 if (UuidNode != NULL) {
2730 AmlDeleteTree ((AML_NODE_HANDLE)UuidNode);
2731 }
2732
2733 if (*PackageNode != NULL) {
2734 AmlDeleteTree ((AML_NODE_HANDLE)*PackageNode);
2735 *PackageNode = NULL;
2736 }
2737
2738 if (UuidDataNode != NULL) {
2739 AmlDeleteTree ((AML_NODE_HANDLE)UuidDataNode);
2740 }
2741
2742 return Status;
2743 }
2744
2745 /** AML code generation to add a package with a name and value,
2746 to a parent package.
2747 This is useful to build the _DSD package but can be used in other cases.
2748
2749 AmlAddNameIntegerPackage ("Name", Value, PackageNode) is
2750 equivalent of the following ASL code:
2751 Package (2) {"Name", Value}
2752
2753 Cf ACPI 6.4 specification, s6.2.5 "_DSD (Device Specific Data)".
2754
2755 @param [in] Name String to place in first entry of package
2756 @param [in] Value Integer to place in second entry of package
2757 @param [in] PackageNode Package to add new sub package to.
2758
2759 @retval EFI_SUCCESS Success.
2760 @retval EFI_INVALID_PARAMETER Invalid parameter.
2761 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
2762 **/
2763 EFI_STATUS
2764 EFIAPI
2765 AmlAddNameIntegerPackage (
2766 IN CHAR8 *Name,
2767 IN UINT64 Value,
2768 IN AML_OBJECT_NODE_HANDLE PackageNode
2769 )
2770 {
2771 EFI_STATUS Status;
2772 AML_OBJECT_NODE *NameNode;
2773 AML_OBJECT_NODE *ValueNode;
2774 AML_OBJECT_NODE *NewPackageNode;
2775
2776 if ((Name == NULL) ||
2777 (AmlGetNodeType ((AML_NODE_HANDLE)PackageNode) != EAmlNodeObject) ||
2778 (!AmlNodeHasOpCode (PackageNode, AML_PACKAGE_OP, 0)))
2779 {
2780 ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
2781 return EFI_INVALID_PARAMETER;
2782 }
2783
2784 NameNode = NULL;
2785 ValueNode = NULL;
2786
2787 // The new package entry.
2788 Status = AmlCodeGenPackage (&NewPackageNode);
2789 if (EFI_ERROR (Status)) {
2790 ASSERT_EFI_ERROR (Status);
2791 return Status;
2792 }
2793
2794 Status = AmlCodeGenString (Name, &NameNode);
2795 if (EFI_ERROR (Status)) {
2796 ASSERT_EFI_ERROR (Status);
2797 goto error_handler;
2798 }
2799
2800 Status = AmlVarListAddTail (
2801 (AML_NODE_HANDLE)NewPackageNode,
2802 (AML_NODE_HANDLE)NameNode
2803 );
2804 if (EFI_ERROR (Status)) {
2805 ASSERT_EFI_ERROR (Status);
2806 goto error_handler;
2807 }
2808
2809 NameNode = NULL;
2810
2811 Status = AmlCodeGenInteger (Value, &ValueNode);
2812 if (EFI_ERROR (Status)) {
2813 ASSERT_EFI_ERROR (Status);
2814 goto error_handler;
2815 }
2816
2817 Status = AmlVarListAddTail (
2818 (AML_NODE_HANDLE)NewPackageNode,
2819 (AML_NODE_HANDLE)ValueNode
2820 );
2821 if (EFI_ERROR (Status)) {
2822 ASSERT_EFI_ERROR (Status);
2823 goto error_handler;
2824 }
2825
2826 ValueNode = NULL;
2827
2828 Status = AmlVarListAddTail (
2829 (AML_NODE_HANDLE)PackageNode,
2830 (AML_NODE_HANDLE)NewPackageNode
2831 );
2832 if (EFI_ERROR (Status)) {
2833 ASSERT_EFI_ERROR (Status);
2834 goto error_handler;
2835 }
2836
2837 return Status;
2838
2839 error_handler:
2840 if (NewPackageNode != NULL) {
2841 AmlDeleteTree ((AML_NODE_HANDLE)NewPackageNode);
2842 }
2843
2844 if (NameNode != NULL) {
2845 AmlDeleteTree ((AML_NODE_HANDLE)NameNode);
2846 }
2847
2848 if (ValueNode != NULL) {
2849 AmlDeleteTree ((AML_NODE_HANDLE)ValueNode);
2850 }
2851
2852 return Status;
2853 }
2854
2855 /** Adds a register to the package
2856
2857 @ingroup CodeGenApis
2858
2859 @param [in] Register If provided, register that will be added to package.
2860 otherwise NULL register will be added
2861 @param [in] PackageNode Package to add value to
2862
2863 @retval EFI_SUCCESS The function completed successfully.
2864 @retval EFI_INVALID_PARAMETER Invalid parameter.
2865 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
2866 **/
2867 STATIC
2868 EFI_STATUS
2869 EFIAPI
2870 AmlAddRegisterToPackage (
2871 IN EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE *Register OPTIONAL,
2872 IN AML_OBJECT_NODE_HANDLE PackageNode
2873 )
2874 {
2875 EFI_STATUS Status;
2876 AML_DATA_NODE_HANDLE RdNode;
2877 AML_OBJECT_NODE_HANDLE ResourceTemplateNode;
2878
2879 RdNode = NULL;
2880
2881 Status = AmlCodeGenResourceTemplate (&ResourceTemplateNode);
2882 if (EFI_ERROR (Status)) {
2883 ASSERT_EFI_ERROR (Status);
2884 return Status;
2885 }
2886
2887 if (Register != NULL) {
2888 Status = AmlCodeGenRdRegister (
2889 Register->AddressSpaceId,
2890 Register->RegisterBitWidth,
2891 Register->RegisterBitOffset,
2892 Register->Address,
2893 Register->AccessSize,
2894 NULL,
2895 &RdNode
2896 );
2897 } else {
2898 Status = AmlCodeGenRdRegister (
2899 EFI_ACPI_6_4_SYSTEM_MEMORY,
2900 0,
2901 0,
2902 0,
2903 0,
2904 NULL,
2905 &RdNode
2906 );
2907 }
2908
2909 if (EFI_ERROR (Status)) {
2910 ASSERT_EFI_ERROR (Status);
2911 goto error_handler;
2912 }
2913
2914 Status = AmlAppendRdNode (ResourceTemplateNode, RdNode);
2915 if (EFI_ERROR (Status)) {
2916 ASSERT_EFI_ERROR (Status);
2917 goto error_handler;
2918 }
2919
2920 RdNode = NULL;
2921
2922 Status = AmlVarListAddTail (
2923 (AML_NODE_HANDLE)PackageNode,
2924 (AML_NODE_HANDLE)ResourceTemplateNode
2925 );
2926 if (EFI_ERROR (Status)) {
2927 ASSERT_EFI_ERROR (Status);
2928 goto error_handler;
2929 }
2930
2931 return Status;
2932
2933 error_handler:
2934 if (RdNode != NULL) {
2935 AmlDeleteTree ((AML_NODE_HANDLE)RdNode);
2936 }
2937
2938 if (ResourceTemplateNode != NULL) {
2939 AmlDeleteTree ((AML_NODE_HANDLE)ResourceTemplateNode);
2940 }
2941
2942 return Status;
2943 }
2944
2945 /** Utility function to check if generic address points to NULL
2946
2947 @param [in] Address Pointer to the Generic address
2948
2949 @retval TRUE Address is system memory with an Address of 0.
2950 @retval FALSE Address does not point to NULL.
2951 **/
2952 STATIC
2953 BOOLEAN
2954 EFIAPI
2955 IsNullGenericAddress (
2956 IN EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE *Address
2957 )
2958 {
2959 if ((Address == NULL) ||
2960 ((Address->AddressSpaceId == EFI_ACPI_6_4_SYSTEM_MEMORY) &&
2961 (Address->Address == 0x0)))
2962 {
2963 return TRUE;
2964 }
2965
2966 return FALSE;
2967 }
2968
2969 /** Adds an integer or register to the package
2970
2971 @ingroup CodeGenApis
2972
2973 @param [in] Register If provided, register that will be added to package
2974 @param [in] Integer If Register is NULL, integer that will be added to the package
2975 @param [in] PackageNode Package to add value to
2976
2977 @retval EFI_SUCCESS The function completed successfully.
2978 @retval EFI_INVALID_PARAMETER Invalid parameter.
2979 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
2980 **/
2981 STATIC
2982 EFI_STATUS
2983 EFIAPI
2984 AmlAddRegisterOrIntegerToPackage (
2985 IN EFI_ACPI_6_4_GENERIC_ADDRESS_STRUCTURE *Register OPTIONAL,
2986 IN UINT32 Integer,
2987 IN AML_OBJECT_NODE_HANDLE PackageNode
2988 )
2989 {
2990 EFI_STATUS Status;
2991 AML_OBJECT_NODE_HANDLE IntegerNode;
2992
2993 IntegerNode = NULL;
2994
2995 if (!IsNullGenericAddress (Register)) {
2996 Status = AmlAddRegisterToPackage (Register, PackageNode);
2997 } else {
2998 Status = AmlCodeGenInteger (Integer, &IntegerNode);
2999 if (EFI_ERROR (Status)) {
3000 ASSERT_EFI_ERROR (Status);
3001 return Status;
3002 }
3003
3004 Status = AmlVarListAddTail (
3005 (AML_NODE_HANDLE)PackageNode,
3006 (AML_NODE_HANDLE)IntegerNode
3007 );
3008 }
3009
3010 if (EFI_ERROR (Status)) {
3011 ASSERT_EFI_ERROR (Status);
3012 if (IntegerNode != NULL) {
3013 AmlDeleteTree ((AML_NODE_HANDLE)IntegerNode);
3014 }
3015 }
3016
3017 return Status;
3018 }
3019
3020 /** Create a _CPC node.
3021
3022 Creates and optionally adds the following node
3023 Name(_CPC, Package()
3024 {
3025 NumEntries, // Integer
3026 Revision, // Integer
3027 HighestPerformance, // Integer or Buffer (Resource Descriptor)
3028 NominalPerformance, // Integer or Buffer (Resource Descriptor)
3029 LowestNonlinearPerformance, // Integer or Buffer (Resource Descriptor)
3030 LowestPerformance, // Integer or Buffer (Resource Descriptor)
3031 GuaranteedPerformanceRegister, // Buffer (Resource Descriptor)
3032 DesiredPerformanceRegister , // Buffer (Resource Descriptor)
3033 MinimumPerformanceRegister , // Buffer (Resource Descriptor)
3034 MaximumPerformanceRegister , // Buffer (Resource Descriptor)
3035 PerformanceReductionToleranceRegister, // Buffer (Resource Descriptor)
3036 TimeWindowRegister, // Buffer (Resource Descriptor)
3037 CounterWraparoundTime, // Integer or Buffer (Resource Descriptor)
3038 ReferencePerformanceCounterRegister, // Buffer (Resource Descriptor)
3039 DeliveredPerformanceCounterRegister, // Buffer (Resource Descriptor)
3040 PerformanceLimitedRegister, // Buffer (Resource Descriptor)
3041 CPPCEnableRegister // Buffer (Resource Descriptor)
3042 AutonomousSelectionEnable, // Integer or Buffer (Resource Descriptor)
3043 AutonomousActivityWindowRegister, // Buffer (Resource Descriptor)
3044 EnergyPerformancePreferenceRegister, // Buffer (Resource Descriptor)
3045 ReferencePerformance // Integer or Buffer (Resource Descriptor)
3046 LowestFrequency, // Integer or Buffer (Resource Descriptor)
3047 NominalFrequency // Integer or Buffer (Resource Descriptor)
3048 })
3049
3050 If resource buffer is NULL then integer will be used.
3051
3052 Cf. ACPI 6.4, s8.4.7.1 _CPC (Continuous Performance Control)
3053
3054 @ingroup CodeGenApis
3055
3056 @param [in] CpcInfo CpcInfo object
3057 @param [in] ParentNode If provided, set ParentNode as the parent
3058 of the node created.
3059 @param [out] NewCpcNode If success and provided, contains the created node.
3060
3061 @retval EFI_SUCCESS The function completed successfully.
3062 @retval EFI_INVALID_PARAMETER Invalid parameter.
3063 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
3064 **/
3065 EFI_STATUS
3066 EFIAPI
3067 AmlCreateCpcNode (
3068 IN AML_CPC_INFO *CpcInfo,
3069 IN AML_NODE_HANDLE ParentNode OPTIONAL,
3070 OUT AML_OBJECT_NODE_HANDLE *NewCpcNode OPTIONAL
3071 )
3072 {
3073 EFI_STATUS Status;
3074 AML_OBJECT_NODE_HANDLE CpcNode;
3075 AML_OBJECT_NODE_HANDLE CpcPackage;
3076 UINT32 NumberOfEntries;
3077
3078 if ((CpcInfo == NULL) ||
3079 ((ParentNode == NULL) && (NewCpcNode == NULL)))
3080 {
3081 ASSERT (0);
3082 return EFI_INVALID_PARAMETER;
3083 }
3084
3085 // Revision 3 per ACPI 6.4 specification
3086 if (CpcInfo->Revision == 3) {
3087 // NumEntries 23 per ACPI 6.4 specification
3088 NumberOfEntries = 23;
3089 } else {
3090 ASSERT (0);
3091 return EFI_INVALID_PARAMETER;
3092 }
3093
3094 if ((IsNullGenericAddress (&CpcInfo->HighestPerformanceBuffer) &&
3095 (CpcInfo->HighestPerformanceInteger == 0)) ||
3096 (IsNullGenericAddress (&CpcInfo->NominalPerformanceBuffer) &&
3097 (CpcInfo->NominalPerformanceInteger == 0)) ||
3098 (IsNullGenericAddress (&CpcInfo->LowestNonlinearPerformanceBuffer) &&
3099 (CpcInfo->LowestNonlinearPerformanceInteger == 0)) ||
3100 (IsNullGenericAddress (&CpcInfo->LowestPerformanceBuffer) &&
3101 (CpcInfo->LowestPerformanceInteger == 0)) ||
3102 IsNullGenericAddress (&CpcInfo->DesiredPerformanceRegister) ||
3103 IsNullGenericAddress (&CpcInfo->ReferencePerformanceCounterRegister) ||
3104 IsNullGenericAddress (&CpcInfo->DeliveredPerformanceCounterRegister) ||
3105 IsNullGenericAddress (&CpcInfo->PerformanceLimitedRegister))
3106 {
3107 ASSERT (0);
3108 return EFI_INVALID_PARAMETER;
3109 }
3110
3111 CpcPackage = NULL;
3112
3113 Status = AmlCodeGenNamePackage ("_CPC", NULL, &CpcNode);
3114 if (EFI_ERROR (Status)) {
3115 ASSERT_EFI_ERROR (Status);
3116 return Status;
3117 }
3118
3119 // Get the Package object node of the _CPC node,
3120 // which is the 2nd fixed argument (i.e. index 1).
3121 CpcPackage = (AML_OBJECT_NODE_HANDLE)AmlGetFixedArgument (
3122 CpcNode,
3123 EAmlParseIndexTerm1
3124 );
3125 if ((CpcPackage == NULL) ||
3126 (AmlGetNodeType ((AML_NODE_HANDLE)CpcPackage) != EAmlNodeObject) ||
3127 (!AmlNodeHasOpCode (CpcPackage, AML_PACKAGE_OP, 0)))
3128 {
3129 ASSERT (0);
3130 Status = EFI_INVALID_PARAMETER;
3131 goto error_handler;
3132 }
3133
3134 Status = AmlAddRegisterOrIntegerToPackage (
3135 NULL,
3136 NumberOfEntries,
3137 CpcPackage
3138 );
3139 if (EFI_ERROR (Status)) {
3140 ASSERT_EFI_ERROR (Status);
3141 goto error_handler;
3142 }
3143
3144 Status = AmlAddRegisterOrIntegerToPackage (
3145 NULL,
3146 CpcInfo->Revision,
3147 CpcPackage
3148 );
3149 if (EFI_ERROR (Status)) {
3150 ASSERT_EFI_ERROR (Status);
3151 goto error_handler;
3152 }
3153
3154 Status = AmlAddRegisterOrIntegerToPackage (
3155 &CpcInfo->HighestPerformanceBuffer,
3156 CpcInfo->HighestPerformanceInteger,
3157 CpcPackage
3158 );
3159 if (EFI_ERROR (Status)) {
3160 ASSERT_EFI_ERROR (Status);
3161 goto error_handler;
3162 }
3163
3164 Status = AmlAddRegisterOrIntegerToPackage (
3165 &CpcInfo->NominalPerformanceBuffer,
3166 CpcInfo->NominalPerformanceInteger,
3167 CpcPackage
3168 );
3169 if (EFI_ERROR (Status)) {
3170 ASSERT_EFI_ERROR (Status);
3171 goto error_handler;
3172 }
3173
3174 Status = AmlAddRegisterOrIntegerToPackage (
3175 &CpcInfo->LowestNonlinearPerformanceBuffer,
3176 CpcInfo->LowestNonlinearPerformanceInteger,
3177 CpcPackage
3178 );
3179 if (EFI_ERROR (Status)) {
3180 ASSERT_EFI_ERROR (Status);
3181 goto error_handler;
3182 }
3183
3184 Status = AmlAddRegisterOrIntegerToPackage (
3185 &CpcInfo->LowestPerformanceBuffer,
3186 CpcInfo->LowestPerformanceInteger,
3187 CpcPackage
3188 );
3189 if (EFI_ERROR (Status)) {
3190 ASSERT_EFI_ERROR (Status);
3191 goto error_handler;
3192 }
3193
3194 Status = AmlAddRegisterToPackage (&CpcInfo->GuaranteedPerformanceRegister, CpcPackage);
3195 if (EFI_ERROR (Status)) {
3196 ASSERT_EFI_ERROR (Status);
3197 goto error_handler;
3198 }
3199
3200 Status = AmlAddRegisterToPackage (&CpcInfo->DesiredPerformanceRegister, CpcPackage);
3201 if (EFI_ERROR (Status)) {
3202 ASSERT_EFI_ERROR (Status);
3203 goto error_handler;
3204 }
3205
3206 Status = AmlAddRegisterToPackage (&CpcInfo->MinimumPerformanceRegister, CpcPackage);
3207 if (EFI_ERROR (Status)) {
3208 ASSERT_EFI_ERROR (Status);
3209 goto error_handler;
3210 }
3211
3212 Status = AmlAddRegisterToPackage (&CpcInfo->MaximumPerformanceRegister, CpcPackage);
3213 if (EFI_ERROR (Status)) {
3214 ASSERT_EFI_ERROR (Status);
3215 goto error_handler;
3216 }
3217
3218 Status = AmlAddRegisterToPackage (&CpcInfo->PerformanceReductionToleranceRegister, CpcPackage);
3219 if (EFI_ERROR (Status)) {
3220 ASSERT_EFI_ERROR (Status);
3221 goto error_handler;
3222 }
3223
3224 Status = AmlAddRegisterToPackage (&CpcInfo->TimeWindowRegister, CpcPackage);
3225 if (EFI_ERROR (Status)) {
3226 ASSERT_EFI_ERROR (Status);
3227 goto error_handler;
3228 }
3229
3230 Status = AmlAddRegisterOrIntegerToPackage (
3231 &CpcInfo->CounterWraparoundTimeBuffer,
3232 CpcInfo->CounterWraparoundTimeInteger,
3233 CpcPackage
3234 );
3235 if (EFI_ERROR (Status)) {
3236 ASSERT_EFI_ERROR (Status);
3237 goto error_handler;
3238 }
3239
3240 Status = AmlAddRegisterToPackage (&CpcInfo->ReferencePerformanceCounterRegister, CpcPackage);
3241 if (EFI_ERROR (Status)) {
3242 ASSERT_EFI_ERROR (Status);
3243 goto error_handler;
3244 }
3245
3246 Status = AmlAddRegisterToPackage (&CpcInfo->DeliveredPerformanceCounterRegister, CpcPackage);
3247 if (EFI_ERROR (Status)) {
3248 ASSERT_EFI_ERROR (Status);
3249 goto error_handler;
3250 }
3251
3252 Status = AmlAddRegisterToPackage (&CpcInfo->PerformanceLimitedRegister, CpcPackage);
3253 if (EFI_ERROR (Status)) {
3254 ASSERT_EFI_ERROR (Status);
3255 goto error_handler;
3256 }
3257
3258 Status = AmlAddRegisterToPackage (&CpcInfo->CPPCEnableRegister, CpcPackage);
3259 if (EFI_ERROR (Status)) {
3260 ASSERT_EFI_ERROR (Status);
3261 goto error_handler;
3262 }
3263
3264 Status = AmlAddRegisterOrIntegerToPackage (
3265 &CpcInfo->AutonomousSelectionEnableBuffer,
3266 CpcInfo->AutonomousSelectionEnableInteger,
3267 CpcPackage
3268 );
3269 if (EFI_ERROR (Status)) {
3270 ASSERT_EFI_ERROR (Status);
3271 goto error_handler;
3272 }
3273
3274 Status = AmlAddRegisterToPackage (&CpcInfo->AutonomousActivityWindowRegister, CpcPackage);
3275 if (EFI_ERROR (Status)) {
3276 ASSERT_EFI_ERROR (Status);
3277 goto error_handler;
3278 }
3279
3280 Status = AmlAddRegisterToPackage (&CpcInfo->EnergyPerformancePreferenceRegister, CpcPackage);
3281 if (EFI_ERROR (Status)) {
3282 ASSERT_EFI_ERROR (Status);
3283 goto error_handler;
3284 }
3285
3286 Status = AmlAddRegisterOrIntegerToPackage (
3287 &CpcInfo->ReferencePerformanceBuffer,
3288 CpcInfo->ReferencePerformanceInteger,
3289 CpcPackage
3290 );
3291 if (EFI_ERROR (Status)) {
3292 ASSERT_EFI_ERROR (Status);
3293 goto error_handler;
3294 }
3295
3296 Status = AmlAddRegisterOrIntegerToPackage (
3297 &CpcInfo->LowestFrequencyBuffer,
3298 CpcInfo->LowestFrequencyInteger,
3299 CpcPackage
3300 );
3301 if (EFI_ERROR (Status)) {
3302 ASSERT_EFI_ERROR (Status);
3303 goto error_handler;
3304 }
3305
3306 Status = AmlAddRegisterOrIntegerToPackage (
3307 &CpcInfo->NominalFrequencyBuffer,
3308 CpcInfo->NominalFrequencyInteger,
3309 CpcPackage
3310 );
3311 if (EFI_ERROR (Status)) {
3312 ASSERT_EFI_ERROR (Status);
3313 goto error_handler;
3314 }
3315
3316 Status = LinkNode (CpcNode, ParentNode, NewCpcNode);
3317 if (EFI_ERROR (Status)) {
3318 ASSERT_EFI_ERROR (Status);
3319 goto error_handler;
3320 }
3321
3322 return Status;
3323
3324 error_handler:
3325 AmlDeleteTree ((AML_NODE_HANDLE)CpcNode);
3326 return Status;
3327 }