]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/contrib/dev/acpica/compiler/aslcodegen.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / contrib / dev / acpica / 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 <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\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 }