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