aslcodegen.c revision 281075
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
53static ACPI_STATUS
54CgAmlWriteWalk (
55    ACPI_PARSE_OBJECT       *Op,
56    UINT32                  Level,
57    void                    *Context);
58
59static void
60CgLocalWriteAmlData (
61    ACPI_PARSE_OBJECT       *Op,
62    void                    *Buffer,
63    UINT32                  Length);
64
65static void
66CgWriteAmlOpcode (
67    ACPI_PARSE_OBJECT       *Op);
68
69static void
70CgWriteTableHeader (
71    ACPI_PARSE_OBJECT       *Op);
72
73static void
74CgCloseTable (
75    void);
76
77static void
78CgWriteNode (
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
95void
96CgGenerateAmlOutput (
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
132static ACPI_STATUS
133CgAmlWriteWalk (
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
212static void
213CgLocalWriteAmlData (
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
244static void
245CgWriteAmlOpcode (
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
414static void
415CgWriteTableHeader (
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 = ASL_REVISION;
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
487static void
488CgCloseTable (
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
526static void
527CgWriteNode (
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}
604