aslcodegen.c revision 306536
1/******************************************************************************
2 *
3 * Module Name: aslcodegen - AML code generation
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2016, 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    /* 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
126static ACPI_STATUS
127CgAmlWriteWalk (
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
209static void
210CgLocalWriteAmlData (
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
241static void
242CgWriteAmlOpcode (
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
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 = 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
493static void
494CgUpdateHeader (
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
546static void
547CgCloseTable (
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
576static void
577CgWriteNode (
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}
659