aslcodegen.c revision 1.1.1.16.4.2 1 /******************************************************************************
2 *
3 * Module Name: aslcodegen - AML code generation
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2021, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "amlcode.h"
47 #include "acconvert.h"
48
49 #define _COMPONENT ACPI_COMPILER
50 ACPI_MODULE_NAME ("aslcodegen")
51
52 /* Local prototypes */
53
54 static ACPI_STATUS
55 CgAmlWriteWalk (
56 ACPI_PARSE_OBJECT *Op,
57 UINT32 Level,
58 void *Context);
59
60 static void
61 CgWriteAmlOpcode (
62 ACPI_PARSE_OBJECT *Op);
63
64 static void
65 CgWriteTableHeader (
66 ACPI_PARSE_OBJECT *Op);
67
68 static void
69 CgWriteNode (
70 ACPI_PARSE_OBJECT *Op);
71
72 static void
73 CgUpdateHeader (
74 ACPI_PARSE_OBJECT *Op);
75
76
77 /*******************************************************************************
78 *
79 * FUNCTION: CgGenerateAmlOutput
80 *
81 * PARAMETERS: None.
82 *
83 * RETURN: None
84 *
85 * DESCRIPTION: Generate AML code. Currently generates the listing file
86 * simultaneously.
87 *
88 ******************************************************************************/
89
90 void
91 CgGenerateAmlOutput (
92 void)
93 {
94
95 /* Generate the AML output file */
96
97 TrWalkParseTree (AslGbl_CurrentDB,
98 ASL_WALK_VISIT_DOWNWARD | ASL_WALK_VISIT_DB_SEPARATELY,
99 CgAmlWriteWalk, NULL, NULL);
100
101 DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER2);
102 CgUpdateHeader (AslGbl_CurrentDB);
103 }
104
105
106 /*******************************************************************************
107 *
108 * FUNCTION: CgAmlWriteWalk
109 *
110 * PARAMETERS: ASL_WALK_CALLBACK
111 *
112 * RETURN: Status
113 *
114 * DESCRIPTION: Parse tree walk to generate the AML code.
115 *
116 ******************************************************************************/
117
118 static ACPI_STATUS
119 CgAmlWriteWalk (
120 ACPI_PARSE_OBJECT *Op,
121 UINT32 Level,
122 void *Context)
123 {
124
125 /* Generate the AML for this node */
126
127 CgWriteNode (Op);
128
129 if (!AslGbl_DebugFlag)
130 {
131 return (AE_OK);
132 }
133
134 /* Print header at level 0. Alignment assumes 32-bit pointers */
135
136 if (!Level)
137 {
138 DbgPrint (ASL_TREE_OUTPUT,
139 "\nFinal parse tree used for AML output:\n");
140 DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER2);
141 }
142
143 /* Dump ParseOp name and possible value */
144
145 switch (Op->Asl.ParseOpcode)
146 {
147 case PARSEOP_NAMESEG:
148 case PARSEOP_NAMESTRING:
149 case PARSEOP_METHODCALL:
150 case PARSEOP_STRING_LITERAL:
151
152 UtDumpStringOp (Op, Level);
153 break;
154
155 default:
156
157 UtDumpBasicOp (Op, Level);
158 break;
159 }
160
161 DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_DEBUG2,
162 /* 1 */ (UINT32) Op->Asl.Value.Integer,
163 /* 2 */ Op->Asl.ParseOpcode,
164 /* 3 */ Op->Asl.AmlOpcode,
165 /* 4 */ Op->Asl.AmlOpcodeLength,
166 /* 5 */ Op->Asl.AmlPkgLenBytes,
167 /* 6 */ Op->Asl.AmlLength,
168 /* 7 */ Op->Asl.AmlSubtreeLength,
169 /* 8 */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0,
170 /* 9 */ Op,
171 /* 10 */ Op->Asl.Parent,
172 /* 11 */ Op->Asl.Child,
173 /* 12 */ Op->Asl.Next,
174 /* 13 */ Op->Asl.CompileFlags,
175 /* 14 */ Op->Asl.AcpiBtype,
176 /* 15 */ Op->Asl.FinalAmlLength,
177 /* 16 */ Op->Asl.Column,
178 /* 17 */ Op->Asl.LineNumber,
179 /* 18 */ Op->Asl.EndLine,
180 /* 19 */ Op->Asl.LogicalLineNumber,
181 /* 20 */ Op->Asl.EndLogicalLine);
182
183 TrPrintOpFlags (Op->Asl.CompileFlags, ASL_TREE_OUTPUT);
184 DbgPrint (ASL_TREE_OUTPUT, "\n");
185 return (AE_OK);
186 }
187
188
189 /*******************************************************************************
190 *
191 * FUNCTION: CgLocalWriteAmlData
192 *
193 * PARAMETERS: Op - Current parse op
194 * Buffer - Buffer to write
195 * Length - Size of data in buffer
196 *
197 * RETURN: None
198 *
199 * DESCRIPTION: Write a buffer of AML data to the AML output file.
200 *
201 ******************************************************************************/
202
203 void
204 CgLocalWriteAmlData (
205 ACPI_PARSE_OBJECT *Op,
206 void *Buffer,
207 UINT32 Length)
208 {
209
210 /* Write the raw data to the AML file */
211
212 FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length);
213
214 /* Update the final AML length for this node (used for listings) */
215
216 if (Op)
217 {
218 Op->Asl.FinalAmlLength += Length;
219 }
220 }
221
222
223 /*******************************************************************************
224 *
225 * FUNCTION: CgWriteAmlOpcode
226 *
227 * PARAMETERS: Op - Parse node with an AML opcode
228 *
229 * RETURN: None.
230 *
231 * DESCRIPTION: Write the AML opcode corresponding to a parse node.
232 *
233 ******************************************************************************/
234
235 static void
236 CgWriteAmlOpcode (
237 ACPI_PARSE_OBJECT *Op)
238 {
239 UINT8 PkgLenFirstByte;
240 UINT32 i;
241 union {
242 UINT16 Opcode;
243 UINT8 OpcodeBytes[2];
244 } Aml;
245 union {
246 UINT32 Len;
247 UINT8 LenBytes[4];
248 } PkgLen;
249
250
251 /* We expect some DEFAULT_ARGs, just ignore them */
252
253 if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
254 {
255 return;
256 }
257
258 /*
259 * Before printing the bytecode, generate comment byte codes
260 * associated with this node.
261 */
262 if (AcpiGbl_CaptureComments)
263 {
264 CgWriteAmlComment(Op);
265 }
266
267 switch (Op->Asl.AmlOpcode)
268 {
269 case AML_UNASSIGNED_OPCODE:
270
271 /* These opcodes should not get here */
272
273 printf ("Found a node with an unassigned AML opcode\n");
274 FlPrintFile (ASL_FILE_STDERR,
275 "Found a node with an unassigned AML opcode\n");
276 return;
277
278 case AML_INT_RESERVEDFIELD_OP:
279
280 /* Special opcodes for within a field definition */
281
282 Aml.Opcode = AML_FIELD_OFFSET_OP;
283 break;
284
285 case AML_INT_ACCESSFIELD_OP:
286
287 Aml.Opcode = AML_FIELD_ACCESS_OP;
288 break;
289
290 case AML_INT_CONNECTION_OP:
291
292 Aml.Opcode = AML_FIELD_CONNECTION_OP;
293 break;
294
295 default:
296
297 Aml.Opcode = Op->Asl.AmlOpcode;
298 break;
299 }
300
301
302 switch (Aml.Opcode)
303 {
304 case AML_PACKAGE_LENGTH:
305
306 /* Value is the length to be encoded (Used in field definitions) */
307
308 PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
309 break;
310
311 default:
312
313 /* Check for two-byte opcode */
314
315 if (Aml.Opcode > 0x00FF)
316 {
317 /* Write the high byte first */
318
319 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
320 }
321
322 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
323
324 /* Subtreelength doesn't include length of package length bytes */
325
326 PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
327 break;
328 }
329
330 /* Does this opcode have an associated "PackageLength" field? */
331
332 if (Op->Asl.CompileFlags & OP_AML_PACKAGE)
333 {
334 if (Op->Asl.AmlPkgLenBytes == 1)
335 {
336 /* Simplest case -- no bytes to follow, just write the count */
337
338 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
339 }
340 else if (Op->Asl.AmlPkgLenBytes != 0)
341 {
342 /*
343 * Encode the "bytes to follow" in the first byte, top two bits.
344 * The low-order nybble of the length is in the bottom 4 bits
345 */
346 PkgLenFirstByte = (UINT8)
347 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
348 (PkgLen.LenBytes[0] & 0x0F));
349
350 CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
351
352 /*
353 * Shift the length over by the 4 bits we just stuffed
354 * in the first byte
355 */
356 PkgLen.Len >>= 4;
357
358 /*
359 * Now we can write the remaining bytes -
360 * either 1, 2, or 3 bytes
361 */
362 for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++)
363 {
364 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1);
365 }
366 }
367 }
368
369 switch (Aml.Opcode)
370 {
371 case AML_BYTE_OP:
372
373 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1);
374 break;
375
376 case AML_WORD_OP:
377
378 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2);
379 break;
380
381 case AML_DWORD_OP:
382
383 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4);
384 break;
385
386 case AML_QWORD_OP:
387
388 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8);
389 break;
390
391 case AML_STRING_OP:
392
393 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
394 break;
395
396 default:
397
398 /* All data opcodes must appear above */
399
400 break;
401 }
402 }
403
404
405 /*******************************************************************************
406 *
407 * FUNCTION: CgWriteTableHeader
408 *
409 * PARAMETERS: Op - The DEFINITIONBLOCK node
410 *
411 * RETURN: None
412 *
413 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK
414 *
415 * NOTE: Input strings should be validated before this function is invoked.
416 *
417 ******************************************************************************/
418
419 static void
420 CgWriteTableHeader (
421 ACPI_PARSE_OBJECT *Op)
422 {
423 ACPI_PARSE_OBJECT *Child;
424 UINT32 CommentLength;
425 ACPI_COMMENT_NODE *Current;
426
427
428 memset (&AslGbl_TableHeader, 0, sizeof (ACPI_TABLE_HEADER));
429
430 /* AML filename */
431
432 Child = Op->Asl.Child;
433
434 /* Signature */
435
436 Child = Child->Asl.Next;
437
438 /*
439 * For ASL-/ASL+ converter: replace the table signature with
440 * "XXXX" and save the original table signature. This results in an AML
441 * file with the signature "XXXX". The converter should remove this AML
442 * file. In the event where this AML file does not get deleted, the
443 * "XXXX" table signature prevents this AML file from running on the AML
444 * interpreter.
445 */
446 if (AcpiGbl_CaptureComments)
447 {
448 ACPI_COPY_NAMESEG (AcpiGbl_TableSig, Child->Asl.Value.String);
449 Child->Asl.Value.String = ACPI_SIG_XXXX;
450 }
451
452 ACPI_COPY_NAMESEG (AslGbl_TableHeader.Signature, Child->Asl.Value.String);
453
454 /* Revision */
455
456 Child = Child->Asl.Next;
457 AslGbl_TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
458
459 /* Command-line Revision override */
460
461 if (AslGbl_RevisionOverride)
462 {
463 AslGbl_TableHeader.Revision = AslGbl_RevisionOverride;
464 }
465
466 /* OEMID */
467
468 Child = Child->Asl.Next;
469 memcpy (AslGbl_TableHeader.OemId, Child->Asl.Value.String,
470 strlen (Child->Asl.Value.String));
471
472 /* OEM TableID */
473
474 Child = Child->Asl.Next;
475 memcpy (AslGbl_TableHeader.OemTableId, Child->Asl.Value.String,
476 strlen (Child->Asl.Value.String));
477
478 /* OEM Revision */
479
480 Child = Child->Asl.Next;
481 AslGbl_TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
482
483 /* Compiler ID */
484
485 ACPI_COPY_NAMESEG (AslGbl_TableHeader.AslCompilerId, ASL_CREATOR_ID);
486
487 /* Compiler version */
488
489 AslGbl_TableHeader.AslCompilerRevision = ACPI_CA_VERSION;
490
491 /* Table length. Checksum zero for now, will rewrite later */
492
493 AslGbl_TableHeader.Length = sizeof (ACPI_TABLE_HEADER) +
494 Op->Asl.AmlSubtreeLength;
495
496 /* Calculate the comment lengths for this definition block parseOp */
497
498 if (AcpiGbl_CaptureComments)
499 {
500 CvDbgPrint ("Calculating comment lengths for %s in write header\n",
501 Op->Asl.ParseOpName);
502
503 /*
504 * Take the filename without extensions, add 3 for the new extension
505 * and another 3 for the a908 bytecode and null terminator.
506 */
507 AslGbl_TableHeader.Length += strrchr (AslGbl_ParseTreeRoot->Asl.Filename, '.')
508 - AslGbl_ParseTreeRoot->Asl.Filename + 1 + 3 + 3;
509
510 Op->Asl.AmlSubtreeLength +=
511 strlen (AslGbl_ParseTreeRoot->Asl.Filename) + 3;
512
513 CvDbgPrint (" Length: %u\n",
514 (UINT32) strlen (AslGbl_ParseTreeRoot->Asl.Filename) + 3);
515
516 if (Op->Asl.CommentList)
517 {
518 Current = Op->Asl.CommentList;
519 while (Current)
520 {
521 CommentLength = strlen (Current->Comment)+3;
522 CvDbgPrint ("Length of standard comment): %d\n", CommentLength);
523 CvDbgPrint (" Comment string: %s\n\n", Current->Comment);
524 AslGbl_TableHeader.Length += CommentLength;
525 Op->Asl.AmlSubtreeLength += CommentLength;
526 Current = Current->Next;
527 CvDbgPrint (" Length: %u\n", CommentLength);
528 }
529 }
530 if (Op->Asl.CloseBraceComment)
531 {
532 CommentLength = strlen (Op->Asl.CloseBraceComment)+3;
533 CvDbgPrint ("Length of inline comment +3: %d\n", CommentLength);
534 CvDbgPrint (" Comment string: %s\n\n", Op->Asl.CloseBraceComment);
535 AslGbl_TableHeader.Length += CommentLength;
536 Op->Asl.AmlSubtreeLength += CommentLength;
537 CvDbgPrint (" Length: %u\n", CommentLength);
538 }
539 }
540
541 AslGbl_TableHeader.Checksum = 0;
542 Op->Asl.FinalAmlOffset = ftell (AslGbl_Files[ASL_FILE_AML_OUTPUT].Handle);
543
544 /* Write entire header and clear the table header global */
545
546 CgLocalWriteAmlData (Op, &AslGbl_TableHeader, sizeof (ACPI_TABLE_HEADER));
547 memset (&AslGbl_TableHeader, 0, sizeof (ACPI_TABLE_HEADER));
548 }
549
550
551 /*******************************************************************************
552 *
553 * FUNCTION: CgUpdateHeader
554 *
555 * PARAMETERS: Op - Op for the Definition Block
556 *
557 * RETURN: None.
558 *
559 * DESCRIPTION: Complete the ACPI table by calculating the checksum and
560 * re-writing the header for the input definition block
561 *
562 ******************************************************************************/
563
564 static void
565 CgUpdateHeader (
566 ACPI_PARSE_OBJECT *Op)
567 {
568 signed char Sum;
569 UINT32 i;
570 UINT32 Length;
571 UINT8 FileByte;
572 UINT8 Checksum;
573
574
575 /* Calculate the checksum over the entire definition block */
576
577 Sum = 0;
578 Length = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength;
579 FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset);
580
581 for (i = 0; i < Length; i++)
582 {
583 if (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) != AE_OK)
584 {
585 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, NULL,
586 "Table length is greater than size of the input file");
587 return;
588 }
589
590 Sum = (signed char) (Sum + FileByte);
591 }
592
593 Checksum = (UINT8) (0 - Sum);
594
595 /* Re-write the checksum byte */
596
597 FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset +
598 ACPI_OFFSET (ACPI_TABLE_HEADER, Checksum));
599
600 FlWriteFile (ASL_FILE_AML_OUTPUT, &Checksum, 1);
601
602 /*
603 * Seek to the end of the file. This is done to support multiple file
604 * compilation. Doing this simplifies other parts of the codebase because
605 * it eliminates the need to seek for a different starting place.
606 */
607 FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset + Length);
608 }
609
610
611 /*******************************************************************************
612 *
613 * FUNCTION: CgWriteNode
614 *
615 * PARAMETERS: Op - Parse node to write.
616 *
617 * RETURN: None.
618 *
619 * DESCRIPTION: Write the AML that corresponds to a parse node.
620 *
621 ******************************************************************************/
622
623 static void
624 CgWriteNode (
625 ACPI_PARSE_OBJECT *Op)
626 {
627 ASL_RESOURCE_NODE *Rnode;
628
629
630 /* Write all comments here. */
631
632 if (AcpiGbl_CaptureComments)
633 {
634 CgWriteAmlComment(Op);
635 }
636
637 /* Always check for DEFAULT_ARG and other "Noop" nodes */
638 /* TBD: this may not be the best place for this check */
639
640 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) ||
641 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) ||
642 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
643 {
644 return;
645 }
646
647 Op->Asl.FinalAmlLength = 0;
648
649 switch (Op->Asl.AmlOpcode)
650 {
651 case AML_RAW_DATA_BYTE:
652 case AML_RAW_DATA_WORD:
653 case AML_RAW_DATA_DWORD:
654 case AML_RAW_DATA_QWORD:
655
656 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
657 return;
658
659
660 case AML_RAW_DATA_BUFFER:
661
662 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
663 return;
664
665
666 case AML_RAW_DATA_CHAIN:
667
668 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
669 while (Rnode)
670 {
671 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
672 Rnode = Rnode->Next;
673 }
674 return;
675
676 default:
677
678 /* Internal data opcodes must all appear above */
679
680 break;
681 }
682
683 switch (Op->Asl.ParseOpcode)
684 {
685 case PARSEOP_DEFAULT_ARG:
686
687 break;
688
689 case PARSEOP_DEFINITION_BLOCK:
690
691 CgWriteTableHeader (Op);
692 if (AcpiGbl_CaptureComments)
693 {
694 CgWriteAmlDefBlockComment (Op);
695 }
696 break;
697
698 case PARSEOP_NAMESEG:
699 case PARSEOP_NAMESTRING:
700 case PARSEOP_METHODCALL:
701
702 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
703 break;
704
705 default:
706
707 CgWriteAmlOpcode (Op);
708 break;
709 }
710 }
711