aslcodegen.c revision 1.1.1.4 1 /******************************************************************************
2 *
3 * Module Name: aslcodegen - AML code generation
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2014, 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 "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "amlcode.h"
47
48 #define _COMPONENT ACPI_COMPILER
49 ACPI_MODULE_NAME ("aslcodegen")
50
51 /* Local prototypes */
52
53 static ACPI_STATUS
54 CgAmlWriteWalk (
55 ACPI_PARSE_OBJECT *Op,
56 UINT32 Level,
57 void *Context);
58
59 static void
60 CgLocalWriteAmlData (
61 ACPI_PARSE_OBJECT *Op,
62 void *Buffer,
63 UINT32 Length);
64
65 static void
66 CgWriteAmlOpcode (
67 ACPI_PARSE_OBJECT *Op);
68
69 static void
70 CgWriteTableHeader (
71 ACPI_PARSE_OBJECT *Op);
72
73 static void
74 CgCloseTable (
75 void);
76
77 static void
78 CgWriteNode (
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
95 void
96 CgGenerateAmlOutput (
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 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
126 static ACPI_STATUS
127 CgAmlWriteWalk (
128 ACPI_PARSE_OBJECT *Op,
129 UINT32 Level,
130 void *Context)
131 {
132
133 /*
134 * Print header at level 0. Alignment assumes 32-bit pointers
135 */
136 if (!Level)
137 {
138 DbgPrint (ASL_TREE_OUTPUT,
139 "Final parse tree used for AML output:\n");
140 DbgPrint (ASL_TREE_OUTPUT,
141 "%*s Value P_Op A_Op OpLen PByts Len SubLen PSubLen OpPtr Child Parent Flags AcTyp Final Col L\n",
142 76, " ");
143 }
144
145 /* Debug output */
146
147 DbgPrint (ASL_TREE_OUTPUT,
148 "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level);
149 UtPrintFormattedName (Op->Asl.ParseOpcode, Level);
150
151 if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG ||
152 Op->Asl.ParseOpcode == PARSEOP_NAMESTRING ||
153 Op->Asl.ParseOpcode == PARSEOP_METHODCALL)
154 {
155 DbgPrint (ASL_TREE_OUTPUT,
156 "%10.32s ", Op->Asl.ExternalName);
157 }
158 else
159 {
160 DbgPrint (ASL_TREE_OUTPUT, " ");
161 }
162
163 DbgPrint (ASL_TREE_OUTPUT,
164 "%08X %04X %04X %01X %04X %04X %04X %04X %08X %08X %08X %08X %08X %04X %02d %02d\n",
165 /* 1 */ (UINT32) Op->Asl.Value.Integer,
166 /* 2 */ Op->Asl.ParseOpcode,
167 /* 3 */ Op->Asl.AmlOpcode,
168 /* 4 */ Op->Asl.AmlOpcodeLength,
169 /* 5 */ Op->Asl.AmlPkgLenBytes,
170 /* 6 */ Op->Asl.AmlLength,
171 /* 7 */ Op->Asl.AmlSubtreeLength,
172 /* 8 */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0,
173 /* 9 */ Op,
174 /* 10 */ Op->Asl.Child,
175 /* 11 */ Op->Asl.Parent,
176 /* 12 */ Op->Asl.CompileFlags,
177 /* 13 */ Op->Asl.AcpiBtype,
178 /* 14 */ Op->Asl.FinalAmlLength,
179 /* 15 */ Op->Asl.Column,
180 /* 16 */ Op->Asl.LineNumber);
181
182 /* Generate the AML for this node */
183
184 CgWriteNode (Op);
185 return (AE_OK);
186 }
187
188
189 /*******************************************************************************
190 *
191 * FUNCTION: CgLocalWriteAmlData
192 *
193 * PARAMETERS: Op - Current parse op
194 * Buffer - Buffer to write
195 * Length - Size of data in buffer
196 *
197 * RETURN: None
198 *
199 * DESCRIPTION: Write a buffer of AML data to the AML output file.
200 *
201 ******************************************************************************/
202
203 static void
204 CgLocalWriteAmlData (
205 ACPI_PARSE_OBJECT *Op,
206 void *Buffer,
207 UINT32 Length)
208 {
209
210 /* Write the raw data to the AML file */
211
212 FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length);
213
214 /* Update the final AML length for this node (used for listings) */
215
216 if (Op)
217 {
218 Op->Asl.FinalAmlLength += Length;
219 }
220 }
221
222
223 /*******************************************************************************
224 *
225 * FUNCTION: CgWriteAmlOpcode
226 *
227 * PARAMETERS: Op - Parse node with an AML opcode
228 *
229 * RETURN: None.
230 *
231 * DESCRIPTION: Write the AML opcode corresponding to a parse node.
232 *
233 ******************************************************************************/
234
235 static void
236 CgWriteAmlOpcode (
237 ACPI_PARSE_OBJECT *Op)
238 {
239 UINT8 PkgLenFirstByte;
240 UINT32 i;
241 union {
242 UINT16 Opcode;
243 UINT8 OpcodeBytes[2];
244 } Aml;
245 union {
246 UINT32 Len;
247 UINT8 LenBytes[4];
248 } PkgLen;
249
250
251 /* We expect some DEFAULT_ARGs, just ignore them */
252
253 if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
254 {
255 return;
256 }
257
258 switch (Op->Asl.AmlOpcode)
259 {
260 case AML_UNASSIGNED_OPCODE:
261
262 /* These opcodes should not get here */
263
264 printf ("Found a node with an unassigned AML opcode\n");
265 FlPrintFile (ASL_FILE_STDERR, "Found a node with an unassigned AML opcode\n");
266 return;
267
268 case AML_INT_RESERVEDFIELD_OP:
269
270 /* Special opcodes for within a field definition */
271
272 Aml.Opcode = AML_FIELD_OFFSET_OP;
273 break;
274
275 case AML_INT_ACCESSFIELD_OP:
276
277 Aml.Opcode = AML_FIELD_ACCESS_OP;
278 break;
279
280 case AML_INT_CONNECTION_OP:
281
282 Aml.Opcode = AML_FIELD_CONNECTION_OP;
283 break;
284
285 default:
286
287 Aml.Opcode = Op->Asl.AmlOpcode;
288 break;
289 }
290
291
292 switch (Aml.Opcode)
293 {
294 case AML_PACKAGE_LENGTH:
295
296 /* Value is the length to be encoded (Used in field definitions) */
297
298 PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
299 break;
300
301 default:
302
303 /* Check for two-byte opcode */
304
305 if (Aml.Opcode > 0x00FF)
306 {
307 /* Write the high byte first */
308
309 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
310 }
311
312 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
313
314 /* Subtreelength doesn't include length of package length bytes */
315
316 PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
317 break;
318 }
319
320 /* Does this opcode have an associated "PackageLength" field? */
321
322 if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
323 {
324 if (Op->Asl.AmlPkgLenBytes == 1)
325 {
326 /* Simplest case -- no bytes to follow, just write the count */
327
328 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
329 }
330 else if (Op->Asl.AmlPkgLenBytes != 0)
331 {
332 /*
333 * Encode the "bytes to follow" in the first byte, top two bits.
334 * The low-order nybble of the length is in the bottom 4 bits
335 */
336 PkgLenFirstByte = (UINT8)
337 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
338 (PkgLen.LenBytes[0] & 0x0F));
339
340 CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
341
342 /*
343 * Shift the length over by the 4 bits we just stuffed
344 * in the first byte
345 */
346 PkgLen.Len >>= 4;
347
348 /* Now we can write the remaining bytes - either 1, 2, or 3 bytes */
349
350 for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++)
351 {
352 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1);
353 }
354 }
355 }
356
357 switch (Aml.Opcode)
358 {
359 case AML_BYTE_OP:
360
361 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1);
362 break;
363
364 case AML_WORD_OP:
365
366 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2);
367 break;
368
369 case AML_DWORD_OP:
370
371 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4);
372 break;
373
374 case AML_QWORD_OP:
375
376 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8);
377 break;
378
379 case AML_STRING_OP:
380
381 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
382 break;
383
384 default:
385
386 /* All data opcodes must appear above */
387
388 break;
389 }
390 }
391
392
393 /*******************************************************************************
394 *
395 * FUNCTION: CgWriteTableHeader
396 *
397 * PARAMETERS: Op - The DEFINITIONBLOCK node
398 *
399 * RETURN: None
400 *
401 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK
402 *
403 ******************************************************************************/
404
405 static void
406 CgWriteTableHeader (
407 ACPI_PARSE_OBJECT *Op)
408 {
409 ACPI_PARSE_OBJECT *Child;
410
411
412 /* AML filename */
413
414 Child = Op->Asl.Child;
415
416 /* Signature */
417
418 Child = Child->Asl.Next;
419 strncpy (TableHeader.Signature, Child->Asl.Value.String, 4);
420
421 /* Revision */
422
423 Child = Child->Asl.Next;
424 TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
425
426 /* Command-line Revision override */
427
428 if (Gbl_RevisionOverride)
429 {
430 TableHeader.Revision = Gbl_RevisionOverride;
431 }
432
433 /* OEMID */
434
435 Child = Child->Asl.Next;
436 strncpy (TableHeader.OemId, Child->Asl.Value.String, 6);
437
438 /* OEM TableID */
439
440 Child = Child->Asl.Next;
441 strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8);
442
443 /* OEM Revision */
444
445 Child = Child->Asl.Next;
446 TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
447
448 /* Compiler ID */
449
450 ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID);
451
452 /* Compiler version */
453
454 TableHeader.AslCompilerRevision = ASL_REVISION;
455
456 /* Table length. Checksum zero for now, will rewrite later */
457
458 TableHeader.Length = Gbl_TableLength;
459 TableHeader.Checksum = 0;
460
461 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
462 }
463
464
465 /*******************************************************************************
466 *
467 * FUNCTION: CgCloseTable
468 *
469 * PARAMETERS: None.
470 *
471 * RETURN: None.
472 *
473 * DESCRIPTION: Complete the ACPI table by calculating the checksum and
474 * re-writing the header.
475 *
476 ******************************************************************************/
477
478 static void
479 CgCloseTable (
480 void)
481 {
482 signed char Sum;
483 UINT8 FileByte;
484
485
486 FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
487 Sum = 0;
488
489 /* Calculate the checksum over the entire file */
490
491 while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK)
492 {
493 Sum = (signed char) (Sum + FileByte);
494 }
495
496 /* Re-write the table header with the checksum */
497
498 TableHeader.Checksum = (UINT8) (0 - Sum);
499
500 FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
501 CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER));
502 }
503
504
505 /*******************************************************************************
506 *
507 * FUNCTION: CgWriteNode
508 *
509 * PARAMETERS: Op - Parse node to write.
510 *
511 * RETURN: None.
512 *
513 * DESCRIPTION: Write the AML that corresponds to a parse node.
514 *
515 ******************************************************************************/
516
517 static void
518 CgWriteNode (
519 ACPI_PARSE_OBJECT *Op)
520 {
521 ASL_RESOURCE_NODE *Rnode;
522
523
524 /* Always check for DEFAULT_ARG and other "Noop" nodes */
525 /* TBD: this may not be the best place for this check */
526
527 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) ||
528 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) ||
529 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) ||
530 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
531 {
532 return;
533 }
534
535 Op->Asl.FinalAmlLength = 0;
536
537 switch (Op->Asl.AmlOpcode)
538 {
539 case AML_RAW_DATA_BYTE:
540 case AML_RAW_DATA_WORD:
541 case AML_RAW_DATA_DWORD:
542 case AML_RAW_DATA_QWORD:
543
544 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
545 return;
546
547
548 case AML_RAW_DATA_BUFFER:
549
550 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
551 return;
552
553
554 case AML_RAW_DATA_CHAIN:
555
556 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
557 while (Rnode)
558 {
559 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
560 Rnode = Rnode->Next;
561 }
562 return;
563
564 default:
565
566 /* Internal data opcodes must all appear above */
567
568 break;
569 }
570
571 switch (Op->Asl.ParseOpcode)
572 {
573 case PARSEOP_DEFAULT_ARG:
574
575 break;
576
577 case PARSEOP_DEFINITIONBLOCK:
578
579 CgWriteTableHeader (Op);
580 break;
581
582 case PARSEOP_NAMESEG:
583 case PARSEOP_NAMESTRING:
584 case PARSEOP_METHODCALL:
585
586 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
587 break;
588
589 default:
590
591 CgWriteAmlOpcode (Op);
592 break;
593 }
594 }
595