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