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