aslcodegen.c revision 217365
1
2/******************************************************************************
3 *
4 * Module Name: aslcodegen - AML code generation
5 *
6 *****************************************************************************/
7
8/*
9 * Copyright (C) 2000 - 2011, 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        fprintf (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 = 0x00;
275        break;
276
277    case AML_INT_ACCESSFIELD_OP:
278
279        Aml.Opcode = 0x01;
280        break;
281
282    default:
283        Aml.Opcode = Op->Asl.AmlOpcode;
284        break;
285    }
286
287
288    switch (Aml.Opcode)
289    {
290    case AML_PACKAGE_LENGTH:
291
292        /* Value is the length to be encoded (Used in field definitions) */
293
294        PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
295        break;
296
297    default:
298
299        /* Check for two-byte opcode */
300
301        if (Aml.Opcode > 0x00FF)
302        {
303            /* Write the high byte first */
304
305            CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
306        }
307
308        CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
309
310        /* Subtreelength doesn't include length of package length bytes */
311
312        PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
313        break;
314    }
315
316    /* Does this opcode have an associated "PackageLength" field? */
317
318    if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
319    {
320        if (Op->Asl.AmlPkgLenBytes == 1)
321        {
322            /* Simplest case -- no bytes to follow, just write the count */
323
324            CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
325        }
326        else if (Op->Asl.AmlPkgLenBytes != 0)
327        {
328            /*
329             * Encode the "bytes to follow" in the first byte, top two bits.
330             * The low-order nybble of the length is in the bottom 4 bits
331             */
332            PkgLenFirstByte = (UINT8)
333                (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
334                (PkgLen.LenBytes[0] & 0x0F));
335
336            CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
337
338            /*
339             * Shift the length over by the 4 bits we just stuffed
340             * in the first byte
341             */
342            PkgLen.Len >>= 4;
343
344            /* Now we can write the remaining bytes - either 1, 2, or 3 bytes */
345
346            for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++)
347            {
348                CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1);
349            }
350        }
351    }
352
353    switch (Aml.Opcode)
354    {
355    case AML_BYTE_OP:
356
357        CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1);
358        break;
359
360    case AML_WORD_OP:
361
362        CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2);
363       break;
364
365    case AML_DWORD_OP:
366
367        CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4);
368        break;
369
370    case AML_QWORD_OP:
371
372        CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8);
373        break;
374
375    case AML_STRING_OP:
376
377        CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
378        break;
379
380    default:
381        /* All data opcodes must appear above */
382        break;
383    }
384}
385
386
387/*******************************************************************************
388 *
389 * FUNCTION:    CgWriteTableHeader
390 *
391 * PARAMETERS:  Op        - The DEFINITIONBLOCK node
392 *
393 * RETURN:      None
394 *
395 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK
396 *
397 ******************************************************************************/
398
399static void
400CgWriteTableHeader (
401    ACPI_PARSE_OBJECT       *Op)
402{
403    ACPI_PARSE_OBJECT       *Child;
404
405
406    /* AML filename */
407
408    Child = Op->Asl.Child;
409
410    /* Signature */
411
412    Child = Child->Asl.Next;
413    strncpy (TableHeader.Signature, Child->Asl.Value.String, 4);
414
415    /* Revision */
416
417    Child = Child->Asl.Next;
418    TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
419
420    /* Command-line Revision override */
421
422    if (Gbl_RevisionOverride)
423    {
424        TableHeader.Revision = Gbl_RevisionOverride;
425    }
426
427    /* OEMID */
428
429    Child = Child->Asl.Next;
430    strncpy (TableHeader.OemId, Child->Asl.Value.String, 6);
431
432    /* OEM TableID */
433
434    Child = Child->Asl.Next;
435    strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8);
436
437    /* OEM Revision */
438
439    Child = Child->Asl.Next;
440    TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
441
442    /* Compiler ID */
443
444    strncpy (TableHeader.AslCompilerId, ASL_CREATOR_ID, 4);
445
446    /* Compiler version */
447
448    TableHeader.AslCompilerRevision = ASL_REVISION;
449
450    /* Table length. Checksum zero for now, will rewrite later */
451
452    TableHeader.Length   = Gbl_TableLength;
453    TableHeader.Checksum = 0;
454
455    CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
456}
457
458
459/*******************************************************************************
460 *
461 * FUNCTION:    CgCloseTable
462 *
463 * PARAMETERS:  None.
464 *
465 * RETURN:      None.
466 *
467 * DESCRIPTION: Complete the ACPI table by calculating the checksum and
468 *              re-writing the header.
469 *
470 ******************************************************************************/
471
472static void
473CgCloseTable (
474    void)
475{
476    signed char         Sum;
477    UINT8               FileByte;
478
479
480    FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
481    Sum = 0;
482
483    /* Calculate the checksum over the entire file */
484
485    while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK)
486    {
487        Sum = (signed char) (Sum + FileByte);
488    }
489
490    /* Re-write the table header with the checksum */
491
492    TableHeader.Checksum = (UINT8) (0 - Sum);
493
494    FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
495    CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER));
496}
497
498
499/*******************************************************************************
500 *
501 * FUNCTION:    CgWriteNode
502 *
503 * PARAMETERS:  Op            - Parse node to write.
504 *
505 * RETURN:      None.
506 *
507 * DESCRIPTION: Write the AML that corresponds to a parse node.
508 *
509 ******************************************************************************/
510
511static void
512CgWriteNode (
513    ACPI_PARSE_OBJECT       *Op)
514{
515    ASL_RESOURCE_NODE       *Rnode;
516
517
518    /* Always check for DEFAULT_ARG and other "Noop" nodes */
519    /* TBD: this may not be the best place for this check */
520
521    if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
522        (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)     ||
523        (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
524        (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
525    {
526        return;
527    }
528
529    Op->Asl.FinalAmlLength = 0;
530
531    switch (Op->Asl.AmlOpcode)
532    {
533    case AML_RAW_DATA_BYTE:
534    case AML_RAW_DATA_WORD:
535    case AML_RAW_DATA_DWORD:
536    case AML_RAW_DATA_QWORD:
537
538        CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
539        return;
540
541
542    case AML_RAW_DATA_BUFFER:
543
544        CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
545        return;
546
547
548    case AML_RAW_DATA_CHAIN:
549
550        Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
551        while (Rnode)
552        {
553            CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
554            Rnode = Rnode->Next;
555        }
556        return;
557
558    default:
559        /* Internal data opcodes must all appear above */
560        break;
561    }
562
563    switch (Op->Asl.ParseOpcode)
564    {
565    case PARSEOP_DEFAULT_ARG:
566
567        break;
568
569    case PARSEOP_DEFINITIONBLOCK:
570
571        CgWriteTableHeader (Op);
572        break;
573
574    case PARSEOP_NAMESEG:
575    case PARSEOP_NAMESTRING:
576    case PARSEOP_METHODCALL:
577
578        CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
579        break;
580
581    default:
582
583        CgWriteAmlOpcode (Op);
584        break;
585    }
586}
587
588
589