xref: /freebsd/sys/contrib/dev/acpica/compiler/aslcodegen.c (revision 59e2ff550c448126b988150ce800cdf73bb5103e)
1 /******************************************************************************
2  *
3  * Module Name: aslcodegen - AML code generation
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2015, 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 
111     DbgPrint (ASL_TREE_OUTPUT,
112         "%*s Value    P_Op A_Op OpLen PByts Len  SubLen PSubLen OpPtr"
113         "    Parent   Child    Next     Flags    AcTyp    Final Col L#  EL#  LL#  ELL#\n",
114         76, " ");
115 
116     CgCloseTable ();
117 }
118 
119 
120 /*******************************************************************************
121  *
122  * FUNCTION:    CgAmlWriteWalk
123  *
124  * PARAMETERS:  ASL_WALK_CALLBACK
125  *
126  * RETURN:      Status
127  *
128  * DESCRIPTION: Parse tree walk to generate the AML code.
129  *
130  ******************************************************************************/
131 
132 static ACPI_STATUS
133 CgAmlWriteWalk (
134     ACPI_PARSE_OBJECT       *Op,
135     UINT32                  Level,
136     void                    *Context)
137 {
138 
139     /*
140      * Print header at level 0. Alignment assumes 32-bit pointers
141      */
142     if (!Level)
143     {
144         DbgPrint (ASL_TREE_OUTPUT,
145             "Final parse tree used for AML output:\n");
146         DbgPrint (ASL_TREE_OUTPUT,
147             "%*s Value    P_Op A_Op OpLen PByts Len  SubLen PSubLen OpPtr"
148             "    Parent   Child    Next     Flags    AcTyp    Final Col L#  EL#  LL#  ELL#\n",
149             76, " ");
150     }
151 
152     /* Debug output */
153 
154     DbgPrint (ASL_TREE_OUTPUT,
155         "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level);
156     UtPrintFormattedName (Op->Asl.ParseOpcode, Level);
157 
158     if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG    ||
159         Op->Asl.ParseOpcode == PARSEOP_NAMESTRING ||
160         Op->Asl.ParseOpcode == PARSEOP_METHODCALL)
161     {
162         DbgPrint (ASL_TREE_OUTPUT,
163             "%10.32s      ", Op->Asl.ExternalName);
164     }
165     else
166     {
167         DbgPrint (ASL_TREE_OUTPUT, "                ");
168     }
169 
170     DbgPrint (ASL_TREE_OUTPUT,
171     "%08X %04X %04X %01X     %04X  %04X %04X   %04X    "
172     "%08X %08X %08X %08X %08X %08X %04X  %02d  %02d   %02d   %02d   %02d\n",
173             /* 1  */ (UINT32) Op->Asl.Value.Integer,
174             /* 2  */ Op->Asl.ParseOpcode,
175             /* 3  */ Op->Asl.AmlOpcode,
176             /* 4  */ Op->Asl.AmlOpcodeLength,
177             /* 5  */ Op->Asl.AmlPkgLenBytes,
178             /* 6  */ Op->Asl.AmlLength,
179             /* 7  */ Op->Asl.AmlSubtreeLength,
180             /* 8  */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0,
181             /* 9  */ Op,
182             /* 10 */ Op->Asl.Parent,
183             /* 11 */ Op->Asl.Child,
184             /* 12 */ Op->Asl.Next,
185             /* 13 */ Op->Asl.CompileFlags,
186             /* 14 */ Op->Asl.AcpiBtype,
187             /* 15 */ Op->Asl.FinalAmlLength,
188             /* 16 */ Op->Asl.Column,
189             /* 17 */ Op->Asl.LineNumber,
190             /* 18 */ Op->Asl.EndLine,
191             /* 19 */ Op->Asl.LogicalLineNumber,
192             /* 20 */ Op->Asl.EndLogicalLine);
193 
194     /* Generate the AML for this node */
195 
196     CgWriteNode (Op);
197     return (AE_OK);
198 }
199 
200 
201 /*******************************************************************************
202  *
203  * FUNCTION:    CgLocalWriteAmlData
204  *
205  * PARAMETERS:  Op              - Current parse op
206  *              Buffer          - Buffer to write
207  *              Length          - Size of data in buffer
208  *
209  * RETURN:      None
210  *
211  * DESCRIPTION: Write a buffer of AML data to the AML output file.
212  *
213  ******************************************************************************/
214 
215 static void
216 CgLocalWriteAmlData (
217     ACPI_PARSE_OBJECT       *Op,
218     void                    *Buffer,
219     UINT32                  Length)
220 {
221 
222     /* Write the raw data to the AML file */
223 
224     FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length);
225 
226     /* Update the final AML length for this node (used for listings) */
227 
228     if (Op)
229     {
230         Op->Asl.FinalAmlLength += Length;
231     }
232 }
233 
234 
235 /*******************************************************************************
236  *
237  * FUNCTION:    CgWriteAmlOpcode
238  *
239  * PARAMETERS:  Op            - Parse node with an AML opcode
240  *
241  * RETURN:      None.
242  *
243  * DESCRIPTION: Write the AML opcode corresponding to a parse node.
244  *
245  ******************************************************************************/
246 
247 static void
248 CgWriteAmlOpcode (
249     ACPI_PARSE_OBJECT       *Op)
250 {
251     UINT8                   PkgLenFirstByte;
252     UINT32                  i;
253     union {
254         UINT16                  Opcode;
255         UINT8                   OpcodeBytes[2];
256     } Aml;
257     union {
258         UINT32                  Len;
259         UINT8                   LenBytes[4];
260     } PkgLen;
261 
262 
263     /* We expect some DEFAULT_ARGs, just ignore them */
264 
265     if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
266     {
267         return;
268     }
269 
270     switch (Op->Asl.AmlOpcode)
271     {
272     case AML_UNASSIGNED_OPCODE:
273 
274         /* These opcodes should not get here */
275 
276         printf ("Found a node with an unassigned AML opcode\n");
277         FlPrintFile (ASL_FILE_STDERR, "Found a node with an unassigned AML opcode\n");
278         return;
279 
280     case AML_INT_RESERVEDFIELD_OP:
281 
282         /* Special opcodes for within a field definition */
283 
284         Aml.Opcode = AML_FIELD_OFFSET_OP;
285         break;
286 
287     case AML_INT_ACCESSFIELD_OP:
288 
289         Aml.Opcode = AML_FIELD_ACCESS_OP;
290         break;
291 
292     case AML_INT_CONNECTION_OP:
293 
294         Aml.Opcode = AML_FIELD_CONNECTION_OP;
295         break;
296 
297     default:
298 
299         Aml.Opcode = Op->Asl.AmlOpcode;
300         break;
301     }
302 
303 
304     switch (Aml.Opcode)
305     {
306     case AML_PACKAGE_LENGTH:
307 
308         /* Value is the length to be encoded (Used in field definitions) */
309 
310         PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
311         break;
312 
313     default:
314 
315         /* Check for two-byte opcode */
316 
317         if (Aml.Opcode > 0x00FF)
318         {
319             /* Write the high byte first */
320 
321             CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
322         }
323 
324         CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
325 
326         /* Subtreelength doesn't include length of package length bytes */
327 
328         PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
329         break;
330     }
331 
332     /* Does this opcode have an associated "PackageLength" field? */
333 
334     if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
335     {
336         if (Op->Asl.AmlPkgLenBytes == 1)
337         {
338             /* Simplest case -- no bytes to follow, just write the count */
339 
340             CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
341         }
342         else if (Op->Asl.AmlPkgLenBytes != 0)
343         {
344             /*
345              * Encode the "bytes to follow" in the first byte, top two bits.
346              * The low-order nybble of the length is in the bottom 4 bits
347              */
348             PkgLenFirstByte = (UINT8)
349                 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
350                 (PkgLen.LenBytes[0] & 0x0F));
351 
352             CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
353 
354             /*
355              * Shift the length over by the 4 bits we just stuffed
356              * in the first byte
357              */
358             PkgLen.Len >>= 4;
359 
360             /* Now we can write the remaining bytes - 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  ******************************************************************************/
416 
417 static void
418 CgWriteTableHeader (
419     ACPI_PARSE_OBJECT       *Op)
420 {
421     ACPI_PARSE_OBJECT       *Child;
422 
423 
424     /* AML filename */
425 
426     Child = Op->Asl.Child;
427 
428     /* Signature */
429 
430     Child = Child->Asl.Next;
431     strncpy (TableHeader.Signature, Child->Asl.Value.String, 4);
432 
433     /* Revision */
434 
435     Child = Child->Asl.Next;
436     TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
437 
438     /* Command-line Revision override */
439 
440     if (Gbl_RevisionOverride)
441     {
442         TableHeader.Revision = Gbl_RevisionOverride;
443     }
444 
445     /* OEMID */
446 
447     Child = Child->Asl.Next;
448     strncpy (TableHeader.OemId, Child->Asl.Value.String, 6);
449 
450     /* OEM TableID */
451 
452     Child = Child->Asl.Next;
453     strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8);
454 
455     /* OEM Revision */
456 
457     Child = Child->Asl.Next;
458     TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
459 
460     /* Compiler ID */
461 
462     ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID);
463 
464     /* Compiler version */
465 
466     TableHeader.AslCompilerRevision = ACPI_CA_VERSION;
467 
468     /* Table length. Checksum zero for now, will rewrite later */
469 
470     TableHeader.Length   = Gbl_TableLength;
471     TableHeader.Checksum = 0;
472 
473     CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
474 }
475 
476 
477 /*******************************************************************************
478  *
479  * FUNCTION:    CgCloseTable
480  *
481  * PARAMETERS:  None.
482  *
483  * RETURN:      None.
484  *
485  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
486  *              re-writing the header.
487  *
488  ******************************************************************************/
489 
490 static void
491 CgCloseTable (
492     void)
493 {
494     signed char         Sum;
495     UINT8               FileByte;
496 
497 
498     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
499     Sum = 0;
500 
501     /* Calculate the checksum over the entire file */
502 
503     while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK)
504     {
505         Sum = (signed char) (Sum + FileByte);
506     }
507 
508     /* Re-write the table header with the checksum */
509 
510     TableHeader.Checksum = (UINT8) (0 - Sum);
511 
512     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
513     CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER));
514 }
515 
516 
517 /*******************************************************************************
518  *
519  * FUNCTION:    CgWriteNode
520  *
521  * PARAMETERS:  Op            - Parse node to write.
522  *
523  * RETURN:      None.
524  *
525  * DESCRIPTION: Write the AML that corresponds to a parse node.
526  *
527  ******************************************************************************/
528 
529 static void
530 CgWriteNode (
531     ACPI_PARSE_OBJECT       *Op)
532 {
533     ASL_RESOURCE_NODE       *Rnode;
534 
535 
536     /* Always check for DEFAULT_ARG and other "Noop" nodes */
537     /* TBD: this may not be the best place for this check */
538 
539     if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
540         (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)     ||
541         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
542         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
543     {
544         return;
545     }
546 
547     Op->Asl.FinalAmlLength = 0;
548 
549     switch (Op->Asl.AmlOpcode)
550     {
551     case AML_RAW_DATA_BYTE:
552     case AML_RAW_DATA_WORD:
553     case AML_RAW_DATA_DWORD:
554     case AML_RAW_DATA_QWORD:
555 
556         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
557         return;
558 
559 
560     case AML_RAW_DATA_BUFFER:
561 
562         CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
563         return;
564 
565 
566     case AML_RAW_DATA_CHAIN:
567 
568         Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
569         while (Rnode)
570         {
571             CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
572             Rnode = Rnode->Next;
573         }
574         return;
575 
576     default:
577 
578         /* Internal data opcodes must all appear above */
579 
580         break;
581     }
582 
583     switch (Op->Asl.ParseOpcode)
584     {
585     case PARSEOP_DEFAULT_ARG:
586 
587         break;
588 
589     case PARSEOP_DEFINITIONBLOCK:
590 
591         CgWriteTableHeader (Op);
592         break;
593 
594     case PARSEOP_NAMESEG:
595     case PARSEOP_NAMESTRING:
596     case PARSEOP_METHODCALL:
597 
598         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
599         break;
600 
601     default:
602 
603         CgWriteAmlOpcode (Op);
604         break;
605     }
606 }
607