1 /******************************************************************************
3 * Module Name: aslopcode - AML opcode generation
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2013, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
45 #include "aslcompiler.h"
46 #include "aslcompiler.y.h"
49 #define _COMPONENT ACPI_COMPILER
50 ACPI_MODULE_NAME ("aslopcodes")
53 /* Local prototypes */
57 ACPI_PARSE_OBJECT
*Op
);
61 ACPI_PARSE_OBJECT
*Op
);
65 ACPI_PARSE_OBJECT
*Op
);
69 ACPI_PARSE_OBJECT
*Op
);
73 ACPI_PARSE_OBJECT
*Op
);
76 /*******************************************************************************
78 * FUNCTION: OpcAmlOpcodeUpdateWalk
80 * PARAMETERS: ASL_WALK_CALLBACK
84 * DESCRIPTION: Opcode update walk, ascending callback
86 ******************************************************************************/
89 OpcAmlOpcodeUpdateWalk (
90 ACPI_PARSE_OBJECT
*Op
,
96 * Handle the Package() case where the actual opcode cannot be determined
97 * until the PackageLength operand has been folded and minimized.
98 * (PackageOp versus VarPackageOp)
100 * This is (as of ACPI 3.0) the only case where the AML opcode can change
101 * based upon the value of a parameter.
103 * The parser always inserts a VarPackage opcode, which can possibly be
104 * optimized to a Package opcode.
106 if (Op
->Asl
.ParseOpcode
== PARSEOP_VAR_PACKAGE
)
115 /*******************************************************************************
117 * FUNCTION: OpcAmlOpcodeWalk
119 * PARAMETERS: ASL_WALK_CALLBACK
123 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML
126 ******************************************************************************/
130 ACPI_PARSE_OBJECT
*Op
,
137 OpcGenerateAmlOpcode (Op
);
138 OpnGenerateAmlOperands (Op
);
143 /*******************************************************************************
145 * FUNCTION: OpcGetIntegerWidth
147 * PARAMETERS: Op - DEFINITION BLOCK op
151 * DESCRIPTION: Extract integer width from the table revision
153 ******************************************************************************/
157 ACPI_PARSE_OBJECT
*Op
)
159 ACPI_PARSE_OBJECT
*Child
;
167 if (Gbl_RevisionOverride
)
169 AcpiUtSetIntegerWidth (Gbl_RevisionOverride
);
173 Child
= Op
->Asl
.Child
;
174 Child
= Child
->Asl
.Next
;
175 Child
= Child
->Asl
.Next
;
177 /* Use the revision to set the integer width */
179 AcpiUtSetIntegerWidth ((UINT8
) Child
->Asl
.Value
.Integer
);
184 /*******************************************************************************
186 * FUNCTION: OpcSetOptimalIntegerSize
188 * PARAMETERS: Op - A parse tree node
190 * RETURN: Integer width, in bytes. Also sets the node AML opcode to the
191 * optimal integer AML prefix opcode.
193 * DESCRIPTION: Determine the optimal AML encoding of an integer. All leading
194 * zeros can be truncated to squeeze the integer into the
195 * minimal number of AML bytes.
197 ******************************************************************************/
200 OpcSetOptimalIntegerSize (
201 ACPI_PARSE_OBJECT
*Op
)
206 * TBD: - we don't want to optimize integers in the block header, but the
207 * code below does not work correctly.
209 if (Op
->Asl
.Parent
&&
210 Op
->Asl
.Parent
->Asl
.Parent
&&
211 (Op
->Asl
.Parent
->Asl
.Parent
->Asl
.ParseOpcode
== PARSEOP_DEFINITIONBLOCK
))
218 * Check for the special AML integers first - Zero, One, Ones.
219 * These are single-byte opcodes that are the smallest possible
220 * representation of an integer.
222 * This optimization is optional.
224 if (Gbl_IntegerOptimizationFlag
)
226 switch (Op
->Asl
.Value
.Integer
)
230 Op
->Asl
.AmlOpcode
= AML_ZERO_OP
;
231 AslError (ASL_OPTIMIZATION
, ASL_MSG_INTEGER_OPTIMIZATION
,
237 Op
->Asl
.AmlOpcode
= AML_ONE_OP
;
238 AslError (ASL_OPTIMIZATION
, ASL_MSG_INTEGER_OPTIMIZATION
,
242 case ACPI_UINT32_MAX
:
244 /* Check for table integer width (32 or 64) */
246 if (AcpiGbl_IntegerByteWidth
== 4)
248 Op
->Asl
.AmlOpcode
= AML_ONES_OP
;
249 AslError (ASL_OPTIMIZATION
, ASL_MSG_INTEGER_OPTIMIZATION
,
255 case ACPI_UINT64_MAX
:
257 /* Check for table integer width (32 or 64) */
259 if (AcpiGbl_IntegerByteWidth
== 8)
261 Op
->Asl
.AmlOpcode
= AML_ONES_OP
;
262 AslError (ASL_OPTIMIZATION
, ASL_MSG_INTEGER_OPTIMIZATION
,
274 /* Find the best fit using the various AML integer prefixes */
276 if (Op
->Asl
.Value
.Integer
<= ACPI_UINT8_MAX
)
278 Op
->Asl
.AmlOpcode
= AML_BYTE_OP
;
281 if (Op
->Asl
.Value
.Integer
<= ACPI_UINT16_MAX
)
283 Op
->Asl
.AmlOpcode
= AML_WORD_OP
;
286 if (Op
->Asl
.Value
.Integer
<= ACPI_UINT32_MAX
)
288 Op
->Asl
.AmlOpcode
= AML_DWORD_OP
;
293 if (AcpiGbl_IntegerByteWidth
== 4)
295 AslError (ASL_WARNING
, ASL_MSG_INTEGER_LENGTH
,
298 if (!Gbl_IgnoreErrors
)
300 /* Truncate the integer to 32-bit */
301 Op
->Asl
.AmlOpcode
= AML_DWORD_OP
;
306 Op
->Asl
.AmlOpcode
= AML_QWORD_OP
;
312 /*******************************************************************************
314 * FUNCTION: OpcDoAccessAs
316 * PARAMETERS: Op - Parse node
320 * DESCRIPTION: Implement the ACCESS_AS ASL keyword.
322 ******************************************************************************/
326 ACPI_PARSE_OBJECT
*Op
)
328 ACPI_PARSE_OBJECT
*TypeOp
;
329 ACPI_PARSE_OBJECT
*AttribOp
;
330 ACPI_PARSE_OBJECT
*LengthOp
;
334 Op
->Asl
.AmlOpcodeLength
= 1;
335 TypeOp
= Op
->Asl
.Child
;
337 /* First child is the access type */
339 TypeOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BYTE
;
340 TypeOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
342 /* Second child is the optional access attribute */
344 AttribOp
= TypeOp
->Asl
.Next
;
345 if (AttribOp
->Asl
.ParseOpcode
== PARSEOP_DEFAULT_ARG
)
347 AttribOp
->Asl
.Value
.Integer
= 0;
349 AttribOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BYTE
;
350 AttribOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
352 /* Only a few AccessAttributes support AccessLength */
354 Attribute
= (UINT8
) AttribOp
->Asl
.Value
.Integer
;
355 if ((Attribute
!= AML_FIELD_ATTRIB_MULTIBYTE
) &&
356 (Attribute
!= AML_FIELD_ATTRIB_RAW_BYTES
) &&
357 (Attribute
!= AML_FIELD_ATTRIB_RAW_PROCESS
))
362 Op
->Asl
.AmlOpcode
= AML_FIELD_EXT_ACCESS_OP
;
365 * Child of Attributes is the AccessLength (required for Multibyte,
366 * RawBytes, RawProcess.)
368 LengthOp
= AttribOp
->Asl
.Child
;
374 /* TBD: probably can remove */
376 if (LengthOp
->Asl
.ParseOpcode
== PARSEOP_DEFAULT_ARG
)
378 LengthOp
->Asl
.Value
.Integer
= 16;
381 LengthOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BYTE
;
382 LengthOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
386 /*******************************************************************************
388 * FUNCTION: OpcDoConnection
390 * PARAMETERS: Op - Parse node
394 * DESCRIPTION: Implement the Connection ASL keyword.
396 ******************************************************************************/
400 ACPI_PARSE_OBJECT
*Op
)
402 ASL_RESOURCE_NODE
*Rnode
;
403 ACPI_PARSE_OBJECT
*BufferOp
;
404 ACPI_PARSE_OBJECT
*BufferLengthOp
;
405 ACPI_PARSE_OBJECT
*BufferDataOp
;
409 Op
->Asl
.AmlOpcodeLength
= 1;
411 if (Op
->Asl
.Child
->Asl
.AmlOpcode
== AML_INT_NAMEPATH_OP
)
416 BufferOp
= Op
->Asl
.Child
;
417 BufferLengthOp
= BufferOp
->Asl
.Child
;
418 BufferDataOp
= BufferLengthOp
->Asl
.Next
;
420 State
= ACPI_RSTATE_NORMAL
;
421 Rnode
= RsDoOneResourceDescriptor (BufferDataOp
->Asl
.Next
, 0, &State
);
428 * Transform the nodes into the following
430 * Op -> AML_BUFFER_OP
431 * First Child -> BufferLength
432 * Second Child -> Descriptor Buffer (raw byte data)
434 BufferOp
->Asl
.ParseOpcode
= PARSEOP_BUFFER
;
435 BufferOp
->Asl
.AmlOpcode
= AML_BUFFER_OP
;
436 BufferOp
->Asl
.CompileFlags
= NODE_AML_PACKAGE
| NODE_IS_RESOURCE_DESC
;
437 UtSetParseOpName (BufferOp
);
439 BufferLengthOp
->Asl
.ParseOpcode
= PARSEOP_INTEGER
;
440 BufferLengthOp
->Asl
.Value
.Integer
= Rnode
->BufferLength
;
441 (void) OpcSetOptimalIntegerSize (BufferLengthOp
);
442 UtSetParseOpName (BufferLengthOp
);
444 BufferDataOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
445 BufferDataOp
->Asl
.AmlOpcode
= AML_RAW_DATA_CHAIN
;
446 BufferDataOp
->Asl
.AmlOpcodeLength
= 0;
447 BufferDataOp
->Asl
.AmlLength
= Rnode
->BufferLength
;
448 BufferDataOp
->Asl
.Value
.Buffer
= (UINT8
*) Rnode
;
449 UtSetParseOpName (BufferDataOp
);
453 /*******************************************************************************
455 * FUNCTION: OpcDoUnicode
457 * PARAMETERS: Op - Parse node
461 * DESCRIPTION: Implement the UNICODE ASL "macro". Convert the input string
462 * to a unicode buffer. There is no Unicode AML opcode.
464 * Note: The Unicode string is 16 bits per character, no leading signature,
465 * with a 16-bit terminating NULL.
467 ******************************************************************************/
471 ACPI_PARSE_OBJECT
*Op
)
473 ACPI_PARSE_OBJECT
*InitializerOp
;
478 UINT16
*UnicodeString
;
479 ACPI_PARSE_OBJECT
*BufferLengthOp
;
482 /* Change op into a buffer object */
484 Op
->Asl
.CompileFlags
&= ~NODE_COMPILE_TIME_CONST
;
485 Op
->Asl
.ParseOpcode
= PARSEOP_BUFFER
;
486 UtSetParseOpName (Op
);
488 /* Buffer Length is first, followed by the string */
490 BufferLengthOp
= Op
->Asl
.Child
;
491 InitializerOp
= BufferLengthOp
->Asl
.Next
;
493 AsciiString
= (UINT8
*) InitializerOp
->Asl
.Value
.String
;
495 /* Create a new buffer for the Unicode string */
497 Count
= strlen (InitializerOp
->Asl
.Value
.String
) + 1;
498 Length
= Count
* sizeof (UINT16
);
499 UnicodeString
= UtLocalCalloc (Length
);
501 /* Convert to Unicode string (including null terminator) */
503 for (i
= 0; i
< Count
; i
++)
505 UnicodeString
[i
] = (UINT16
) AsciiString
[i
];
509 * Just set the buffer size node to be the buffer length, regardless
510 * of whether it was previously an integer or a default_arg placeholder
512 BufferLengthOp
->Asl
.ParseOpcode
= PARSEOP_INTEGER
;
513 BufferLengthOp
->Asl
.AmlOpcode
= AML_DWORD_OP
;
514 BufferLengthOp
->Asl
.Value
.Integer
= Length
;
515 UtSetParseOpName (BufferLengthOp
);
517 (void) OpcSetOptimalIntegerSize (BufferLengthOp
);
519 /* The Unicode string is a raw data buffer */
521 InitializerOp
->Asl
.Value
.Buffer
= (UINT8
*) UnicodeString
;
522 InitializerOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BUFFER
;
523 InitializerOp
->Asl
.AmlLength
= Length
;
524 InitializerOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
525 InitializerOp
->Asl
.Child
= NULL
;
526 UtSetParseOpName (InitializerOp
);
530 /*******************************************************************************
532 * FUNCTION: OpcDoEisaId
534 * PARAMETERS: Op - Parse node
538 * DESCRIPTION: Convert a string EISA ID to numeric representation. See the
539 * Pnp BIOS Specification for details. Here is an excerpt:
541 * A seven character ASCII representation of the product
542 * identifier compressed into a 32-bit identifier. The seven
543 * character ID consists of a three character manufacturer code,
544 * a three character hexadecimal product identifier, and a one
545 * character hexadecimal revision number. The manufacturer code
546 * is a 3 uppercase character code that is compressed into 3 5-bit
548 * 1) Find hex ASCII value for each letter
549 * 2) Subtract 40h from each ASCII value
550 * 3) Retain 5 least significant bits for each letter by
551 * discarding upper 3 bits because they are always 0.
552 * 4) Compressed code = concatenate 0 and the 3 5-bit values
554 * The format of the compressed product identifier is as follows:
555 * Byte 0: Bit 7 - Reserved (0)
556 * Bits 6-2: - 1st character of compressed mfg code
557 * Bits 1-0 - Upper 2 bits of 2nd character of mfg code
558 * Byte 1: Bits 7-5 - Lower 3 bits of 2nd character of mfg code
559 * Bits 4-0 - 3rd character of mfg code
560 * Byte 2: Bits 7-4 - 1st hex digit of product number
561 * Bits 3-0 - 2nd hex digit of product number
562 * Byte 3: Bits 7-4 - 3st hex digit of product number
563 * Bits 3-0 - Hex digit of the revision number
565 ******************************************************************************/
569 ACPI_PARSE_OBJECT
*Op
)
574 ACPI_STATUS Status
= AE_OK
;
578 InString
= (char *) Op
->Asl
.Value
.String
;
581 * The EISAID string must be exactly 7 characters and of the form
582 * "UUUXXXX" -- 3 uppercase letters and 4 hex digits (e.g., "PNP0001")
584 if (ACPI_STRLEN (InString
) != 7)
586 Status
= AE_BAD_PARAMETER
;
590 /* Check all 7 characters for correct format */
592 for (i
= 0; i
< 7; i
++)
594 /* First 3 characters must be uppercase letters */
598 if (!isupper ((int) InString
[i
]))
600 Status
= AE_BAD_PARAMETER
;
604 /* Last 4 characters must be hex digits */
606 else if (!isxdigit ((int) InString
[i
]))
608 Status
= AE_BAD_PARAMETER
;
613 if (ACPI_FAILURE (Status
))
615 AslError (ASL_ERROR
, ASL_MSG_INVALID_EISAID
, Op
, Op
->Asl
.Value
.String
);
619 /* Create ID big-endian first (bits are contiguous) */
622 (UINT32
) ((UINT8
) (InString
[0] - 0x40)) << 26 |
623 (UINT32
) ((UINT8
) (InString
[1] - 0x40)) << 21 |
624 (UINT32
) ((UINT8
) (InString
[2] - 0x40)) << 16 |
626 (UtHexCharToValue (InString
[3])) << 12 |
627 (UtHexCharToValue (InString
[4])) << 8 |
628 (UtHexCharToValue (InString
[5])) << 4 |
629 UtHexCharToValue (InString
[6]);
631 /* Swap to little-endian to get final ID (see function header) */
633 EisaId
= AcpiUtDwordByteSwap (BigEndianId
);
637 * Morph the Op into an integer, regardless of whether there
638 * was an error in the EISAID string
640 Op
->Asl
.Value
.Integer
= EisaId
;
642 Op
->Asl
.CompileFlags
&= ~NODE_COMPILE_TIME_CONST
;
643 Op
->Asl
.ParseOpcode
= PARSEOP_INTEGER
;
644 (void) OpcSetOptimalIntegerSize (Op
);
646 /* Op is now an integer */
648 UtSetParseOpName (Op
);
652 /*******************************************************************************
654 * FUNCTION: OpcDoUuId
656 * PARAMETERS: Op - Parse node
660 * DESCRIPTION: Convert UUID string to 16-byte buffer
662 ******************************************************************************/
666 ACPI_PARSE_OBJECT
*Op
)
670 ACPI_STATUS Status
= AE_OK
;
671 ACPI_PARSE_OBJECT
*NewOp
;
674 InString
= (char *) Op
->Asl
.Value
.String
;
675 Buffer
= UtLocalCalloc (16);
677 Status
= AuValidateUuid (InString
);
678 if (ACPI_FAILURE (Status
))
680 AslError (ASL_ERROR
, ASL_MSG_INVALID_UUID
, Op
, Op
->Asl
.Value
.String
);
684 (void) AuConvertStringToUuid (InString
, Buffer
);
687 /* Change Op to a Buffer */
689 Op
->Asl
.ParseOpcode
= PARSEOP_BUFFER
;
690 Op
->Common
.AmlOpcode
= AML_BUFFER_OP
;
692 /* Disable further optimization */
694 Op
->Asl
.CompileFlags
&= ~NODE_COMPILE_TIME_CONST
;
695 UtSetParseOpName (Op
);
697 /* Child node is the buffer length */
699 NewOp
= TrAllocateNode (PARSEOP_INTEGER
);
701 NewOp
->Asl
.AmlOpcode
= AML_BYTE_OP
;
702 NewOp
->Asl
.Value
.Integer
= 16;
703 NewOp
->Asl
.Parent
= Op
;
705 Op
->Asl
.Child
= NewOp
;
708 /* Peer to the child is the raw buffer data */
710 NewOp
= TrAllocateNode (PARSEOP_RAW_DATA
);
711 NewOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BUFFER
;
712 NewOp
->Asl
.AmlLength
= 16;
713 NewOp
->Asl
.Value
.String
= (char *) Buffer
;
714 NewOp
->Asl
.Parent
= Op
->Asl
.Parent
;
716 Op
->Asl
.Next
= NewOp
;
720 /*******************************************************************************
722 * FUNCTION: OpcGenerateAmlOpcode
724 * PARAMETERS: Op - Parse node
728 * DESCRIPTION: Generate the AML opcode associated with the node and its
729 * parse (lex/flex) keyword opcode. Essentially implements
730 * a mapping between the parse opcodes and the actual AML opcodes.
732 ******************************************************************************/
735 OpcGenerateAmlOpcode (
736 ACPI_PARSE_OBJECT
*Op
)
742 Index
= (UINT16
) (Op
->Asl
.ParseOpcode
- ASL_PARSE_OPCODE_BASE
);
744 Op
->Asl
.AmlOpcode
= AslKeywordMapping
[Index
].AmlOpcode
;
745 Op
->Asl
.AcpiBtype
= AslKeywordMapping
[Index
].AcpiBtype
;
746 Op
->Asl
.CompileFlags
|= AslKeywordMapping
[Index
].Flags
;
748 if (!Op
->Asl
.Value
.Integer
)
750 Op
->Asl
.Value
.Integer
= AslKeywordMapping
[Index
].Value
;
753 /* Special handling for some opcodes */
755 switch (Op
->Asl
.ParseOpcode
)
757 case PARSEOP_INTEGER
:
759 * Set the opcode based on the size of the integer
761 (void) OpcSetOptimalIntegerSize (Op
);
766 Op
->Asl
.AmlOpcodeLength
= 1;
769 case PARSEOP_ACCESSAS
:
774 case PARSEOP_CONNECTION
:
776 OpcDoConnection (Op
);
789 case PARSEOP_UNICODE
:
794 case PARSEOP_INCLUDE
:
796 Op
->Asl
.Child
->Asl
.ParseOpcode
= PARSEOP_DEFAULT_ARG
;
797 Gbl_HasIncludeFiles
= TRUE
;
800 case PARSEOP_EXTERNAL
:
802 Op
->Asl
.Child
->Asl
.ParseOpcode
= PARSEOP_DEFAULT_ARG
;
803 Op
->Asl
.Child
->Asl
.Next
->Asl
.ParseOpcode
= PARSEOP_DEFAULT_ARG
;
808 if (AcpiGbl_IntegerBitWidth
== 32)
810 AslError (ASL_REMARK
, ASL_MSG_TRUNCATION
, Op
, NULL
);
816 /* Nothing to do for other opcodes */