| /****************************************************************************** |
| * |
| * Module Name: asllength - Tree walk to determine package and opcode lengths |
| * |
| *****************************************************************************/ |
| |
| /* |
| * Copyright (C) 2000 - 2016, Intel Corp. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions, and the following disclaimer, |
| * without modification. |
| * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
| * substantially similar to the "NO WARRANTY" disclaimer below |
| * ("Disclaimer") and any redistribution must be conditioned upon |
| * including a substantially similar Disclaimer requirement for further |
| * binary redistribution. |
| * 3. Neither the names of the above-listed copyright holders nor the names |
| * of any contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * Alternatively, this software may be distributed under the terms of the |
| * GNU General Public License ("GPL") version 2 as published by the Free |
| * Software Foundation. |
| * |
| * NO WARRANTY |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGES. |
| */ |
| |
| #include "aslcompiler.h" |
| #include "aslcompiler.y.h" |
| #include "amlcode.h" |
| |
| |
| #define _COMPONENT ACPI_COMPILER |
| ACPI_MODULE_NAME ("asllength") |
| |
| /* Local prototypes */ |
| |
| static UINT8 |
| CgGetPackageLenByteCount ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 PackageLength); |
| |
| static void |
| CgGenerateAmlOpcodeLength ( |
| ACPI_PARSE_OBJECT *Op); |
| |
| |
| #ifdef ACPI_OBSOLETE_FUNCTIONS |
| void |
| LnAdjustLengthToRoot ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 LengthDelta); |
| #endif |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: LnInitLengthsWalk |
| * |
| * PARAMETERS: ASL_WALK_CALLBACK |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Walk callback to initialize (and re-initialize) the node |
| * subtree length(s) to zero. The Subtree lengths are bubbled |
| * up to the root node in order to get a total AML length. |
| * |
| ******************************************************************************/ |
| |
| ACPI_STATUS |
| LnInitLengthsWalk ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 Level, |
| void *Context) |
| { |
| |
| Op->Asl.AmlSubtreeLength = 0; |
| return (AE_OK); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: LnPackageLengthWalk |
| * |
| * PARAMETERS: ASL_WALK_CALLBACK |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Walk callback to calculate the total AML length. |
| * 1) Calculate the AML lengths (opcode, package length, etc.) for |
| * THIS node. |
| * 2) Bubbble up all of these lengths to the parent node by summing |
| * them all into the parent subtree length. |
| * |
| * Note: The SubtreeLength represents the total AML length of all child nodes |
| * in all subtrees under a given node. Therefore, once this walk is |
| * complete, the Root Node subtree length is the AML length of the entire |
| * tree (and thus, the entire ACPI table) |
| * |
| ******************************************************************************/ |
| |
| ACPI_STATUS |
| LnPackageLengthWalk ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 Level, |
| void *Context) |
| { |
| |
| /* Generate the AML lengths for this node */ |
| |
| CgGenerateAmlLengths (Op); |
| |
| /* Bubble up all lengths (this node and all below it) to the parent */ |
| |
| if ((Op->Asl.Parent) && |
| (Op->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)) |
| { |
| Op->Asl.Parent->Asl.AmlSubtreeLength += ( |
| Op->Asl.AmlLength + |
| Op->Asl.AmlOpcodeLength + |
| Op->Asl.AmlPkgLenBytes + |
| Op->Asl.AmlSubtreeLength); |
| } |
| return (AE_OK); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: CgGetPackageLenByteCount |
| * |
| * PARAMETERS: Op - Parse node |
| * PackageLength - Length to be encoded |
| * |
| * RETURN: Required length of the package length encoding |
| * |
| * DESCRIPTION: Calculate the number of bytes required to encode the given |
| * package length. |
| * |
| ******************************************************************************/ |
| |
| static UINT8 |
| CgGetPackageLenByteCount ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 PackageLength) |
| { |
| |
| /* |
| * Determine the number of bytes required to encode the package length |
| * Note: the package length includes the number of bytes used to encode |
| * the package length, so we must account for this also. |
| */ |
| if (PackageLength <= (0x0000003F - 1)) |
| { |
| return (1); |
| } |
| else if (PackageLength <= (0x00000FFF - 2)) |
| { |
| return (2); |
| } |
| else if (PackageLength <= (0x000FFFFF - 3)) |
| { |
| return (3); |
| } |
| else if (PackageLength <= (0x0FFFFFFF - 4)) |
| { |
| return (4); |
| } |
| else |
| { |
| /* Fatal error - the package length is too large to encode */ |
| |
| AslError (ASL_ERROR, ASL_MSG_ENCODING_LENGTH, Op, NULL); |
| } |
| |
| return (0); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: CgGenerateAmlOpcodeLength |
| * |
| * PARAMETERS: Op - Parse node whose AML opcode lengths will be |
| * calculated |
| * |
| * RETURN: None. |
| * |
| * DESCRIPTION: Calculate the AmlOpcodeLength, AmlPkgLenBytes, and AmlLength |
| * fields for this node. |
| * |
| ******************************************************************************/ |
| |
| static void |
| CgGenerateAmlOpcodeLength ( |
| ACPI_PARSE_OBJECT *Op) |
| { |
| |
| /* Check for two-byte opcode */ |
| |
| if (Op->Asl.AmlOpcode > 0x00FF) |
| { |
| Op->Asl.AmlOpcodeLength = 2; |
| } |
| else |
| { |
| Op->Asl.AmlOpcodeLength = 1; |
| } |
| |
| /* Does this opcode have an associated "PackageLength" field? */ |
| |
| Op->Asl.AmlPkgLenBytes = 0; |
| if (Op->Asl.CompileFlags & NODE_AML_PACKAGE) |
| { |
| Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount ( |
| Op, Op->Asl.AmlSubtreeLength); |
| } |
| |
| /* Data opcode lengths are easy */ |
| |
| switch (Op->Asl.AmlOpcode) |
| { |
| case AML_BYTE_OP: |
| |
| Op->Asl.AmlLength = 1; |
| break; |
| |
| case AML_WORD_OP: |
| |
| Op->Asl.AmlLength = 2; |
| break; |
| |
| case AML_DWORD_OP: |
| |
| Op->Asl.AmlLength = 4; |
| break; |
| |
| case AML_QWORD_OP: |
| |
| Op->Asl.AmlLength = 8; |
| break; |
| |
| default: |
| |
| /* All data opcodes must be above */ |
| break; |
| } |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: CgGenerateAmlLengths |
| * |
| * PARAMETERS: Op - Parse node |
| * |
| * RETURN: None. |
| * |
| * DESCRIPTION: Generate internal length fields based on the AML opcode or |
| * parse opcode. |
| * |
| ******************************************************************************/ |
| |
| void |
| CgGenerateAmlLengths ( |
| ACPI_PARSE_OBJECT *Op) |
| { |
| char *Buffer; |
| ACPI_STATUS Status; |
| |
| |
| switch (Op->Asl.AmlOpcode) |
| { |
| case AML_RAW_DATA_BYTE: |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| Op->Asl.AmlLength = 1; |
| return; |
| |
| case AML_RAW_DATA_WORD: |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| Op->Asl.AmlLength = 2; |
| return; |
| |
| case AML_RAW_DATA_DWORD: |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| Op->Asl.AmlLength = 4; |
| return; |
| |
| case AML_RAW_DATA_QWORD: |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| Op->Asl.AmlLength = 8; |
| return; |
| |
| case AML_RAW_DATA_BUFFER: |
| |
| /* Aml length is/was set by creator */ |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| return; |
| |
| case AML_RAW_DATA_CHAIN: |
| |
| /* Aml length is/was set by creator */ |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| return; |
| |
| default: |
| |
| break; |
| } |
| |
| switch (Op->Asl.ParseOpcode) |
| { |
| case PARSEOP_DEFINITION_BLOCK: |
| |
| Gbl_TableLength = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength; |
| break; |
| |
| case PARSEOP_NAMESEG: |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| Op->Asl.AmlLength = 4; |
| Op->Asl.ExternalName = Op->Asl.Value.String; |
| break; |
| |
| case PARSEOP_NAMESTRING: |
| case PARSEOP_METHODCALL: |
| |
| if (Op->Asl.CompileFlags & NODE_NAME_INTERNALIZED) |
| { |
| break; |
| } |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| Status = UtInternalizeName (Op->Asl.Value.String, &Buffer); |
| if (ACPI_FAILURE (Status)) |
| { |
| DbgPrint (ASL_DEBUG_OUTPUT, |
| "Failure from internalize name %X\n", Status); |
| break; |
| } |
| |
| Op->Asl.ExternalName = Op->Asl.Value.String; |
| Op->Asl.Value.String = Buffer; |
| Op->Asl.CompileFlags |= NODE_NAME_INTERNALIZED; |
| Op->Asl.AmlLength = strlen (Buffer); |
| |
| /* |
| * Check for single backslash reference to root, |
| * make it a null terminated string in the AML |
| */ |
| if (Op->Asl.AmlLength == 1) |
| { |
| Op->Asl.AmlLength = 2; |
| } |
| break; |
| |
| case PARSEOP_STRING_LITERAL: |
| |
| Op->Asl.AmlOpcodeLength = 1; |
| |
| /* Get null terminator */ |
| |
| Op->Asl.AmlLength = strlen (Op->Asl.Value.String) + 1; |
| break; |
| |
| case PARSEOP_PACKAGE_LENGTH: |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| Op->Asl.AmlPkgLenBytes = CgGetPackageLenByteCount (Op, |
| (UINT32) Op->Asl.Value.Integer); |
| break; |
| |
| case PARSEOP_RAW_DATA: |
| |
| Op->Asl.AmlOpcodeLength = 0; |
| break; |
| |
| case PARSEOP_DEFAULT_ARG: |
| case PARSEOP_EXTERNAL: |
| case PARSEOP_INCLUDE: |
| case PARSEOP_INCLUDE_END: |
| |
| /* Ignore the "default arg" nodes, they are extraneous at this point */ |
| |
| break; |
| |
| default: |
| |
| CgGenerateAmlOpcodeLength (Op); |
| break; |
| } |
| } |
| |
| |
| #ifdef ACPI_OBSOLETE_FUNCTIONS |
| /******************************************************************************* |
| * |
| * FUNCTION: LnAdjustLengthToRoot |
| * |
| * PARAMETERS: Op - Node whose Length was changed |
| * |
| * RETURN: None. |
| * |
| * DESCRIPTION: Change the Subtree length of the given node, and bubble the |
| * change all the way up to the root node. This allows for |
| * last second changes to a package length (for example, if the |
| * package length encoding gets shorter or longer.) |
| * |
| ******************************************************************************/ |
| |
| void |
| LnAdjustLengthToRoot ( |
| ACPI_PARSE_OBJECT *SubtreeOp, |
| UINT32 LengthDelta) |
| { |
| ACPI_PARSE_OBJECT *Op; |
| |
| |
| /* Adjust all subtree lengths up to the root */ |
| |
| Op = SubtreeOp->Asl.Parent; |
| while (Op) |
| { |
| Op->Asl.AmlSubtreeLength -= LengthDelta; |
| Op = Op->Asl.Parent; |
| } |
| |
| /* Adjust the global table length */ |
| |
| Gbl_TableLength -= LengthDelta; |
| } |
| #endif |