xref: /freebsd/sys/contrib/dev/acpica/compiler/aslcodegen.c (revision 55620f43deef5c0eb5b4b0f675de18b30c8d1c2d)
1 /******************************************************************************
2  *
3  * Module Name: aslcodegen - AML code generation
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 MERCHANTIBILITY 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 <contrib/dev/acpica/compiler/aslcompiler.h>
45 #include "aslcompiler.y.h"
46 #include <contrib/dev/acpica/include/amlcode.h>
47 
48 #define _COMPONENT          ACPI_COMPILER
49         ACPI_MODULE_NAME    ("aslcodegen")
50 
51 /* Local prototypes */
52 
53 static ACPI_STATUS
54 CgAmlWriteWalk (
55     ACPI_PARSE_OBJECT       *Op,
56     UINT32                  Level,
57     void                    *Context);
58 
59 static void
60 CgLocalWriteAmlData (
61     ACPI_PARSE_OBJECT       *Op,
62     void                    *Buffer,
63     UINT32                  Length);
64 
65 static void
66 CgWriteAmlOpcode (
67     ACPI_PARSE_OBJECT       *Op);
68 
69 static void
70 CgWriteTableHeader (
71     ACPI_PARSE_OBJECT       *Op);
72 
73 static void
74 CgCloseTable (
75     void);
76 
77 static void
78 CgWriteNode (
79     ACPI_PARSE_OBJECT       *Op);
80 
81 
82 /*******************************************************************************
83  *
84  * FUNCTION:    CgGenerateAmlOutput
85  *
86  * PARAMETERS:  None.
87  *
88  * RETURN:      None
89  *
90  * DESCRIPTION: Generate AML code. Currently generates the listing file
91  *              simultaneously.
92  *
93  ******************************************************************************/
94 
95 void
96 CgGenerateAmlOutput (
97     void)
98 {
99 
100     /* Generate the AML output file */
101 
102     FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0);
103     Gbl_SourceLine = 0;
104     Gbl_NextError = Gbl_ErrorLog;
105 
106     TrWalkParseTree (Gbl_ParseTreeRoot, ASL_WALK_VISIT_DOWNWARD,
107         CgAmlWriteWalk, NULL, NULL);
108 
109     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER2);
110     CgCloseTable ();
111 }
112 
113 
114 /*******************************************************************************
115  *
116  * FUNCTION:    CgAmlWriteWalk
117  *
118  * PARAMETERS:  ASL_WALK_CALLBACK
119  *
120  * RETURN:      Status
121  *
122  * DESCRIPTION: Parse tree walk to generate the AML code.
123  *
124  ******************************************************************************/
125 
126 static ACPI_STATUS
127 CgAmlWriteWalk (
128     ACPI_PARSE_OBJECT       *Op,
129     UINT32                  Level,
130     void                    *Context)
131 {
132 
133     /* Generate the AML for this node */
134 
135     CgWriteNode (Op);
136 
137     if (!Gbl_DebugFlag)
138     {
139         return (AE_OK);
140     }
141 
142     /* Print header at level 0. Alignment assumes 32-bit pointers */
143 
144     if (!Level)
145     {
146         DbgPrint (ASL_TREE_OUTPUT,
147             "\nFinal parse tree used for AML output:\n");
148         DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER2);
149     }
150 
151     /* Dump ParseOp name and possible value */
152 
153     switch (Op->Asl.ParseOpcode)
154     {
155     case PARSEOP_NAMESEG:
156     case PARSEOP_NAMESTRING:
157     case PARSEOP_METHODCALL:
158     case PARSEOP_STRING_LITERAL:
159 
160         UtDumpStringOp (Op, Level);
161         break;
162 
163     default:
164 
165         UtDumpBasicOp (Op, Level);
166         break;
167     }
168 
169     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_DEBUG2,
170         /* 1  */ (UINT32) Op->Asl.Value.Integer,
171         /* 2  */ Op->Asl.ParseOpcode,
172         /* 3  */ Op->Asl.AmlOpcode,
173         /* 4  */ Op->Asl.AmlOpcodeLength,
174         /* 5  */ Op->Asl.AmlPkgLenBytes,
175         /* 6  */ Op->Asl.AmlLength,
176         /* 7  */ Op->Asl.AmlSubtreeLength,
177         /* 8  */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0,
178         /* 9  */ Op,
179         /* 10 */ Op->Asl.Parent,
180         /* 11 */ Op->Asl.Child,
181         /* 12 */ Op->Asl.Next,
182         /* 13 */ Op->Asl.CompileFlags,
183         /* 14 */ Op->Asl.AcpiBtype,
184         /* 15 */ Op->Asl.FinalAmlLength,
185         /* 16 */ Op->Asl.Column,
186         /* 17 */ Op->Asl.LineNumber,
187         /* 18 */ Op->Asl.EndLine,
188         /* 19 */ Op->Asl.LogicalLineNumber,
189         /* 20 */ Op->Asl.EndLogicalLine);
190 
191     return (AE_OK);
192 }
193 
194 
195 /*******************************************************************************
196  *
197  * FUNCTION:    CgLocalWriteAmlData
198  *
199  * PARAMETERS:  Op              - Current parse op
200  *              Buffer          - Buffer to write
201  *              Length          - Size of data in buffer
202  *
203  * RETURN:      None
204  *
205  * DESCRIPTION: Write a buffer of AML data to the AML output file.
206  *
207  ******************************************************************************/
208 
209 static void
210 CgLocalWriteAmlData (
211     ACPI_PARSE_OBJECT       *Op,
212     void                    *Buffer,
213     UINT32                  Length)
214 {
215 
216     /* Write the raw data to the AML file */
217 
218     FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length);
219 
220     /* Update the final AML length for this node (used for listings) */
221 
222     if (Op)
223     {
224         Op->Asl.FinalAmlLength += Length;
225     }
226 }
227 
228 
229 /*******************************************************************************
230  *
231  * FUNCTION:    CgWriteAmlOpcode
232  *
233  * PARAMETERS:  Op            - Parse node with an AML opcode
234  *
235  * RETURN:      None.
236  *
237  * DESCRIPTION: Write the AML opcode corresponding to a parse node.
238  *
239  ******************************************************************************/
240 
241 static void
242 CgWriteAmlOpcode (
243     ACPI_PARSE_OBJECT       *Op)
244 {
245     UINT8                   PkgLenFirstByte;
246     UINT32                  i;
247     union {
248         UINT16                  Opcode;
249         UINT8                   OpcodeBytes[2];
250     } Aml;
251     union {
252         UINT32                  Len;
253         UINT8                   LenBytes[4];
254     } PkgLen;
255 
256 
257     /* We expect some DEFAULT_ARGs, just ignore them */
258 
259     if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
260     {
261         return;
262     }
263 
264     switch (Op->Asl.AmlOpcode)
265     {
266     case AML_UNASSIGNED_OPCODE:
267 
268         /* These opcodes should not get here */
269 
270         printf ("Found a node with an unassigned AML opcode\n");
271         FlPrintFile (ASL_FILE_STDERR,
272             "Found a node with an unassigned AML opcode\n");
273         return;
274 
275     case AML_INT_RESERVEDFIELD_OP:
276 
277         /* Special opcodes for within a field definition */
278 
279         Aml.Opcode = AML_FIELD_OFFSET_OP;
280         break;
281 
282     case AML_INT_ACCESSFIELD_OP:
283 
284         Aml.Opcode = AML_FIELD_ACCESS_OP;
285         break;
286 
287     case AML_INT_CONNECTION_OP:
288 
289         Aml.Opcode = AML_FIELD_CONNECTION_OP;
290         break;
291 
292     default:
293 
294         Aml.Opcode = Op->Asl.AmlOpcode;
295         break;
296     }
297 
298 
299     switch (Aml.Opcode)
300     {
301     case AML_PACKAGE_LENGTH:
302 
303         /* Value is the length to be encoded (Used in field definitions) */
304 
305         PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
306         break;
307 
308     default:
309 
310         /* Check for two-byte opcode */
311 
312         if (Aml.Opcode > 0x00FF)
313         {
314             /* Write the high byte first */
315 
316             CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
317         }
318 
319         CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
320 
321         /* Subtreelength doesn't include length of package length bytes */
322 
323         PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
324         break;
325     }
326 
327     /* Does this opcode have an associated "PackageLength" field? */
328 
329     if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
330     {
331         if (Op->Asl.AmlPkgLenBytes == 1)
332         {
333             /* Simplest case -- no bytes to follow, just write the count */
334 
335             CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
336         }
337         else if (Op->Asl.AmlPkgLenBytes != 0)
338         {
339             /*
340              * Encode the "bytes to follow" in the first byte, top two bits.
341              * The low-order nybble of the length is in the bottom 4 bits
342              */
343             PkgLenFirstByte = (UINT8)
344                 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
345                 (PkgLen.LenBytes[0] & 0x0F));
346 
347             CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
348 
349             /*
350              * Shift the length over by the 4 bits we just stuffed
351              * in the first byte
352              */
353             PkgLen.Len >>= 4;
354 
355             /*
356              * Now we can write the remaining bytes -
357              * either 1, 2, or 3 bytes
358              */
359             for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++)
360             {
361                 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1);
362             }
363         }
364     }
365 
366     switch (Aml.Opcode)
367     {
368     case AML_BYTE_OP:
369 
370         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1);
371         break;
372 
373     case AML_WORD_OP:
374 
375         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2);
376        break;
377 
378     case AML_DWORD_OP:
379 
380         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4);
381         break;
382 
383     case AML_QWORD_OP:
384 
385         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8);
386         break;
387 
388     case AML_STRING_OP:
389 
390         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
391         break;
392 
393     default:
394 
395         /* All data opcodes must appear above */
396 
397         break;
398     }
399 }
400 
401 
402 /*******************************************************************************
403  *
404  * FUNCTION:    CgWriteTableHeader
405  *
406  * PARAMETERS:  Op        - The DEFINITIONBLOCK node
407  *
408  * RETURN:      None
409  *
410  * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK
411  *
412  ******************************************************************************/
413 
414 static void
415 CgWriteTableHeader (
416     ACPI_PARSE_OBJECT       *Op)
417 {
418     ACPI_PARSE_OBJECT       *Child;
419 
420 
421     /* AML filename */
422 
423     Child = Op->Asl.Child;
424 
425     /* Signature */
426 
427     Child = Child->Asl.Next;
428     strncpy (TableHeader.Signature, Child->Asl.Value.String, 4);
429 
430     /* Revision */
431 
432     Child = Child->Asl.Next;
433     TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
434 
435     /* Command-line Revision override */
436 
437     if (Gbl_RevisionOverride)
438     {
439         TableHeader.Revision = Gbl_RevisionOverride;
440     }
441 
442     /* OEMID */
443 
444     Child = Child->Asl.Next;
445     strncpy (TableHeader.OemId, Child->Asl.Value.String, 6);
446 
447     /* OEM TableID */
448 
449     Child = Child->Asl.Next;
450     strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8);
451 
452     /* OEM Revision */
453 
454     Child = Child->Asl.Next;
455     TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
456 
457     /* Compiler ID */
458 
459     ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID);
460 
461     /* Compiler version */
462 
463     TableHeader.AslCompilerRevision = ACPI_CA_VERSION;
464 
465     /* Table length. Checksum zero for now, will rewrite later */
466 
467     TableHeader.Length = sizeof (ACPI_TABLE_HEADER) +
468         Op->Asl.AmlSubtreeLength;
469     TableHeader.Checksum = 0;
470 
471     Op->Asl.FinalAmlOffset = ftell (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle);
472 
473     /* Write entire header and clear the table header global */
474 
475     CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
476     memset (&TableHeader, 0, sizeof (ACPI_TABLE_HEADER));
477 }
478 
479 
480 /*******************************************************************************
481  *
482  * FUNCTION:    CgUpdateHeader
483  *
484  * PARAMETERS:  Op                  - Op for the Definition Block
485  *
486  * RETURN:      None.
487  *
488  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
489  *              re-writing the header for the input definition block
490  *
491  ******************************************************************************/
492 
493 static void
494 CgUpdateHeader (
495     ACPI_PARSE_OBJECT   *Op)
496 {
497     signed char         Sum;
498     UINT32              i;
499     UINT32              Length;
500     UINT8               FileByte;
501     UINT8               Checksum;
502 
503 
504     /* Calculate the checksum over the entire definition block */
505 
506     Sum = 0;
507     Length = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength;
508     FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset);
509 
510     for (i = 0; i < Length; i++)
511     {
512         if (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) != AE_OK)
513         {
514             printf ("EOF while reading checksum bytes\n");
515             return;
516         }
517 
518         Sum = (signed char) (Sum + FileByte);
519     }
520 
521     Checksum = (UINT8) (0 - Sum);
522 
523     /* Re-write the the checksum byte */
524 
525     FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset +
526         ACPI_OFFSET (ACPI_TABLE_HEADER, Checksum));
527 
528     FlWriteFile (ASL_FILE_AML_OUTPUT, &Checksum, 1);
529 }
530 
531 
532 /*******************************************************************************
533  *
534  * FUNCTION:    CgCloseTable
535  *
536  * PARAMETERS:  None.
537  *
538  * RETURN:      None.
539  *
540  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
541  *              re-writing each table header. This allows support for
542  *              multiple definition blocks in a single source file.
543  *
544  ******************************************************************************/
545 
546 static void
547 CgCloseTable (
548     void)
549 {
550     ACPI_PARSE_OBJECT   *Op;
551 
552 
553     /* Process all definition blocks */
554 
555     Op = Gbl_ParseTreeRoot->Asl.Child;
556     while (Op)
557     {
558         CgUpdateHeader (Op);
559         Op = Op->Asl.Next;
560     }
561 }
562 
563 
564 /*******************************************************************************
565  *
566  * FUNCTION:    CgWriteNode
567  *
568  * PARAMETERS:  Op            - Parse node to write.
569  *
570  * RETURN:      None.
571  *
572  * DESCRIPTION: Write the AML that corresponds to a parse node.
573  *
574  ******************************************************************************/
575 
576 static void
577 CgWriteNode (
578     ACPI_PARSE_OBJECT       *Op)
579 {
580     ASL_RESOURCE_NODE       *Rnode;
581 
582 
583     /* Always check for DEFAULT_ARG and other "Noop" nodes */
584     /* TBD: this may not be the best place for this check */
585 
586     if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
587         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
588         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
589     {
590         return;
591     }
592 
593     if ((Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) &&
594         Gbl_DoExternals == FALSE)
595     {
596         return;
597     }
598 
599     Op->Asl.FinalAmlLength = 0;
600 
601     switch (Op->Asl.AmlOpcode)
602     {
603     case AML_RAW_DATA_BYTE:
604     case AML_RAW_DATA_WORD:
605     case AML_RAW_DATA_DWORD:
606     case AML_RAW_DATA_QWORD:
607 
608         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
609         return;
610 
611 
612     case AML_RAW_DATA_BUFFER:
613 
614         CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
615         return;
616 
617 
618     case AML_RAW_DATA_CHAIN:
619 
620         Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
621         while (Rnode)
622         {
623             CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
624             Rnode = Rnode->Next;
625         }
626         return;
627 
628     default:
629 
630         /* Internal data opcodes must all appear above */
631 
632         break;
633     }
634 
635     switch (Op->Asl.ParseOpcode)
636     {
637     case PARSEOP_DEFAULT_ARG:
638 
639         break;
640 
641     case PARSEOP_DEFINITION_BLOCK:
642 
643         CgWriteTableHeader (Op);
644         break;
645 
646     case PARSEOP_NAMESEG:
647     case PARSEOP_NAMESTRING:
648     case PARSEOP_METHODCALL:
649 
650         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
651         break;
652 
653     default:
654 
655         CgWriteAmlOpcode (Op);
656         break;
657     }
658 }
659