aslcodegen.c revision 233250
1
2/******************************************************************************
3 *
4 * Module Name: aslcodegen - AML code generation
5 *
6 *****************************************************************************/
7
8/*
9 * Copyright (C) 2000 - 2012, Intel Corp.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions, and the following disclaimer,
17 *    without modification.
18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 *    substantially similar to the "NO WARRANTY" disclaimer below
20 *    ("Disclaimer") and any redistribution must be conditioned upon
21 *    including a substantially similar Disclaimer requirement for further
22 *    binary redistribution.
23 * 3. Neither the names of the above-listed copyright holders nor the names
24 *    of any contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * Alternatively, this software may be distributed under the terms of the
28 * GNU General Public License ("GPL") version 2 as published by the Free
29 * Software Foundation.
30 *
31 * NO WARRANTY
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGES.
43 */
44
45
46#include <contrib/dev/acpica/compiler/aslcompiler.h>
47#include "aslcompiler.y.h"
48#include <contrib/dev/acpica/include/amlcode.h>
49
50#define _COMPONENT          ACPI_COMPILER
51        ACPI_MODULE_NAME    ("aslcodegen")
52
53/* Local prototypes */
54
55static ACPI_STATUS
56CgAmlWriteWalk (
57    ACPI_PARSE_OBJECT       *Op,
58    UINT32                  Level,
59    void                    *Context);
60
61static void
62CgLocalWriteAmlData (
63    ACPI_PARSE_OBJECT       *Op,
64    void                    *Buffer,
65    UINT32                  Length);
66
67static void
68CgWriteAmlOpcode (
69    ACPI_PARSE_OBJECT       *Op);
70
71static void
72CgWriteTableHeader (
73    ACPI_PARSE_OBJECT       *Op);
74
75static void
76CgCloseTable (
77    void);
78
79static void
80CgWriteNode (
81    ACPI_PARSE_OBJECT       *Op);
82
83
84/*******************************************************************************
85 *
86 * FUNCTION:    CgGenerateAmlOutput
87 *
88 * PARAMETERS:  None.
89 *
90 * RETURN:      None
91 *
92 * DESCRIPTION: Generate AML code.  Currently generates the listing file
93 *              simultaneously.
94 *
95 ******************************************************************************/
96
97void
98CgGenerateAmlOutput (
99    void)
100{
101
102    DbgPrint (ASL_DEBUG_OUTPUT, "\nWriting AML\n\n");
103
104    /* Generate the AML output file */
105
106    FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0);
107    Gbl_SourceLine = 0;
108    Gbl_NextError = Gbl_ErrorLog;
109
110    TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD,
111        CgAmlWriteWalk, NULL, NULL);
112    CgCloseTable ();
113}
114
115
116/*******************************************************************************
117 *
118 * FUNCTION:    CgAmlWriteWalk
119 *
120 * PARAMETERS:  ASL_WALK_CALLBACK
121 *
122 * RETURN:      Status
123 *
124 * DESCRIPTION: Parse tree walk to generate the AML code.
125 *
126 ******************************************************************************/
127
128static ACPI_STATUS
129CgAmlWriteWalk (
130    ACPI_PARSE_OBJECT       *Op,
131    UINT32                  Level,
132    void                    *Context)
133{
134
135    /*
136     * Print header at level 0. Alignment assumes 32-bit pointers
137     */
138    if (!Level)
139    {
140        DbgPrint (ASL_TREE_OUTPUT,
141            "Final parse tree used for AML output:\n");
142        DbgPrint (ASL_TREE_OUTPUT,
143            "%*s Value    P_Op A_Op OpLen PByts Len  SubLen PSubLen OpPtr    Child    Parent   Flags    AcTyp    Final Col L\n",
144            76, " ");
145    }
146
147    /* Debug output */
148
149    DbgPrint (ASL_TREE_OUTPUT,
150        "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level);
151    UtPrintFormattedName (Op->Asl.ParseOpcode, Level);
152
153    if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG    ||
154        Op->Asl.ParseOpcode == PARSEOP_NAMESTRING ||
155        Op->Asl.ParseOpcode == PARSEOP_METHODCALL)
156    {
157        DbgPrint (ASL_TREE_OUTPUT,
158            "%10.32s      ", Op->Asl.ExternalName);
159    }
160    else
161    {
162        DbgPrint (ASL_TREE_OUTPUT, "                ");
163    }
164
165    DbgPrint (ASL_TREE_OUTPUT,
166    "%08X %04X %04X %01X     %04X  %04X %04X   %04X    %08X %08X %08X %08X %08X %04X  %02d  %02d\n",
167            /* 1  */ (UINT32) Op->Asl.Value.Integer,
168            /* 2  */ Op->Asl.ParseOpcode,
169            /* 3  */ Op->Asl.AmlOpcode,
170            /* 4  */ Op->Asl.AmlOpcodeLength,
171            /* 5  */ Op->Asl.AmlPkgLenBytes,
172            /* 6  */ Op->Asl.AmlLength,
173            /* 7  */ Op->Asl.AmlSubtreeLength,
174            /* 8  */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0,
175            /* 9  */ Op,
176            /* 10 */ Op->Asl.Child,
177            /* 11 */ Op->Asl.Parent,
178            /* 12 */ Op->Asl.CompileFlags,
179            /* 13 */ Op->Asl.AcpiBtype,
180            /* 14 */ Op->Asl.FinalAmlLength,
181            /* 15 */ Op->Asl.Column,
182            /* 16 */ Op->Asl.LineNumber);
183
184    /* Generate the AML for this node */
185
186    CgWriteNode (Op);
187    return (AE_OK);
188}
189
190
191/*******************************************************************************
192 *
193 * FUNCTION:    CgLocalWriteAmlData
194 *
195 * PARAMETERS:  Op              - Current parse op
196 *              Buffer          - Buffer to write
197 *              Length          - Size of data in buffer
198 *
199 * RETURN:      None
200 *
201 * DESCRIPTION: Write a buffer of AML data to the AML output file.
202 *
203 ******************************************************************************/
204
205static void
206CgLocalWriteAmlData (
207    ACPI_PARSE_OBJECT       *Op,
208    void                    *Buffer,
209    UINT32                  Length)
210{
211
212    /* Write the raw data to the AML file */
213
214    FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length);
215
216    /* Update the final AML length for this node (used for listings) */
217
218    if (Op)
219    {
220        Op->Asl.FinalAmlLength += Length;
221    }
222}
223
224
225/*******************************************************************************
226 *
227 * FUNCTION:    CgWriteAmlOpcode
228 *
229 * PARAMETERS:  Op            - Parse node with an AML opcode
230 *
231 * RETURN:      None.
232 *
233 * DESCRIPTION: Write the AML opcode corresponding to a parse node.
234 *
235 ******************************************************************************/
236
237static void
238CgWriteAmlOpcode (
239    ACPI_PARSE_OBJECT       *Op)
240{
241    UINT8                   PkgLenFirstByte;
242    UINT32                  i;
243    union {
244        UINT16                  Opcode;
245        UINT8                   OpcodeBytes[2];
246    } Aml;
247    union {
248        UINT32                  Len;
249        UINT8                   LenBytes[4];
250    } PkgLen;
251
252
253    /* We expect some DEFAULT_ARGs, just ignore them */
254
255    if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
256    {
257        return;
258    }
259
260    switch (Op->Asl.AmlOpcode)
261    {
262    case AML_UNASSIGNED_OPCODE:
263
264        /* These opcodes should not get here */
265
266        printf ("Found a node with an unassigned AML opcode\n");
267        FlPrintFile (ASL_FILE_STDERR, "Found a node with an unassigned AML opcode\n");
268        return;
269
270    case AML_INT_RESERVEDFIELD_OP:
271
272        /* Special opcodes for within a field definition */
273
274        Aml.Opcode = AML_FIELD_OFFSET_OP;
275        break;
276
277    case AML_INT_ACCESSFIELD_OP:
278
279        Aml.Opcode = AML_FIELD_ACCESS_OP;
280        break;
281
282    case AML_INT_CONNECTION_OP:
283
284        Aml.Opcode = AML_FIELD_CONNECTION_OP;
285        break;
286
287    default:
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        /* All data opcodes must appear above */
387        break;
388    }
389}
390
391
392/*******************************************************************************
393 *
394 * FUNCTION:    CgWriteTableHeader
395 *
396 * PARAMETERS:  Op        - The DEFINITIONBLOCK node
397 *
398 * RETURN:      None
399 *
400 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK
401 *
402 ******************************************************************************/
403
404static void
405CgWriteTableHeader (
406    ACPI_PARSE_OBJECT       *Op)
407{
408    ACPI_PARSE_OBJECT       *Child;
409
410
411    /* AML filename */
412
413    Child = Op->Asl.Child;
414
415    /* Signature */
416
417    Child = Child->Asl.Next;
418    strncpy (TableHeader.Signature, Child->Asl.Value.String, 4);
419
420    /* Revision */
421
422    Child = Child->Asl.Next;
423    TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
424
425    /* Command-line Revision override */
426
427    if (Gbl_RevisionOverride)
428    {
429        TableHeader.Revision = Gbl_RevisionOverride;
430    }
431
432    /* OEMID */
433
434    Child = Child->Asl.Next;
435    strncpy (TableHeader.OemId, Child->Asl.Value.String, 6);
436
437    /* OEM TableID */
438
439    Child = Child->Asl.Next;
440    strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8);
441
442    /* OEM Revision */
443
444    Child = Child->Asl.Next;
445    TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
446
447    /* Compiler ID */
448
449    strncpy (TableHeader.AslCompilerId, ASL_CREATOR_ID, 4);
450
451    /* Compiler version */
452
453    TableHeader.AslCompilerRevision = ASL_REVISION;
454
455    /* Table length. Checksum zero for now, will rewrite later */
456
457    TableHeader.Length   = Gbl_TableLength;
458    TableHeader.Checksum = 0;
459
460    CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
461}
462
463
464/*******************************************************************************
465 *
466 * FUNCTION:    CgCloseTable
467 *
468 * PARAMETERS:  None.
469 *
470 * RETURN:      None.
471 *
472 * DESCRIPTION: Complete the ACPI table by calculating the checksum and
473 *              re-writing the header.
474 *
475 ******************************************************************************/
476
477static void
478CgCloseTable (
479    void)
480{
481    signed char         Sum;
482    UINT8               FileByte;
483
484
485    FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
486    Sum = 0;
487
488    /* Calculate the checksum over the entire file */
489
490    while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK)
491    {
492        Sum = (signed char) (Sum + FileByte);
493    }
494
495    /* Re-write the table header with the checksum */
496
497    TableHeader.Checksum = (UINT8) (0 - Sum);
498
499    FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
500    CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER));
501}
502
503
504/*******************************************************************************
505 *
506 * FUNCTION:    CgWriteNode
507 *
508 * PARAMETERS:  Op            - Parse node to write.
509 *
510 * RETURN:      None.
511 *
512 * DESCRIPTION: Write the AML that corresponds to a parse node.
513 *
514 ******************************************************************************/
515
516static void
517CgWriteNode (
518    ACPI_PARSE_OBJECT       *Op)
519{
520    ASL_RESOURCE_NODE       *Rnode;
521
522
523    /* Always check for DEFAULT_ARG and other "Noop" nodes */
524    /* TBD: this may not be the best place for this check */
525
526    if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
527        (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)     ||
528        (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
529        (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
530    {
531        return;
532    }
533
534    Op->Asl.FinalAmlLength = 0;
535
536    switch (Op->Asl.AmlOpcode)
537    {
538    case AML_RAW_DATA_BYTE:
539    case AML_RAW_DATA_WORD:
540    case AML_RAW_DATA_DWORD:
541    case AML_RAW_DATA_QWORD:
542
543        CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
544        return;
545
546
547    case AML_RAW_DATA_BUFFER:
548
549        CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
550        return;
551
552
553    case AML_RAW_DATA_CHAIN:
554
555        Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
556        while (Rnode)
557        {
558            CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
559            Rnode = Rnode->Next;
560        }
561        return;
562
563    default:
564        /* Internal data opcodes must all appear above */
565        break;
566    }
567
568    switch (Op->Asl.ParseOpcode)
569    {
570    case PARSEOP_DEFAULT_ARG:
571
572        break;
573
574    case PARSEOP_DEFINITIONBLOCK:
575
576        CgWriteTableHeader (Op);
577        break;
578
579    case PARSEOP_NAMESEG:
580    case PARSEOP_NAMESTRING:
581    case PARSEOP_METHODCALL:
582
583        CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
584        break;
585
586    default:
587
588        CgWriteAmlOpcode (Op);
589        break;
590    }
591}
592
593
594