aslcodegen.c revision 1.1.1.2.8.2 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 "aslcompiler.h"
47 #include "aslcompiler.y.h"
48 #include "amlcode.h"
49
50 #define _COMPONENT ACPI_COMPILER
51 ACPI_MODULE_NAME ("aslcodegen")
52
53 /* Local prototypes */
54
55 static ACPI_STATUS
56 CgAmlWriteWalk (
57 ACPI_PARSE_OBJECT *Op,
58 UINT32 Level,
59 void *Context);
60
61 static void
62 CgLocalWriteAmlData (
63 ACPI_PARSE_OBJECT *Op,
64 void *Buffer,
65 UINT32 Length);
66
67 static void
68 CgWriteAmlOpcode (
69 ACPI_PARSE_OBJECT *Op);
70
71 static void
72 CgWriteTableHeader (
73 ACPI_PARSE_OBJECT *Op);
74
75 static void
76 CgCloseTable (
77 void);
78
79 static void
80 CgWriteNode (
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
97 void
98 CgGenerateAmlOutput (
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
128 static ACPI_STATUS
129 CgAmlWriteWalk (
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
205 static void
206 CgLocalWriteAmlData (
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
237 static void
238 CgWriteAmlOpcode (
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
399 static void
400 CgWriteTableHeader (
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
472 static void
473 CgCloseTable (
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
511 static void
512 CgWriteNode (
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