1 /******************************************************************************
3 * Module Name: aslopcode - AML opcode generation
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2016, 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.
44 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
48 #define _COMPONENT ACPI_COMPILER
49 ACPI_MODULE_NAME ("aslopcodes")
52 /* Local prototypes */
56 ACPI_PARSE_OBJECT
*Op
);
60 ACPI_PARSE_OBJECT
*Op
);
64 ACPI_PARSE_OBJECT
*Op
);
68 ACPI_PARSE_OBJECT
*Op
);
72 ACPI_PARSE_OBJECT
*Op
);
75 /*******************************************************************************
77 * FUNCTION: OpcAmlOpcodeUpdateWalk
79 * PARAMETERS: ASL_WALK_CALLBACK
83 * DESCRIPTION: Opcode update walk, ascending callback
85 ******************************************************************************/
88 OpcAmlOpcodeUpdateWalk (
89 ACPI_PARSE_OBJECT
*Op
,
95 * Handle the Package() case where the actual opcode cannot be determined
96 * until the PackageLength operand has been folded and minimized.
97 * (PackageOp versus VarPackageOp)
99 * This is (as of ACPI 3.0) the only case where the AML opcode can change
100 * based upon the value of a parameter.
102 * The parser always inserts a VarPackage opcode, which can possibly be
103 * optimized to a Package opcode.
105 if (Op
->Asl
.ParseOpcode
== PARSEOP_VAR_PACKAGE
)
114 /*******************************************************************************
116 * FUNCTION: OpcAmlOpcodeWalk
118 * PARAMETERS: ASL_WALK_CALLBACK
122 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML
125 ******************************************************************************/
129 ACPI_PARSE_OBJECT
*Op
,
136 OpcGenerateAmlOpcode (Op
);
137 OpnGenerateAmlOperands (Op
);
142 /*******************************************************************************
144 * FUNCTION: OpcGetIntegerWidth
146 * PARAMETERS: Op - DEFINITION BLOCK op
150 * DESCRIPTION: Extract integer width from the table revision
152 ******************************************************************************/
156 ACPI_PARSE_OBJECT
*Op
)
158 ACPI_PARSE_OBJECT
*Child
;
166 if (Gbl_RevisionOverride
)
168 AcpiUtSetIntegerWidth (Gbl_RevisionOverride
);
172 Child
= Op
->Asl
.Child
;
173 Child
= Child
->Asl
.Next
;
174 Child
= Child
->Asl
.Next
;
176 /* Use the revision to set the integer width */
178 AcpiUtSetIntegerWidth ((UINT8
) Child
->Asl
.Value
.Integer
);
183 /*******************************************************************************
185 * FUNCTION: OpcSetOptimalIntegerSize
187 * PARAMETERS: Op - A parse tree node
189 * RETURN: Integer width, in bytes. Also sets the node AML opcode to the
190 * optimal integer AML prefix opcode.
192 * DESCRIPTION: Determine the optimal AML encoding of an integer. All leading
193 * zeros can be truncated to squeeze the integer into the
194 * minimal number of AML bytes.
196 ******************************************************************************/
199 OpcSetOptimalIntegerSize (
200 ACPI_PARSE_OBJECT
*Op
)
205 * TBD: - we don't want to optimize integers in the block header, but the
206 * code below does not work correctly.
208 if (Op
->Asl
.Parent
&&
209 Op
->Asl
.Parent
->Asl
.Parent
&&
210 (Op
->Asl
.Parent
->Asl
.Parent
->Asl
.ParseOpcode
== PARSEOP_DEFINITION_BLOCK
))
217 * Check for the special AML integers first - Zero, One, Ones.
218 * These are single-byte opcodes that are the smallest possible
219 * representation of an integer.
221 * This optimization is optional.
223 if (Gbl_IntegerOptimizationFlag
)
225 switch (Op
->Asl
.Value
.Integer
)
229 Op
->Asl
.AmlOpcode
= AML_ZERO_OP
;
230 AslError (ASL_OPTIMIZATION
, ASL_MSG_INTEGER_OPTIMIZATION
,
236 Op
->Asl
.AmlOpcode
= AML_ONE_OP
;
237 AslError (ASL_OPTIMIZATION
, ASL_MSG_INTEGER_OPTIMIZATION
,
241 case ACPI_UINT32_MAX
:
243 /* Check for table integer width (32 or 64) */
245 if (AcpiGbl_IntegerByteWidth
== 4)
247 Op
->Asl
.AmlOpcode
= AML_ONES_OP
;
248 AslError (ASL_OPTIMIZATION
, ASL_MSG_INTEGER_OPTIMIZATION
,
254 case ACPI_UINT64_MAX
:
256 /* Check for table integer width (32 or 64) */
258 if (AcpiGbl_IntegerByteWidth
== 8)
260 Op
->Asl
.AmlOpcode
= AML_ONES_OP
;
261 AslError (ASL_OPTIMIZATION
, ASL_MSG_INTEGER_OPTIMIZATION
,
273 /* Find the best fit using the various AML integer prefixes */
275 if (Op
->Asl
.Value
.Integer
<= ACPI_UINT8_MAX
)
277 Op
->Asl
.AmlOpcode
= AML_BYTE_OP
;
281 if (Op
->Asl
.Value
.Integer
<= ACPI_UINT16_MAX
)
283 Op
->Asl
.AmlOpcode
= AML_WORD_OP
;
287 if (Op
->Asl
.Value
.Integer
<= ACPI_UINT32_MAX
)
289 Op
->Asl
.AmlOpcode
= AML_DWORD_OP
;
292 else /* 64-bit integer */
294 if (AcpiGbl_IntegerByteWidth
== 4)
296 AslError (ASL_WARNING
, ASL_MSG_INTEGER_LENGTH
,
299 if (!Gbl_IgnoreErrors
)
301 /* Truncate the integer to 32-bit */
303 Op
->Asl
.Value
.Integer
&= ACPI_UINT32_MAX
;
305 /* Now set the optimal integer size */
307 return (OpcSetOptimalIntegerSize (Op
));
311 Op
->Asl
.AmlOpcode
= AML_QWORD_OP
;
317 /*******************************************************************************
319 * FUNCTION: OpcDoAccessAs
321 * PARAMETERS: Op - Parse node
325 * DESCRIPTION: Implement the ACCESS_AS ASL keyword.
327 ******************************************************************************/
331 ACPI_PARSE_OBJECT
*Op
)
333 ACPI_PARSE_OBJECT
*TypeOp
;
334 ACPI_PARSE_OBJECT
*AttribOp
;
335 ACPI_PARSE_OBJECT
*LengthOp
;
339 Op
->Asl
.AmlOpcodeLength
= 1;
340 TypeOp
= Op
->Asl
.Child
;
342 /* First child is the access type */
344 TypeOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BYTE
;
345 TypeOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
347 /* Second child is the optional access attribute */
349 AttribOp
= TypeOp
->Asl
.Next
;
350 if (AttribOp
->Asl
.ParseOpcode
== PARSEOP_DEFAULT_ARG
)
352 AttribOp
->Asl
.Value
.Integer
= 0;
355 AttribOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BYTE
;
356 AttribOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
358 /* Only a few AccessAttributes support AccessLength */
360 Attribute
= (UINT8
) AttribOp
->Asl
.Value
.Integer
;
361 if ((Attribute
!= AML_FIELD_ATTRIB_MULTIBYTE
) &&
362 (Attribute
!= AML_FIELD_ATTRIB_RAW_BYTES
) &&
363 (Attribute
!= AML_FIELD_ATTRIB_RAW_PROCESS
))
368 Op
->Asl
.AmlOpcode
= AML_FIELD_EXT_ACCESS_OP
;
371 * Child of Attributes is the AccessLength (required for Multibyte,
372 * RawBytes, RawProcess.)
374 LengthOp
= AttribOp
->Asl
.Child
;
380 /* TBD: probably can remove */
382 if (LengthOp
->Asl
.ParseOpcode
== PARSEOP_DEFAULT_ARG
)
384 LengthOp
->Asl
.Value
.Integer
= 16;
387 LengthOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BYTE
;
388 LengthOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
392 /*******************************************************************************
394 * FUNCTION: OpcDoConnection
396 * PARAMETERS: Op - Parse node
400 * DESCRIPTION: Implement the Connection ASL keyword.
402 ******************************************************************************/
406 ACPI_PARSE_OBJECT
*Op
)
408 ASL_RESOURCE_NODE
*Rnode
;
409 ACPI_PARSE_OBJECT
*BufferOp
;
410 ACPI_PARSE_OBJECT
*BufferLengthOp
;
411 ACPI_PARSE_OBJECT
*BufferDataOp
;
412 ASL_RESOURCE_INFO Info
;
416 Op
->Asl
.AmlOpcodeLength
= 1;
418 if (Op
->Asl
.Child
->Asl
.AmlOpcode
== AML_INT_NAMEPATH_OP
)
423 BufferOp
= Op
->Asl
.Child
;
424 BufferLengthOp
= BufferOp
->Asl
.Child
;
425 BufferDataOp
= BufferLengthOp
->Asl
.Next
;
427 Info
.DescriptorTypeOp
= BufferDataOp
->Asl
.Next
;
428 Info
.CurrentByteOffset
= 0;
429 State
= ACPI_RSTATE_NORMAL
;
430 Rnode
= RsDoOneResourceDescriptor (&Info
, &State
);
437 * Transform the nodes into the following
439 * Op -> AML_BUFFER_OP
440 * First Child -> BufferLength
441 * Second Child -> Descriptor Buffer (raw byte data)
443 BufferOp
->Asl
.ParseOpcode
= PARSEOP_BUFFER
;
444 BufferOp
->Asl
.AmlOpcode
= AML_BUFFER_OP
;
445 BufferOp
->Asl
.CompileFlags
= NODE_AML_PACKAGE
| NODE_IS_RESOURCE_DESC
;
446 UtSetParseOpName (BufferOp
);
448 BufferLengthOp
->Asl
.ParseOpcode
= PARSEOP_INTEGER
;
449 BufferLengthOp
->Asl
.Value
.Integer
= Rnode
->BufferLength
;
450 (void) OpcSetOptimalIntegerSize (BufferLengthOp
);
451 UtSetParseOpName (BufferLengthOp
);
453 BufferDataOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
454 BufferDataOp
->Asl
.AmlOpcode
= AML_RAW_DATA_CHAIN
;
455 BufferDataOp
->Asl
.AmlOpcodeLength
= 0;
456 BufferDataOp
->Asl
.AmlLength
= Rnode
->BufferLength
;
457 BufferDataOp
->Asl
.Value
.Buffer
= (UINT8
*) Rnode
;
458 UtSetParseOpName (BufferDataOp
);
462 /*******************************************************************************
464 * FUNCTION: OpcDoUnicode
466 * PARAMETERS: Op - Parse node
470 * DESCRIPTION: Implement the UNICODE ASL "macro". Convert the input string
471 * to a unicode buffer. There is no Unicode AML opcode.
473 * Note: The Unicode string is 16 bits per character, no leading signature,
474 * with a 16-bit terminating NULL.
476 ******************************************************************************/
480 ACPI_PARSE_OBJECT
*Op
)
482 ACPI_PARSE_OBJECT
*InitializerOp
;
487 UINT16
*UnicodeString
;
488 ACPI_PARSE_OBJECT
*BufferLengthOp
;
491 /* Change op into a buffer object */
493 Op
->Asl
.CompileFlags
&= ~NODE_COMPILE_TIME_CONST
;
494 Op
->Asl
.ParseOpcode
= PARSEOP_BUFFER
;
495 UtSetParseOpName (Op
);
497 /* Buffer Length is first, followed by the string */
499 BufferLengthOp
= Op
->Asl
.Child
;
500 InitializerOp
= BufferLengthOp
->Asl
.Next
;
502 AsciiString
= (UINT8
*) InitializerOp
->Asl
.Value
.String
;
504 /* Create a new buffer for the Unicode string */
506 Count
= strlen (InitializerOp
->Asl
.Value
.String
) + 1;
507 Length
= Count
* sizeof (UINT16
);
508 UnicodeString
= UtLocalCalloc (Length
);
510 /* Convert to Unicode string (including null terminator) */
512 for (i
= 0; i
< Count
; i
++)
514 UnicodeString
[i
] = (UINT16
) AsciiString
[i
];
518 * Just set the buffer size node to be the buffer length, regardless
519 * of whether it was previously an integer or a default_arg placeholder
521 BufferLengthOp
->Asl
.ParseOpcode
= PARSEOP_INTEGER
;
522 BufferLengthOp
->Asl
.AmlOpcode
= AML_DWORD_OP
;
523 BufferLengthOp
->Asl
.Value
.Integer
= Length
;
524 UtSetParseOpName (BufferLengthOp
);
526 (void) OpcSetOptimalIntegerSize (BufferLengthOp
);
528 /* The Unicode string is a raw data buffer */
530 InitializerOp
->Asl
.Value
.Buffer
= (UINT8
*) UnicodeString
;
531 InitializerOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BUFFER
;
532 InitializerOp
->Asl
.AmlLength
= Length
;
533 InitializerOp
->Asl
.ParseOpcode
= PARSEOP_RAW_DATA
;
534 InitializerOp
->Asl
.Child
= NULL
;
535 UtSetParseOpName (InitializerOp
);
539 /*******************************************************************************
541 * FUNCTION: OpcDoEisaId
543 * PARAMETERS: Op - Parse node
547 * DESCRIPTION: Convert a string EISA ID to numeric representation. See the
548 * Pnp BIOS Specification for details. Here is an excerpt:
550 * A seven character ASCII representation of the product
551 * identifier compressed into a 32-bit identifier. The seven
552 * character ID consists of a three character manufacturer code,
553 * a three character hexadecimal product identifier, and a one
554 * character hexadecimal revision number. The manufacturer code
555 * is a 3 uppercase character code that is compressed into 3 5-bit
557 * 1) Find hex ASCII value for each letter
558 * 2) Subtract 40h from each ASCII value
559 * 3) Retain 5 least significant bits for each letter by
560 * discarding upper 3 bits because they are always 0.
561 * 4) Compressed code = concatenate 0 and the 3 5-bit values
563 * The format of the compressed product identifier is as follows:
564 * Byte 0: Bit 7 - Reserved (0)
565 * Bits 6-2: - 1st character of compressed mfg code
566 * Bits 1-0 - Upper 2 bits of 2nd character of mfg code
567 * Byte 1: Bits 7-5 - Lower 3 bits of 2nd character of mfg code
568 * Bits 4-0 - 3rd character of mfg code
569 * Byte 2: Bits 7-4 - 1st hex digit of product number
570 * Bits 3-0 - 2nd hex digit of product number
571 * Byte 3: Bits 7-4 - 3st hex digit of product number
572 * Bits 3-0 - Hex digit of the revision number
574 ******************************************************************************/
578 ACPI_PARSE_OBJECT
*Op
)
583 ACPI_STATUS Status
= AE_OK
;
587 InString
= (char *) Op
->Asl
.Value
.String
;
590 * The EISAID string must be exactly 7 characters and of the form
591 * "UUUXXXX" -- 3 uppercase letters and 4 hex digits (e.g., "PNP0001")
593 if (strlen (InString
) != 7)
595 Status
= AE_BAD_PARAMETER
;
599 /* Check all 7 characters for correct format */
601 for (i
= 0; i
< 7; i
++)
603 /* First 3 characters must be uppercase letters */
607 if (!isupper ((int) InString
[i
]))
609 Status
= AE_BAD_PARAMETER
;
613 /* Last 4 characters must be hex digits */
615 else if (!isxdigit ((int) InString
[i
]))
617 Status
= AE_BAD_PARAMETER
;
622 if (ACPI_FAILURE (Status
))
624 AslError (ASL_ERROR
, ASL_MSG_INVALID_EISAID
, Op
, Op
->Asl
.Value
.String
);
628 /* Create ID big-endian first (bits are contiguous) */
631 (UINT32
) ((UINT8
) (InString
[0] - 0x40)) << 26 |
632 (UINT32
) ((UINT8
) (InString
[1] - 0x40)) << 21 |
633 (UINT32
) ((UINT8
) (InString
[2] - 0x40)) << 16 |
635 (AcpiUtAsciiCharToHex (InString
[3])) << 12 |
636 (AcpiUtAsciiCharToHex (InString
[4])) << 8 |
637 (AcpiUtAsciiCharToHex (InString
[5])) << 4 |
638 AcpiUtAsciiCharToHex (InString
[6]);
640 /* Swap to little-endian to get final ID (see function header) */
642 EisaId
= AcpiUtDwordByteSwap (BigEndianId
);
646 * Morph the Op into an integer, regardless of whether there
647 * was an error in the EISAID string
649 Op
->Asl
.Value
.Integer
= EisaId
;
651 Op
->Asl
.CompileFlags
&= ~NODE_COMPILE_TIME_CONST
;
652 Op
->Asl
.ParseOpcode
= PARSEOP_INTEGER
;
653 (void) OpcSetOptimalIntegerSize (Op
);
655 /* Op is now an integer */
657 UtSetParseOpName (Op
);
661 /*******************************************************************************
663 * FUNCTION: OpcDoUuId
665 * PARAMETERS: Op - Parse node
669 * DESCRIPTION: Convert UUID string to 16-byte buffer
671 ******************************************************************************/
675 ACPI_PARSE_OBJECT
*Op
)
679 ACPI_STATUS Status
= AE_OK
;
680 ACPI_PARSE_OBJECT
*NewOp
;
683 InString
= ACPI_CAST_PTR (char, Op
->Asl
.Value
.String
);
684 Buffer
= UtLocalCalloc (16);
686 Status
= AuValidateUuid (InString
);
687 if (ACPI_FAILURE (Status
))
689 AslError (ASL_ERROR
, ASL_MSG_INVALID_UUID
, Op
, Op
->Asl
.Value
.String
);
693 AcpiUtConvertStringToUuid (InString
, Buffer
);
696 /* Change Op to a Buffer */
698 Op
->Asl
.ParseOpcode
= PARSEOP_BUFFER
;
699 Op
->Common
.AmlOpcode
= AML_BUFFER_OP
;
701 /* Disable further optimization */
703 Op
->Asl
.CompileFlags
&= ~NODE_COMPILE_TIME_CONST
;
704 UtSetParseOpName (Op
);
706 /* Child node is the buffer length */
708 NewOp
= TrAllocateNode (PARSEOP_INTEGER
);
710 NewOp
->Asl
.AmlOpcode
= AML_BYTE_OP
;
711 NewOp
->Asl
.Value
.Integer
= 16;
712 NewOp
->Asl
.Parent
= Op
;
714 Op
->Asl
.Child
= NewOp
;
717 /* Peer to the child is the raw buffer data */
719 NewOp
= TrAllocateNode (PARSEOP_RAW_DATA
);
720 NewOp
->Asl
.AmlOpcode
= AML_RAW_DATA_BUFFER
;
721 NewOp
->Asl
.AmlLength
= 16;
722 NewOp
->Asl
.Value
.String
= ACPI_CAST_PTR (char, Buffer
);
723 NewOp
->Asl
.Parent
= Op
->Asl
.Parent
;
725 Op
->Asl
.Next
= NewOp
;
729 /*******************************************************************************
731 * FUNCTION: OpcGenerateAmlOpcode
733 * PARAMETERS: Op - Parse node
737 * DESCRIPTION: Generate the AML opcode associated with the node and its
738 * parse (lex/flex) keyword opcode. Essentially implements
739 * a mapping between the parse opcodes and the actual AML opcodes.
741 ******************************************************************************/
744 OpcGenerateAmlOpcode (
745 ACPI_PARSE_OBJECT
*Op
)
750 Index
= (UINT16
) (Op
->Asl
.ParseOpcode
- ASL_PARSE_OPCODE_BASE
);
752 Op
->Asl
.AmlOpcode
= AslKeywordMapping
[Index
].AmlOpcode
;
753 Op
->Asl
.AcpiBtype
= AslKeywordMapping
[Index
].AcpiBtype
;
754 Op
->Asl
.CompileFlags
|= AslKeywordMapping
[Index
].Flags
;
756 if (!Op
->Asl
.Value
.Integer
)
758 Op
->Asl
.Value
.Integer
= AslKeywordMapping
[Index
].Value
;
761 /* Special handling for some opcodes */
763 switch (Op
->Asl
.ParseOpcode
)
765 case PARSEOP_INTEGER
:
767 * Set the opcode based on the size of the integer
769 (void) OpcSetOptimalIntegerSize (Op
);
774 Op
->Asl
.AmlOpcodeLength
= 1;
777 case PARSEOP_ACCESSAS
:
782 case PARSEOP_CONNECTION
:
784 OpcDoConnection (Op
);
797 case PARSEOP_FPRINTF
:
812 case PARSEOP_UNICODE
:
817 case PARSEOP_INCLUDE
:
819 Gbl_HasIncludeFiles
= TRUE
;
822 case PARSEOP_EXTERNAL
:
824 if (Gbl_DoExternals
== FALSE
)
826 Op
->Asl
.Child
->Asl
.ParseOpcode
= PARSEOP_DEFAULT_ARG
;
827 Op
->Asl
.Child
->Asl
.Next
->Asl
.ParseOpcode
= PARSEOP_DEFAULT_ARG
;
833 if (AcpiGbl_IntegerBitWidth
== 32)
835 AslError (ASL_REMARK
, ASL_MSG_TRUNCATION
, Op
, NULL
);
841 /* Nothing to do for other opcodes */