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 "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #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\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\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\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 
191     /* Generate the AML for this node */
192 
193     CgWriteNode (Op);
194     return (AE_OK);
195 }
196 
197 
198 /*******************************************************************************
199  *
200  * FUNCTION:    CgLocalWriteAmlData
201  *
202  * PARAMETERS:  Op              - Current parse op
203  *              Buffer          - Buffer to write
204  *              Length          - Size of data in buffer
205  *
206  * RETURN:      None
207  *
208  * DESCRIPTION: Write a buffer of AML data to the AML output file.
209  *
210  ******************************************************************************/
211 
212 static void
213 CgLocalWriteAmlData (
214     ACPI_PARSE_OBJECT       *Op,
215     void                    *Buffer,
216     UINT32                  Length)
217 {
218 
219     /* Write the raw data to the AML file */
220 
221     FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length);
222 
223     /* Update the final AML length for this node (used for listings) */
224 
225     if (Op)
226     {
227         Op->Asl.FinalAmlLength += Length;
228     }
229 }
230 
231 
232 /*******************************************************************************
233  *
234  * FUNCTION:    CgWriteAmlOpcode
235  *
236  * PARAMETERS:  Op            - Parse node with an AML opcode
237  *
238  * RETURN:      None.
239  *
240  * DESCRIPTION: Write the AML opcode corresponding to a parse node.
241  *
242  ******************************************************************************/
243 
244 static void
245 CgWriteAmlOpcode (
246     ACPI_PARSE_OBJECT       *Op)
247 {
248     UINT8                   PkgLenFirstByte;
249     UINT32                  i;
250     union {
251         UINT16                  Opcode;
252         UINT8                   OpcodeBytes[2];
253     } Aml;
254     union {
255         UINT32                  Len;
256         UINT8                   LenBytes[4];
257     } PkgLen;
258 
259 
260     /* We expect some DEFAULT_ARGs, just ignore them */
261 
262     if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
263     {
264         return;
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, "Found a node with an unassigned AML opcode\n");
275         return;
276 
277     case AML_INT_RESERVEDFIELD_OP:
278 
279         /* Special opcodes for within a field definition */
280 
281         Aml.Opcode = AML_FIELD_OFFSET_OP;
282         break;
283 
284     case AML_INT_ACCESSFIELD_OP:
285 
286         Aml.Opcode = AML_FIELD_ACCESS_OP;
287         break;
288 
289     case AML_INT_CONNECTION_OP:
290 
291         Aml.Opcode = AML_FIELD_CONNECTION_OP;
292         break;
293 
294     default:
295 
296         Aml.Opcode = Op->Asl.AmlOpcode;
297         break;
298     }
299 
300 
301     switch (Aml.Opcode)
302     {
303     case AML_PACKAGE_LENGTH:
304 
305         /* Value is the length to be encoded (Used in field definitions) */
306 
307         PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
308         break;
309 
310     default:
311 
312         /* Check for two-byte opcode */
313 
314         if (Aml.Opcode > 0x00FF)
315         {
316             /* Write the high byte first */
317 
318             CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
319         }
320 
321         CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
322 
323         /* Subtreelength doesn't include length of package length bytes */
324 
325         PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
326         break;
327     }
328 
329     /* Does this opcode have an associated "PackageLength" field? */
330 
331     if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
332     {
333         if (Op->Asl.AmlPkgLenBytes == 1)
334         {
335             /* Simplest case -- no bytes to follow, just write the count */
336 
337             CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
338         }
339         else if (Op->Asl.AmlPkgLenBytes != 0)
340         {
341             /*
342              * Encode the "bytes to follow" in the first byte, top two bits.
343              * The low-order nybble of the length is in the bottom 4 bits
344              */
345             PkgLenFirstByte = (UINT8)
346                 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
347                 (PkgLen.LenBytes[0] & 0x0F));
348 
349             CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
350 
351             /*
352              * Shift the length over by the 4 bits we just stuffed
353              * in the first byte
354              */
355             PkgLen.Len >>= 4;
356 
357             /* Now we can write the remaining bytes - 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   = Gbl_TableLength;
468     TableHeader.Checksum = 0;
469 
470     CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
471 }
472 
473 
474 /*******************************************************************************
475  *
476  * FUNCTION:    CgCloseTable
477  *
478  * PARAMETERS:  None.
479  *
480  * RETURN:      None.
481  *
482  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
483  *              re-writing the header.
484  *
485  ******************************************************************************/
486 
487 static void
488 CgCloseTable (
489     void)
490 {
491     signed char         Sum;
492     UINT8               FileByte;
493 
494 
495     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
496     Sum = 0;
497 
498     /* Calculate the checksum over the entire file */
499 
500     while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK)
501     {
502         Sum = (signed char) (Sum + FileByte);
503     }
504 
505     /* Re-write the table header with the checksum */
506 
507     TableHeader.Checksum = (UINT8) (0 - Sum);
508 
509     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
510     CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER));
511 }
512 
513 
514 /*******************************************************************************
515  *
516  * FUNCTION:    CgWriteNode
517  *
518  * PARAMETERS:  Op            - Parse node to write.
519  *
520  * RETURN:      None.
521  *
522  * DESCRIPTION: Write the AML that corresponds to a parse node.
523  *
524  ******************************************************************************/
525 
526 static void
527 CgWriteNode (
528     ACPI_PARSE_OBJECT       *Op)
529 {
530     ASL_RESOURCE_NODE       *Rnode;
531 
532 
533     /* Always check for DEFAULT_ARG and other "Noop" nodes */
534     /* TBD: this may not be the best place for this check */
535 
536     if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
537         (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)     ||
538         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
539         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
540     {
541         return;
542     }
543 
544     Op->Asl.FinalAmlLength = 0;
545 
546     switch (Op->Asl.AmlOpcode)
547     {
548     case AML_RAW_DATA_BYTE:
549     case AML_RAW_DATA_WORD:
550     case AML_RAW_DATA_DWORD:
551     case AML_RAW_DATA_QWORD:
552 
553         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
554         return;
555 
556 
557     case AML_RAW_DATA_BUFFER:
558 
559         CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
560         return;
561 
562 
563     case AML_RAW_DATA_CHAIN:
564 
565         Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
566         while (Rnode)
567         {
568             CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
569             Rnode = Rnode->Next;
570         }
571         return;
572 
573     default:
574 
575         /* Internal data opcodes must all appear above */
576 
577         break;
578     }
579 
580     switch (Op->Asl.ParseOpcode)
581     {
582     case PARSEOP_DEFAULT_ARG:
583 
584         break;
585 
586     case PARSEOP_DEFINITIONBLOCK:
587 
588         CgWriteTableHeader (Op);
589         break;
590 
591     case PARSEOP_NAMESEG:
592     case PARSEOP_NAMESTRING:
593     case PARSEOP_METHODCALL:
594 
595         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
596         break;
597 
598     default:
599 
600         CgWriteAmlOpcode (Op);
601         break;
602     }
603 }
604