Sync ACPICA with Intel's version 20170119.
[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 - 2017, 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     /* Generate the AML output file */
101
102     FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0);
103     Gbl_SourceLine = 0;
104     Gbl_NextError = Gbl_ErrorLog;
105
106     TrWalkParseTree (Gbl_ParseTreeRoot, ASL_WALK_VISIT_DOWNWARD,
107         CgAmlWriteWalk, NULL, NULL);
108
109     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER2);
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     /* Generate the AML for this node */
134
135     CgWriteNode (Op);
136
137     if (!Gbl_DebugFlag)
138     {
139         return (AE_OK);
140     }
141
142     /* Print header at level 0. Alignment assumes 32-bit pointers */
143
144     if (!Level)
145     {
146         DbgPrint (ASL_TREE_OUTPUT,
147             "\nFinal parse tree used for AML output:\n");
148         DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER2);
149     }
150
151     /* Dump ParseOp name and possible value */
152
153     switch (Op->Asl.ParseOpcode)
154     {
155     case PARSEOP_NAMESEG:
156     case PARSEOP_NAMESTRING:
157     case PARSEOP_METHODCALL:
158     case PARSEOP_STRING_LITERAL:
159
160         UtDumpStringOp (Op, Level);
161         break;
162
163     default:
164
165         UtDumpBasicOp (Op, Level);
166         break;
167     }
168
169     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_DEBUG2,
170         /* 1  */ (UINT32) Op->Asl.Value.Integer,
171         /* 2  */ Op->Asl.ParseOpcode,
172         /* 3  */ Op->Asl.AmlOpcode,
173         /* 4  */ Op->Asl.AmlOpcodeLength,
174         /* 5  */ Op->Asl.AmlPkgLenBytes,
175         /* 6  */ Op->Asl.AmlLength,
176         /* 7  */ Op->Asl.AmlSubtreeLength,
177         /* 8  */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0,
178         /* 9  */ Op,
179         /* 10 */ Op->Asl.Parent,
180         /* 11 */ Op->Asl.Child,
181         /* 12 */ Op->Asl.Next,
182         /* 13 */ Op->Asl.CompileFlags,
183         /* 14 */ Op->Asl.AcpiBtype,
184         /* 15 */ Op->Asl.FinalAmlLength,
185         /* 16 */ Op->Asl.Column,
186         /* 17 */ Op->Asl.LineNumber,
187         /* 18 */ Op->Asl.EndLine,
188         /* 19 */ Op->Asl.LogicalLineNumber,
189         /* 20 */ Op->Asl.EndLogicalLine);
190
191     return (AE_OK);
192 }
193
194
195 /*******************************************************************************
196  *
197  * FUNCTION:    CgLocalWriteAmlData
198  *
199  * PARAMETERS:  Op              - Current parse op
200  *              Buffer          - Buffer to write
201  *              Length          - Size of data in buffer
202  *
203  * RETURN:      None
204  *
205  * DESCRIPTION: Write a buffer of AML data to the AML output file.
206  *
207  ******************************************************************************/
208
209 static void
210 CgLocalWriteAmlData (
211     ACPI_PARSE_OBJECT       *Op,
212     void                    *Buffer,
213     UINT32                  Length)
214 {
215
216     /* Write the raw data to the AML file */
217
218     FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length);
219
220     /* Update the final AML length for this node (used for listings) */
221
222     if (Op)
223     {
224         Op->Asl.FinalAmlLength += Length;
225     }
226 }
227
228
229 /*******************************************************************************
230  *
231  * FUNCTION:    CgWriteAmlOpcode
232  *
233  * PARAMETERS:  Op            - Parse node with an AML opcode
234  *
235  * RETURN:      None.
236  *
237  * DESCRIPTION: Write the AML opcode corresponding to a parse node.
238  *
239  ******************************************************************************/
240
241 static void
242 CgWriteAmlOpcode (
243     ACPI_PARSE_OBJECT       *Op)
244 {
245     UINT8                   PkgLenFirstByte;
246     UINT32                  i;
247     union {
248         UINT16                  Opcode;
249         UINT8                   OpcodeBytes[2];
250     } Aml;
251     union {
252         UINT32                  Len;
253         UINT8                   LenBytes[4];
254     } PkgLen;
255
256
257     /* We expect some DEFAULT_ARGs, just ignore them */
258
259     if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
260     {
261         return;
262     }
263
264     switch (Op->Asl.AmlOpcode)
265     {
266     case AML_UNASSIGNED_OPCODE:
267
268         /* These opcodes should not get here */
269
270         printf ("Found a node with an unassigned AML opcode\n");
271         FlPrintFile (ASL_FILE_STDERR,
272             "Found a node with an unassigned AML opcode\n");
273         return;
274
275     case AML_INT_RESERVEDFIELD_OP:
276
277         /* Special opcodes for within a field definition */
278
279         Aml.Opcode = AML_FIELD_OFFSET_OP;
280         break;
281
282     case AML_INT_ACCESSFIELD_OP:
283
284         Aml.Opcode = AML_FIELD_ACCESS_OP;
285         break;
286
287     case AML_INT_CONNECTION_OP:
288
289         Aml.Opcode = AML_FIELD_CONNECTION_OP;
290         break;
291
292     default:
293
294         Aml.Opcode = Op->Asl.AmlOpcode;
295         break;
296     }
297
298
299     switch (Aml.Opcode)
300     {
301     case AML_PACKAGE_LENGTH:
302
303         /* Value is the length to be encoded (Used in field definitions) */
304
305         PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
306         break;
307
308     default:
309
310         /* Check for two-byte opcode */
311
312         if (Aml.Opcode > 0x00FF)
313         {
314             /* Write the high byte first */
315
316             CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
317         }
318
319         CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
320
321         /* Subtreelength doesn't include length of package length bytes */
322
323         PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
324         break;
325     }
326
327     /* Does this opcode have an associated "PackageLength" field? */
328
329     if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
330     {
331         if (Op->Asl.AmlPkgLenBytes == 1)
332         {
333             /* Simplest case -- no bytes to follow, just write the count */
334
335             CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
336         }
337         else if (Op->Asl.AmlPkgLenBytes != 0)
338         {
339             /*
340              * Encode the "bytes to follow" in the first byte, top two bits.
341              * The low-order nybble of the length is in the bottom 4 bits
342              */
343             PkgLenFirstByte = (UINT8)
344                 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
345                 (PkgLen.LenBytes[0] & 0x0F));
346
347             CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
348
349             /*
350              * Shift the length over by the 4 bits we just stuffed
351              * in the first byte
352              */
353             PkgLen.Len >>= 4;
354
355             /*
356              * Now we can write the remaining bytes -
357              * 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 = sizeof (ACPI_TABLE_HEADER) +
468         Op->Asl.AmlSubtreeLength;
469     TableHeader.Checksum = 0;
470
471     Op->Asl.FinalAmlOffset = ftell (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle);
472
473     /* Write entire header and clear the table header global */
474
475     CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
476     memset (&TableHeader, 0, sizeof (ACPI_TABLE_HEADER));
477 }
478
479
480 /*******************************************************************************
481  *
482  * FUNCTION:    CgUpdateHeader
483  *
484  * PARAMETERS:  Op                  - Op for the Definition Block
485  *
486  * RETURN:      None.
487  *
488  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
489  *              re-writing the header for the input definition block
490  *
491  ******************************************************************************/
492
493 static void
494 CgUpdateHeader (
495     ACPI_PARSE_OBJECT   *Op)
496 {
497     signed char         Sum;
498     UINT32              i;
499     UINT32              Length;
500     UINT8               FileByte;
501     UINT8               Checksum;
502
503
504     /* Calculate the checksum over the entire definition block */
505
506     Sum = 0;
507     Length = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength;
508     FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset);
509
510     for (i = 0; i < Length; i++)
511     {
512         if (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) != AE_OK)
513         {
514             printf ("EOF while reading checksum bytes\n");
515             return;
516         }
517
518         Sum = (signed char) (Sum + FileByte);
519     }
520
521     Checksum = (UINT8) (0 - Sum);
522
523     /* Re-write the the checksum byte */
524
525     FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset +
526         ACPI_OFFSET (ACPI_TABLE_HEADER, Checksum));
527
528     FlWriteFile (ASL_FILE_AML_OUTPUT, &Checksum, 1);
529 }
530
531
532 /*******************************************************************************
533  *
534  * FUNCTION:    CgCloseTable
535  *
536  * PARAMETERS:  None.
537  *
538  * RETURN:      None.
539  *
540  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
541  *              re-writing each table header. This allows support for
542  *              multiple definition blocks in a single source file.
543  *
544  ******************************************************************************/
545
546 static void
547 CgCloseTable (
548     void)
549 {
550     ACPI_PARSE_OBJECT   *Op;
551
552
553     /* Process all definition blocks */
554
555     Op = Gbl_ParseTreeRoot->Asl.Child;
556     while (Op)
557     {
558         CgUpdateHeader (Op);
559         Op = Op->Asl.Next;
560     }
561 }
562
563
564 /*******************************************************************************
565  *
566  * FUNCTION:    CgWriteNode
567  *
568  * PARAMETERS:  Op            - Parse node to write.
569  *
570  * RETURN:      None.
571  *
572  * DESCRIPTION: Write the AML that corresponds to a parse node.
573  *
574  ******************************************************************************/
575
576 static void
577 CgWriteNode (
578     ACPI_PARSE_OBJECT       *Op)
579 {
580     ASL_RESOURCE_NODE       *Rnode;
581
582
583     /* Always check for DEFAULT_ARG and other "Noop" nodes */
584     /* TBD: this may not be the best place for this check */
585
586     if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
587         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
588         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
589     {
590         return;
591     }
592
593     if ((Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) &&
594         Gbl_DoExternals == FALSE)
595     {
596         return;
597     }
598
599     Op->Asl.FinalAmlLength = 0;
600
601     switch (Op->Asl.AmlOpcode)
602     {
603     case AML_RAW_DATA_BYTE:
604     case AML_RAW_DATA_WORD:
605     case AML_RAW_DATA_DWORD:
606     case AML_RAW_DATA_QWORD:
607
608         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
609         return;
610
611
612     case AML_RAW_DATA_BUFFER:
613
614         CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
615         return;
616
617
618     case AML_RAW_DATA_CHAIN:
619
620         Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
621         while (Rnode)
622         {
623             CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
624             Rnode = Rnode->Next;
625         }
626         return;
627
628     default:
629
630         /* Internal data opcodes must all appear above */
631
632         break;
633     }
634
635     switch (Op->Asl.ParseOpcode)
636     {
637     case PARSEOP_DEFAULT_ARG:
638
639         break;
640
641     case PARSEOP_DEFINITION_BLOCK:
642
643         CgWriteTableHeader (Op);
644         break;
645
646     case PARSEOP_NAMESEG:
647     case PARSEOP_NAMESTRING:
648     case PARSEOP_METHODCALL:
649
650         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
651         break;
652
653     default:
654
655         CgWriteAmlOpcode (Op);
656         break;
657     }
658 }