cb3a4a5c783185a6c35d2fc50d0fd225fe155b61
[dragonfly.git] / sys / contrib / dev / acpica / source / compiler / aslcodegen.c
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#  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,
278             "Found a node with an unassigned AML opcode\n");
279         return;
280
281     case AML_INT_RESERVEDFIELD_OP:
282
283         /* Special opcodes for within a field definition */
284
285         Aml.Opcode = AML_FIELD_OFFSET_OP;
286         break;
287
288     case AML_INT_ACCESSFIELD_OP:
289
290         Aml.Opcode = AML_FIELD_ACCESS_OP;
291         break;
292
293     case AML_INT_CONNECTION_OP:
294
295         Aml.Opcode = AML_FIELD_CONNECTION_OP;
296         break;
297
298     default:
299
300         Aml.Opcode = Op->Asl.AmlOpcode;
301         break;
302     }
303
304
305     switch (Aml.Opcode)
306     {
307     case AML_PACKAGE_LENGTH:
308
309         /* Value is the length to be encoded (Used in field definitions) */
310
311         PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
312         break;
313
314     default:
315
316         /* Check for two-byte opcode */
317
318         if (Aml.Opcode > 0x00FF)
319         {
320             /* Write the high byte first */
321
322             CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
323         }
324
325         CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
326
327         /* Subtreelength doesn't include length of package length bytes */
328
329         PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
330         break;
331     }
332
333     /* Does this opcode have an associated "PackageLength" field? */
334
335     if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
336     {
337         if (Op->Asl.AmlPkgLenBytes == 1)
338         {
339             /* Simplest case -- no bytes to follow, just write the count */
340
341             CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
342         }
343         else if (Op->Asl.AmlPkgLenBytes != 0)
344         {
345             /*
346              * Encode the "bytes to follow" in the first byte, top two bits.
347              * The low-order nybble of the length is in the bottom 4 bits
348              */
349             PkgLenFirstByte = (UINT8)
350                 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
351                 (PkgLen.LenBytes[0] & 0x0F));
352
353             CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
354
355             /*
356              * Shift the length over by the 4 bits we just stuffed
357              * in the first byte
358              */
359             PkgLen.Len >>= 4;
360
361             /*
362              * Now we can write the remaining bytes -
363              * either 1, 2, or 3 bytes
364              */
365             for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++)
366             {
367                 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1);
368             }
369         }
370     }
371
372     switch (Aml.Opcode)
373     {
374     case AML_BYTE_OP:
375
376         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1);
377         break;
378
379     case AML_WORD_OP:
380
381         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2);
382        break;
383
384     case AML_DWORD_OP:
385
386         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4);
387         break;
388
389     case AML_QWORD_OP:
390
391         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8);
392         break;
393
394     case AML_STRING_OP:
395
396         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
397         break;
398
399     default:
400
401         /* All data opcodes must appear above */
402
403         break;
404     }
405 }
406
407
408 /*******************************************************************************
409  *
410  * FUNCTION:    CgWriteTableHeader
411  *
412  * PARAMETERS:  Op        - The DEFINITIONBLOCK node
413  *
414  * RETURN:      None
415  *
416  * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK
417  *
418  ******************************************************************************/
419
420 static void
421 CgWriteTableHeader (
422     ACPI_PARSE_OBJECT       *Op)
423 {
424     ACPI_PARSE_OBJECT       *Child;
425
426
427     /* AML filename */
428
429     Child = Op->Asl.Child;
430
431     /* Signature */
432
433     Child = Child->Asl.Next;
434     strncpy (TableHeader.Signature, Child->Asl.Value.String, 4);
435
436     /* Revision */
437
438     Child = Child->Asl.Next;
439     TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
440
441     /* Command-line Revision override */
442
443     if (Gbl_RevisionOverride)
444     {
445         TableHeader.Revision = Gbl_RevisionOverride;
446     }
447
448     /* OEMID */
449
450     Child = Child->Asl.Next;
451     strncpy (TableHeader.OemId, Child->Asl.Value.String, 6);
452
453     /* OEM TableID */
454
455     Child = Child->Asl.Next;
456     strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8);
457
458     /* OEM Revision */
459
460     Child = Child->Asl.Next;
461     TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
462
463     /* Compiler ID */
464
465     ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID);
466
467     /* Compiler version */
468
469     TableHeader.AslCompilerRevision = ACPI_CA_VERSION;
470
471     /* Table length. Checksum zero for now, will rewrite later */
472
473     TableHeader.Length = sizeof (ACPI_TABLE_HEADER) +
474         Op->Asl.AmlSubtreeLength;
475     TableHeader.Checksum = 0;
476
477     Op->Asl.FinalAmlOffset = ftell (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle);
478
479     /* Write entire header and clear the table header global */
480
481     CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
482     memset (&TableHeader, 0, sizeof (ACPI_TABLE_HEADER));
483 }
484
485
486 /*******************************************************************************
487  *
488  * FUNCTION:    CgUpdateHeader
489  *
490  * PARAMETERS:  Op                  - Op for the Definition Block
491  *
492  * RETURN:      None.
493  *
494  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
495  *              re-writing the header for the input definition block
496  *
497  ******************************************************************************/
498
499 static void
500 CgUpdateHeader (
501     ACPI_PARSE_OBJECT   *Op)
502 {
503     signed char         Sum;
504     UINT32              i;
505     UINT32              Length;
506     UINT8               FileByte;
507     UINT8               Checksum;
508
509
510     /* Calculate the checksum over the entire definition block */
511
512     Sum = 0;
513     Length = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength;
514     FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset);
515
516     for (i = 0; i < Length; i++)
517     {
518         if (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) != AE_OK)
519         {
520             printf ("EOF while reading checksum bytes\n");
521             return;
522         }
523
524         Sum = (signed char) (Sum + FileByte);
525     }
526
527     Checksum = (UINT8) (0 - Sum);
528
529     /* Re-write the the checksum byte */
530
531     FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset +
532         ACPI_OFFSET (ACPI_TABLE_HEADER, Checksum));
533
534     FlWriteFile (ASL_FILE_AML_OUTPUT, &Checksum, 1);
535 }
536
537
538 /*******************************************************************************
539  *
540  * FUNCTION:    CgCloseTable
541  *
542  * PARAMETERS:  None.
543  *
544  * RETURN:      None.
545  *
546  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
547  *              re-writing each table header. This allows support for
548  *              multiple definition blocks in a single source file.
549  *
550  ******************************************************************************/
551
552 static void
553 CgCloseTable (
554     void)
555 {
556     ACPI_PARSE_OBJECT   *Op;
557
558
559     /* Process all definition blocks */
560
561     Op = RootNode->Asl.Child;
562     while (Op)
563     {
564         CgUpdateHeader (Op);
565         Op = Op->Asl.Next;
566     }
567 }
568
569
570 /*******************************************************************************
571  *
572  * FUNCTION:    CgWriteNode
573  *
574  * PARAMETERS:  Op            - Parse node to write.
575  *
576  * RETURN:      None.
577  *
578  * DESCRIPTION: Write the AML that corresponds to a parse node.
579  *
580  ******************************************************************************/
581
582 static void
583 CgWriteNode (
584     ACPI_PARSE_OBJECT       *Op)
585 {
586     ASL_RESOURCE_NODE       *Rnode;
587
588
589     /* Always check for DEFAULT_ARG and other "Noop" nodes */
590     /* TBD: this may not be the best place for this check */
591
592     if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
593         (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)     ||
594         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
595         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
596     {
597         return;
598     }
599
600     Op->Asl.FinalAmlLength = 0;
601
602     switch (Op->Asl.AmlOpcode)
603     {
604     case AML_RAW_DATA_BYTE:
605     case AML_RAW_DATA_WORD:
606     case AML_RAW_DATA_DWORD:
607     case AML_RAW_DATA_QWORD:
608
609         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
610         return;
611
612
613     case AML_RAW_DATA_BUFFER:
614
615         CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
616         return;
617
618
619     case AML_RAW_DATA_CHAIN:
620
621         Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
622         while (Rnode)
623         {
624             CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
625             Rnode = Rnode->Next;
626         }
627         return;
628
629     default:
630
631         /* Internal data opcodes must all appear above */
632
633         break;
634     }
635
636     switch (Op->Asl.ParseOpcode)
637     {
638     case PARSEOP_DEFAULT_ARG:
639
640         break;
641
642     case PARSEOP_DEFINITION_BLOCK:
643
644         CgWriteTableHeader (Op);
645         break;
646
647     case PARSEOP_NAMESEG:
648     case PARSEOP_NAMESTRING:
649     case PARSEOP_METHODCALL:
650
651         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
652         break;
653
654     default:
655
656         CgWriteAmlOpcode (Op);
657         break;
658     }
659 }