xref: /freebsd/sys/contrib/dev/acpica/compiler/aslcodegen.c (revision 38d120bc13ac1de5b739b67b87016b9122149374)
1 /******************************************************************************
2  *
3  * Module Name: aslcodegen - AML code generation
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2014, 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     DbgPrint (ASL_DEBUG_OUTPUT, "\nWriting AML\n\n");
101 
102     /* Generate the AML output file */
103 
104     FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0);
105     Gbl_SourceLine = 0;
106     Gbl_NextError = Gbl_ErrorLog;
107 
108     TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD,
109         CgAmlWriteWalk, NULL, NULL);
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     /*
134      * Print header at level 0. Alignment assumes 32-bit pointers
135      */
136     if (!Level)
137     {
138         DbgPrint (ASL_TREE_OUTPUT,
139             "Final parse tree used for AML output:\n");
140         DbgPrint (ASL_TREE_OUTPUT,
141             "%*s Value    P_Op A_Op OpLen PByts Len  SubLen PSubLen OpPtr    Child    Parent   Flags    AcTyp    Final Col L\n",
142             76, " ");
143     }
144 
145     /* Debug output */
146 
147     DbgPrint (ASL_TREE_OUTPUT,
148         "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level);
149     UtPrintFormattedName (Op->Asl.ParseOpcode, Level);
150 
151     if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG    ||
152         Op->Asl.ParseOpcode == PARSEOP_NAMESTRING ||
153         Op->Asl.ParseOpcode == PARSEOP_METHODCALL)
154     {
155         DbgPrint (ASL_TREE_OUTPUT,
156             "%10.32s      ", Op->Asl.ExternalName);
157     }
158     else
159     {
160         DbgPrint (ASL_TREE_OUTPUT, "                ");
161     }
162 
163     DbgPrint (ASL_TREE_OUTPUT,
164     "%08X %04X %04X %01X     %04X  %04X %04X   %04X    %08X %08X %08X %08X %08X %04X  %02d  %02d\n",
165             /* 1  */ (UINT32) Op->Asl.Value.Integer,
166             /* 2  */ Op->Asl.ParseOpcode,
167             /* 3  */ Op->Asl.AmlOpcode,
168             /* 4  */ Op->Asl.AmlOpcodeLength,
169             /* 5  */ Op->Asl.AmlPkgLenBytes,
170             /* 6  */ Op->Asl.AmlLength,
171             /* 7  */ Op->Asl.AmlSubtreeLength,
172             /* 8  */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0,
173             /* 9  */ Op,
174             /* 10 */ Op->Asl.Child,
175             /* 11 */ Op->Asl.Parent,
176             /* 12 */ Op->Asl.CompileFlags,
177             /* 13 */ Op->Asl.AcpiBtype,
178             /* 14 */ Op->Asl.FinalAmlLength,
179             /* 15 */ Op->Asl.Column,
180             /* 16 */ Op->Asl.LineNumber);
181 
182     /* Generate the AML for this node */
183 
184     CgWriteNode (Op);
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 static 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     switch (Op->Asl.AmlOpcode)
259     {
260     case AML_UNASSIGNED_OPCODE:
261 
262         /* These opcodes should not get here */
263 
264         printf ("Found a node with an unassigned AML opcode\n");
265         FlPrintFile (ASL_FILE_STDERR, "Found a node with an unassigned AML opcode\n");
266         return;
267 
268     case AML_INT_RESERVEDFIELD_OP:
269 
270         /* Special opcodes for within a field definition */
271 
272         Aml.Opcode = AML_FIELD_OFFSET_OP;
273         break;
274 
275     case AML_INT_ACCESSFIELD_OP:
276 
277         Aml.Opcode = AML_FIELD_ACCESS_OP;
278         break;
279 
280     case AML_INT_CONNECTION_OP:
281 
282         Aml.Opcode = AML_FIELD_CONNECTION_OP;
283         break;
284 
285     default:
286 
287         Aml.Opcode = Op->Asl.AmlOpcode;
288         break;
289     }
290 
291 
292     switch (Aml.Opcode)
293     {
294     case AML_PACKAGE_LENGTH:
295 
296         /* Value is the length to be encoded (Used in field definitions) */
297 
298         PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
299         break;
300 
301     default:
302 
303         /* Check for two-byte opcode */
304 
305         if (Aml.Opcode > 0x00FF)
306         {
307             /* Write the high byte first */
308 
309             CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
310         }
311 
312         CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
313 
314         /* Subtreelength doesn't include length of package length bytes */
315 
316         PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
317         break;
318     }
319 
320     /* Does this opcode have an associated "PackageLength" field? */
321 
322     if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
323     {
324         if (Op->Asl.AmlPkgLenBytes == 1)
325         {
326             /* Simplest case -- no bytes to follow, just write the count */
327 
328             CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
329         }
330         else if (Op->Asl.AmlPkgLenBytes != 0)
331         {
332             /*
333              * Encode the "bytes to follow" in the first byte, top two bits.
334              * The low-order nybble of the length is in the bottom 4 bits
335              */
336             PkgLenFirstByte = (UINT8)
337                 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
338                 (PkgLen.LenBytes[0] & 0x0F));
339 
340             CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
341 
342             /*
343              * Shift the length over by the 4 bits we just stuffed
344              * in the first byte
345              */
346             PkgLen.Len >>= 4;
347 
348             /* Now we can write the remaining bytes - either 1, 2, or 3 bytes */
349 
350             for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++)
351             {
352                 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1);
353             }
354         }
355     }
356 
357     switch (Aml.Opcode)
358     {
359     case AML_BYTE_OP:
360 
361         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1);
362         break;
363 
364     case AML_WORD_OP:
365 
366         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2);
367        break;
368 
369     case AML_DWORD_OP:
370 
371         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4);
372         break;
373 
374     case AML_QWORD_OP:
375 
376         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8);
377         break;
378 
379     case AML_STRING_OP:
380 
381         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
382         break;
383 
384     default:
385 
386         /* All data opcodes must appear above */
387 
388         break;
389     }
390 }
391 
392 
393 /*******************************************************************************
394  *
395  * FUNCTION:    CgWriteTableHeader
396  *
397  * PARAMETERS:  Op        - The DEFINITIONBLOCK node
398  *
399  * RETURN:      None
400  *
401  * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK
402  *
403  ******************************************************************************/
404 
405 static void
406 CgWriteTableHeader (
407     ACPI_PARSE_OBJECT       *Op)
408 {
409     ACPI_PARSE_OBJECT       *Child;
410 
411 
412     /* AML filename */
413 
414     Child = Op->Asl.Child;
415 
416     /* Signature */
417 
418     Child = Child->Asl.Next;
419     strncpy (TableHeader.Signature, Child->Asl.Value.String, 4);
420 
421     /* Revision */
422 
423     Child = Child->Asl.Next;
424     TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
425 
426     /* Command-line Revision override */
427 
428     if (Gbl_RevisionOverride)
429     {
430         TableHeader.Revision = Gbl_RevisionOverride;
431     }
432 
433     /* OEMID */
434 
435     Child = Child->Asl.Next;
436     strncpy (TableHeader.OemId, Child->Asl.Value.String, 6);
437 
438     /* OEM TableID */
439 
440     Child = Child->Asl.Next;
441     strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8);
442 
443     /* OEM Revision */
444 
445     Child = Child->Asl.Next;
446     TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
447 
448     /* Compiler ID */
449 
450     ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID);
451 
452     /* Compiler version */
453 
454     TableHeader.AslCompilerRevision = ASL_REVISION;
455 
456     /* Table length. Checksum zero for now, will rewrite later */
457 
458     TableHeader.Length   = Gbl_TableLength;
459     TableHeader.Checksum = 0;
460 
461     CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
462 }
463 
464 
465 /*******************************************************************************
466  *
467  * FUNCTION:    CgCloseTable
468  *
469  * PARAMETERS:  None.
470  *
471  * RETURN:      None.
472  *
473  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
474  *              re-writing the header.
475  *
476  ******************************************************************************/
477 
478 static void
479 CgCloseTable (
480     void)
481 {
482     signed char         Sum;
483     UINT8               FileByte;
484 
485 
486     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
487     Sum = 0;
488 
489     /* Calculate the checksum over the entire file */
490 
491     while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK)
492     {
493         Sum = (signed char) (Sum + FileByte);
494     }
495 
496     /* Re-write the table header with the checksum */
497 
498     TableHeader.Checksum = (UINT8) (0 - Sum);
499 
500     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
501     CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER));
502 }
503 
504 
505 /*******************************************************************************
506  *
507  * FUNCTION:    CgWriteNode
508  *
509  * PARAMETERS:  Op            - Parse node to write.
510  *
511  * RETURN:      None.
512  *
513  * DESCRIPTION: Write the AML that corresponds to a parse node.
514  *
515  ******************************************************************************/
516 
517 static void
518 CgWriteNode (
519     ACPI_PARSE_OBJECT       *Op)
520 {
521     ASL_RESOURCE_NODE       *Rnode;
522 
523 
524     /* Always check for DEFAULT_ARG and other "Noop" nodes */
525     /* TBD: this may not be the best place for this check */
526 
527     if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
528         (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)     ||
529         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
530         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
531     {
532         return;
533     }
534 
535     Op->Asl.FinalAmlLength = 0;
536 
537     switch (Op->Asl.AmlOpcode)
538     {
539     case AML_RAW_DATA_BYTE:
540     case AML_RAW_DATA_WORD:
541     case AML_RAW_DATA_DWORD:
542     case AML_RAW_DATA_QWORD:
543 
544         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
545         return;
546 
547 
548     case AML_RAW_DATA_BUFFER:
549 
550         CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
551         return;
552 
553 
554     case AML_RAW_DATA_CHAIN:
555 
556         Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
557         while (Rnode)
558         {
559             CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
560             Rnode = Rnode->Next;
561         }
562         return;
563 
564     default:
565 
566         /* Internal data opcodes must all appear above */
567 
568         break;
569     }
570 
571     switch (Op->Asl.ParseOpcode)
572     {
573     case PARSEOP_DEFAULT_ARG:
574 
575         break;
576 
577     case PARSEOP_DEFINITIONBLOCK:
578 
579         CgWriteTableHeader (Op);
580         break;
581 
582     case PARSEOP_NAMESEG:
583     case PARSEOP_NAMESTRING:
584     case PARSEOP_METHODCALL:
585 
586         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
587         break;
588 
589     default:
590 
591         CgWriteAmlOpcode (Op);
592         break;
593     }
594 }
595