diff options
Diffstat (limited to 'sys/contrib/dev/acpica/compiler/aslwalks.c')
-rw-r--r-- | sys/contrib/dev/acpica/compiler/aslwalks.c | 1262 |
1 files changed, 1262 insertions, 0 deletions
diff --git a/sys/contrib/dev/acpica/compiler/aslwalks.c b/sys/contrib/dev/acpica/compiler/aslwalks.c new file mode 100644 index 000000000000..09bf205f5f8d --- /dev/null +++ b/sys/contrib/dev/acpica/compiler/aslwalks.c @@ -0,0 +1,1262 @@ +/****************************************************************************** + * + * Module Name: aslwalks.c - Miscellaneous analytical parse tree walks + * + *****************************************************************************/ + +/****************************************************************************** + * + * 1. Copyright Notice + * + * Some or all of this work - Copyright (c) 1999 - 2020, Intel Corp. + * All rights reserved. + * + * 2. License + * + * 2.1. This is your license from Intel Corp. under its intellectual property + * rights. You may have additional license terms from the party that provided + * you this software, covering your right to use that party's intellectual + * property rights. + * + * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a + * copy of the source code appearing in this file ("Covered Code") an + * irrevocable, perpetual, worldwide license under Intel's copyrights in the + * base code distributed originally by Intel ("Original Intel Code") to copy, + * make derivatives, distribute, use and display any portion of the Covered + * Code in any form, with the right to sublicense such rights; and + * + * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent + * license (with the right to sublicense), under only those claims of Intel + * patents that are infringed by the Original Intel Code, to make, use, sell, + * offer to sell, and import the Covered Code and derivative works thereof + * solely to the minimum extent necessary to exercise the above copyright + * license, and in no event shall the patent license extend to any additions + * to or modifications of the Original Intel Code. No other license or right + * is granted directly or by implication, estoppel or otherwise; + * + * The above copyright and patent license is granted only if the following + * conditions are met: + * + * 3. Conditions + * + * 3.1. Redistribution of Source with Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification with rights to further distribute source must include + * the above Copyright Notice, the above License, this list of Conditions, + * and the following Disclaimer and Export Compliance provision. In addition, + * Licensee must cause all Covered Code to which Licensee contributes to + * contain a file documenting the changes Licensee made to create that Covered + * Code and the date of any change. Licensee must include in that file the + * documentation of any changes made by any predecessor Licensee. Licensee + * must include a prominent statement that the modification is derived, + * directly or indirectly, from Original Intel Code. + * + * 3.2. Redistribution of Source with no Rights to Further Distribute Source. + * Redistribution of source code of any substantial portion of the Covered + * Code or modification without rights to further distribute source must + * include the following Disclaimer and Export Compliance provision in the + * documentation and/or other materials provided with distribution. In + * addition, Licensee may not authorize further sublicense of source of any + * portion of the Covered Code, and must include terms to the effect that the + * license from Licensee to its licensee is limited to the intellectual + * property embodied in the software Licensee provides to its licensee, and + * not to intellectual property embodied in modifications its licensee may + * make. + * + * 3.3. Redistribution of Executable. Redistribution in executable form of any + * substantial portion of the Covered Code or modification must reproduce the + * above Copyright Notice, and the following Disclaimer and Export Compliance + * provision in the documentation and/or other materials provided with the + * distribution. + * + * 3.4. Intel retains all right, title, and interest in and to the Original + * Intel Code. + * + * 3.5. Neither the name Intel nor any other trademark owned or controlled by + * Intel shall be used in advertising or otherwise to promote the sale, use or + * other dealings in products derived from or relating to the Covered Code + * without prior written authorization from Intel. + * + * 4. Disclaimer and Export Compliance + * + * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED + * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE + * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, + * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY + * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A + * PARTICULAR PURPOSE. + * + * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES + * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR + * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, + * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY + * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL + * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS + * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY + * LIMITED REMEDY. + * + * 4.3. Licensee shall not export, either directly or indirectly, any of this + * software or system incorporating such software without first obtaining any + * required license or other approval from the U. S. Department of Commerce or + * any other agency or department of the United States Government. In the + * event Licensee exports any such software from the United States or + * re-exports any such software from a foreign destination, Licensee shall + * ensure that the distribution and export/re-export of the software is in + * compliance with all laws, regulations, orders, or other restrictions of the + * U.S. Export Administration Regulations. Licensee agrees that neither it nor + * any of its subsidiaries will export/re-export any technical data, process, + * software, or service, directly or indirectly, to any country for which the + * United States government or any agency thereof requires an export license, + * other governmental approval, or letter of assurance, without first obtaining + * such license, approval or letter. + * + ***************************************************************************** + * + * Alternatively, you may choose to be licensed under the terms of the + * following license: + * + * 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. + * + * 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 MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * 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 DAMAGE. + * + * Alternatively, you may choose to be licensed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + *****************************************************************************/ + +#include <contrib/dev/acpica/compiler/aslcompiler.h> +#include "aslcompiler.y.h" +#include <contrib/dev/acpica/include/acparser.h> +#include <contrib/dev/acpica/include/amlcode.h> + + +#define _COMPONENT ACPI_COMPILER + ACPI_MODULE_NAME ("aslwalks") + + +/* Local prototypes */ + +static void +AnAnalyzeStoreOperator ( + ACPI_PARSE_OBJECT *Op); + +static BOOLEAN +AnIsValidBufferConstant ( + ACPI_PARSE_OBJECT *Op); + +static void +AnValidateCreateBufferField ( + ACPI_PARSE_OBJECT *CreateBufferFieldOp); + + +/******************************************************************************* + * + * FUNCTION: AnMethodTypingWalkEnd + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback for typing walk. Complete the method + * return analysis. Check methods for: + * 1) Initialized local variables + * 2) Valid arguments + * 3) Return types + * + ******************************************************************************/ + +ACPI_STATUS +AnMethodTypingWalkEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + UINT32 ThisOpBtype; + + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_METHOD: + + Op->Asl.CompileFlags |= OP_METHOD_TYPED; + break; + + case PARSEOP_RETURN: + + if ((Op->Asl.Child) && + (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)) + { + ThisOpBtype = AnGetBtype (Op->Asl.Child); + + if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_METHODCALL) && + (ThisOpBtype == (ACPI_UINT32_MAX -1))) + { + /* + * The called method is untyped at this time (typically a + * forward reference). + * + * Check for a recursive method call first. Note: the + * Child->Node will be null if the method has not been + * resolved. + */ + if (Op->Asl.Child->Asl.Node && + (Op->Asl.ParentMethod != Op->Asl.Child->Asl.Node->Op)) + { + /* We must type the method here */ + + TrWalkParseTree (Op->Asl.Child->Asl.Node->Op, + ASL_WALK_VISIT_UPWARD, NULL, + AnMethodTypingWalkEnd, NULL); + + ThisOpBtype = AnGetBtype (Op->Asl.Child); + } + } + + /* Returns a value, save the value type */ + + if (Op->Asl.ParentMethod) + { + Op->Asl.ParentMethod->Asl.AcpiBtype |= ThisOpBtype; + } + } + break; + + default: + + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AnOperandTypecheckWalkEnd + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback for analysis walk. Complete method + * return analysis. + * + ******************************************************************************/ + +ACPI_STATUS +AnOperandTypecheckWalkEnd ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + const ACPI_OPCODE_INFO *OpInfo; + UINT32 RuntimeArgTypes; + UINT32 RuntimeArgTypes2; + UINT32 RequiredBtypes; + UINT32 ThisNodeBtype; + UINT32 CommonBtypes; + UINT32 OpcodeClass; + ACPI_PARSE_OBJECT *ArgOp; + UINT32 ArgType; + + + switch (Op->Asl.AmlOpcode) + { + case AML_RAW_DATA_BYTE: + case AML_RAW_DATA_WORD: + case AML_RAW_DATA_DWORD: + case AML_RAW_DATA_QWORD: + case AML_RAW_DATA_BUFFER: + case AML_RAW_DATA_CHAIN: + case AML_PACKAGE_LENGTH: + case AML_UNASSIGNED_OPCODE: + case AML_DEFAULT_ARG_OP: + + /* Ignore the internal (compiler-only) AML opcodes */ + + return (AE_OK); + + default: + + break; + } + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + if (!OpInfo) + { + return (AE_OK); + } + + ArgOp = Op->Asl.Child; + OpcodeClass = OpInfo->Class; + RuntimeArgTypes = OpInfo->RuntimeArgs; + +#ifdef ASL_ERROR_NAMED_OBJECT_IN_WHILE + /* + * Update 11/2008: In practice, we can't perform this check. A simple + * analysis is not sufficient. Also, it can cause errors when compiling + * disassembled code because of the way Switch operators are implemented + * (a While(One) loop with a named temp variable created within.) + */ + + /* + * If we are creating a named object, check if we are within a while loop + * by checking if the parent is a WHILE op. This is a simple analysis, but + * probably sufficient for many cases. + * + * Allow Scope(), Buffer(), and Package(). + */ + if (((OpcodeClass == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_SCOPE_OP)) || + ((OpcodeClass == AML_CLASS_CREATE) && (OpInfo->Flags & AML_NSNODE))) + { + if (Op->Asl.Parent->Asl.AmlOpcode == AML_WHILE_OP) + { + AslError (ASL_ERROR, ASL_MSG_NAMED_OBJECT_IN_WHILE, Op, NULL); + } + } +#endif + + /* + * Special case for control opcodes IF/RETURN/WHILE since they + * have no runtime arg list (at this time) + */ + switch (Op->Asl.AmlOpcode) + { + case AML_IF_OP: + case AML_WHILE_OP: + case AML_RETURN_OP: + + if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) + { + /* Check for an internal method */ + + if (AnIsInternalMethod (ArgOp)) + { + return (AE_OK); + } + + /* The lone arg is a method call, check it */ + + RequiredBtypes = AnMapArgTypeToBtype (ARGI_INTEGER); + if (Op->Asl.AmlOpcode == AML_RETURN_OP) + { + RequiredBtypes = 0xFFFFFFFF; + } + + ThisNodeBtype = AnGetBtype (ArgOp); + if (ThisNodeBtype == ACPI_UINT32_MAX) + { + return (AE_OK); + } + + AnCheckMethodReturnValue (Op, OpInfo, ArgOp, + RequiredBtypes, ThisNodeBtype); + } + return (AE_OK); + + case AML_EXTERNAL_OP: + /* + * Not really a "runtime" opcode since it used by disassembler only. + * The parser will find any issues with the operands. + */ + return (AE_OK); + + default: + + break; + } + + /* Ignore the non-executable opcodes */ + + if (RuntimeArgTypes == ARGI_INVALID_OPCODE) + { + return (AE_OK); + } + + /* + * Special handling for certain opcodes. + */ + switch (Op->Asl.AmlOpcode) + { + /* BankField has one TermArg */ + + case AML_BANK_FIELD_OP: + + OpcodeClass = AML_CLASS_EXECUTE; + ArgOp = ArgOp->Asl.Next; + ArgOp = ArgOp->Asl.Next; + break; + + /* Operation Region has 2 TermArgs */ + + case AML_REGION_OP: + + OpcodeClass = AML_CLASS_EXECUTE; + ArgOp = ArgOp->Asl.Next; + ArgOp = ArgOp->Asl.Next; + break; + + /* DataTableRegion has 3 TermArgs */ + + case AML_DATA_REGION_OP: + + OpcodeClass = AML_CLASS_EXECUTE; + ArgOp = ArgOp->Asl.Next; + break; + + /* Buffers/Packages have a length that is a TermArg */ + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VARIABLE_PACKAGE_OP: + + /* If length is a constant, we are done */ + + if ((ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER) || + (ArgOp->Asl.ParseOpcode == PARSEOP_RAW_DATA)) + { + return (AE_OK); + } + break; + + /* Store can write any object to the Debug object */ + + case AML_STORE_OP: + /* + * If this is a Store() to the Debug object, we don't need + * to perform any further validation -- because a Store of + * any object to Debug is permitted and supported. + */ + if (ArgOp->Asl.Next->Asl.AmlOpcode == AML_DEBUG_OP) + { + return (AE_OK); + } + break; + + default: + break; + } + + switch (OpcodeClass) + { + case AML_CLASS_EXECUTE: + case AML_CLASS_CREATE: + case AML_CLASS_CONTROL: + case AML_CLASS_RETURN_VALUE: + + /* Reverse the runtime argument list */ + + RuntimeArgTypes2 = 0; + while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes))) + { + RuntimeArgTypes2 <<= ARG_TYPE_WIDTH; + RuntimeArgTypes2 |= ArgType; + INCREMENT_ARG_LIST (RuntimeArgTypes); + } + + /* Typecheck each argument */ + + while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes2))) + { + /* Get the required type(s) for the argument */ + + RequiredBtypes = AnMapArgTypeToBtype (ArgType); + + if (!ArgOp) + { + AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op, + "Null ArgOp in argument loop"); + AslAbort (); + } + + /* Get the actual type of the argument */ + + ThisNodeBtype = AnGetBtype (ArgOp); + if (ThisNodeBtype == ACPI_UINT32_MAX) + { + goto NextArgument; + } + + /* Examine the arg based on the required type of the arg */ + + switch (ArgType) + { + case ARGI_TARGETREF: + + if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO) + { + /* ZERO is the placeholder for "don't store result" */ + + ThisNodeBtype = RequiredBtypes; + break; + } + + /* Fallthrough */ + + case ARGI_STORE_TARGET: + + if (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER) + { + /* + * This is the case where an original reference to a resource + * descriptor field has been replaced by an (Integer) offset. + * These named fields are supported at compile-time only; + * the names are not passed to the interpreter (via the AML). + */ + if ((ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) || + (ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE)) + { + AslError (ASL_ERROR, ASL_MSG_RESOURCE_FIELD, + ArgOp, NULL); + } + else + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, + ArgOp, NULL); + } + } + break; + + +#ifdef __FUTURE_IMPLEMENTATION +/* + * Possible future typechecking support + */ + case ARGI_REFERENCE: /* References */ + case ARGI_INTEGER_REF: + case ARGI_OBJECT_REF: + case ARGI_DEVICE_REF: + + switch (ArgOp->Asl.ParseOpcode) + { + case PARSEOP_LOCAL0: + case PARSEOP_LOCAL1: + case PARSEOP_LOCAL2: + case PARSEOP_LOCAL3: + case PARSEOP_LOCAL4: + case PARSEOP_LOCAL5: + case PARSEOP_LOCAL6: + case PARSEOP_LOCAL7: + + /* TBD: implement analysis of current value (type) of the local */ + /* For now, just treat any local as a typematch */ + + /*ThisNodeBtype = RequiredBtypes;*/ + break; + + case PARSEOP_ARG0: + case PARSEOP_ARG1: + case PARSEOP_ARG2: + case PARSEOP_ARG3: + case PARSEOP_ARG4: + case PARSEOP_ARG5: + case PARSEOP_ARG6: + + /* Hard to analyze argument types, so we won't */ + /* for now. Just treat any arg as a typematch */ + + /* ThisNodeBtype = RequiredBtypes; */ + break; + + case PARSEOP_DEBUG: + case PARSEOP_REFOF: + case PARSEOP_INDEX: + default: + + break; + } + break; +#endif + case ARGI_INTEGER: + default: + + break; + } + + + /* Check for a type mismatch (required versus actual) */ + + CommonBtypes = ThisNodeBtype & RequiredBtypes; + + if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) + { + if (AnIsInternalMethod (ArgOp)) + { + return (AE_OK); + } + + /* Check a method call for a valid return value */ + + AnCheckMethodReturnValue (Op, OpInfo, ArgOp, + RequiredBtypes, ThisNodeBtype); + } + + /* + * Now check if the actual type(s) match at least one + * bit to the required type + */ + else if (!CommonBtypes) + { + /* No match -- this is a type mismatch error */ + + AnFormatBtype (AslGbl_StringBuffer, ThisNodeBtype); + AnFormatBtype (AslGbl_StringBuffer2, RequiredBtypes); + + sprintf (AslGbl_MsgBuffer, "[%s] found, %s operator requires [%s]", + AslGbl_StringBuffer, OpInfo->Name, AslGbl_StringBuffer2); + + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, + ArgOp, AslGbl_MsgBuffer); + } + + NextArgument: + ArgOp = ArgOp->Asl.Next; + INCREMENT_ARG_LIST (RuntimeArgTypes2); + } + break; + + default: + + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AnOtherSemanticAnalysisWalkBegin + * + * PARAMETERS: ASL_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Descending callback for the analysis walk. Checks for + * miscellaneous issues in the code. + * + ******************************************************************************/ + +ACPI_STATUS +AnOtherSemanticAnalysisWalkBegin ( + ACPI_PARSE_OBJECT *Op, + UINT32 Level, + void *Context) +{ + ACPI_PARSE_OBJECT *ArgOp; + ACPI_PARSE_OBJECT *PrevArgOp = NULL; + const ACPI_OPCODE_INFO *OpInfo; + ACPI_NAMESPACE_NODE *Node; + + + OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); + + + if (OpInfo->Flags & AML_CREATE) + { + /* This group contains all of the Create Buffer Field operators */ + + AnValidateCreateBufferField (Op); + return (AE_OK); + } + + /* + * Determine if an execution class operator actually does something by + * checking if it has a target and/or the function return value is used. + * (Target is optional, so a standalone statement can actually do nothing.) + */ + if ((OpInfo->Class == AML_CLASS_EXECUTE) && + (OpInfo->Flags & AML_HAS_RETVAL) && + (!AnIsResultUsed (Op))) + { + if (OpInfo->Flags & AML_HAS_TARGET) + { + /* + * Find the target node, it is always the last child. If the target + * is not specified in the ASL, a default node of type Zero was + * created by the parser. + */ + ArgOp = Op->Asl.Child; + while (ArgOp->Asl.Next) + { + PrevArgOp = ArgOp; + ArgOp = ArgOp->Asl.Next; + } + + /* Divide() is the only weird case, it has two targets */ + + if (Op->Asl.AmlOpcode == AML_DIVIDE_OP) + { + if ((ArgOp->Asl.ParseOpcode == PARSEOP_ZERO) && + (PrevArgOp) && + (PrevArgOp->Asl.ParseOpcode == PARSEOP_ZERO)) + { + AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED, + Op, Op->Asl.ExternalName); + } + } + + else if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO) + { + AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED, + Op, Op->Asl.ExternalName); + } + } + else + { + /* + * Has no target and the result is not used. Only a couple opcodes + * can have this combination. + */ + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_ACQUIRE: + case PARSEOP_WAIT: + case PARSEOP_LOADTABLE: + + break; + + default: + + AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED, + Op, Op->Asl.ExternalName); + break; + } + } + } + + /* + * Semantic checks for individual ASL operators + */ + + switch (Op->Asl.ParseOpcode) + { + case PARSEOP_STORE: + + if (AslGbl_DoTypechecking) + { + AnAnalyzeStoreOperator (Op); + } + break; + + + case PARSEOP_ACQUIRE: + case PARSEOP_WAIT: + /* + * Emit a warning if the timeout parameter for these operators is not + * ACPI_WAIT_FOREVER, and the result value from the operator is not + * checked, meaning that a timeout could happen, but the code + * would not know about it. + */ + + /* First child is the namepath, 2nd child is timeout */ + + ArgOp = Op->Asl.Child; + ArgOp = ArgOp->Asl.Next; + + /* + * Check for the WAIT_FOREVER case - defined by the ACPI spec to be + * 0xFFFF or greater + */ + if (((ArgOp->Asl.ParseOpcode == PARSEOP_WORDCONST) || + (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER)) && + (ArgOp->Asl.Value.Integer >= (UINT64) ACPI_WAIT_FOREVER)) + { + break; + } + + /* + * The operation could timeout. If the return value is not used + * (indicates timeout occurred), issue a warning + */ + if (!AnIsResultUsed (Op)) + { + AslError (ASL_WARNING, ASL_MSG_TIMEOUT, ArgOp, + Op->Asl.ExternalName); + } + break; + + case PARSEOP_CONNECTION: + /* + * Ensure that the referenced operation region has the correct SPACE_ID. + * From the grammar/parser, we know the parent is a FIELD definition. + */ + ArgOp = Op->Asl.Parent; /* Field definition */ + ArgOp = ArgOp->Asl.Child; /* First child is the OpRegion Name */ + Node = ArgOp->Asl.Node; /* OpRegion namespace node */ + if (!Node) + { + break; + } + + ArgOp = Node->Op; /* OpRegion definition */ + ArgOp = ArgOp->Asl.Child; /* First child is the OpRegion Name */ + ArgOp = ArgOp->Asl.Next; /* Next peer is the SPACE_ID (what we want) */ + + /* + * The Connection() operator is only valid for the following operation + * region SpaceIds: GeneralPurposeIo and GenericSerialBus. + */ + if ((ArgOp->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) && + (ArgOp->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS)) + { + AslError (ASL_ERROR, ASL_MSG_CONNECTION_INVALID, Op, NULL); + } + break; + + case PARSEOP_FIELD: + /* + * Ensure that fields for GeneralPurposeIo and GenericSerialBus + * contain at least one Connection() operator + */ + ArgOp = Op->Asl.Child; /* 1st child is the OpRegion Name */ + Node = ArgOp->Asl.Node; /* OpRegion namespace node */ + if (!Node) + { + break; + } + + ArgOp = Node->Op; /* OpRegion definition */ + ArgOp = ArgOp->Asl.Child; /* First child is the OpRegion Name */ + ArgOp = ArgOp->Asl.Next; /* Next peer is the SPACE_ID (what we want) */ + + /* We are only interested in GeneralPurposeIo and GenericSerialBus */ + + if ((ArgOp->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) && + (ArgOp->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS)) + { + break; + } + + ArgOp = Op->Asl.Child; /* 1st child is the OpRegion Name */ + ArgOp = ArgOp->Asl.Next; /* AccessType */ + ArgOp = ArgOp->Asl.Next; /* LockRule */ + ArgOp = ArgOp->Asl.Next; /* UpdateRule */ + ArgOp = ArgOp->Asl.Next; /* Start of FieldUnitList */ + + /* Walk the FieldUnitList */ + + while (ArgOp) + { + if (ArgOp->Asl.ParseOpcode == PARSEOP_CONNECTION) + { + break; + } + else if (ArgOp->Asl.ParseOpcode == PARSEOP_NAMESEG) + { + AslError (ASL_ERROR, ASL_MSG_CONNECTION_MISSING, ArgOp, NULL); + break; + } + + ArgOp = ArgOp->Asl.Next; + } + break; + + default: + + break; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: AnValidateCreateBufferField + * + * PARAMETERS: Op - A create buffer field operator + * + * RETURN: None + * + * DESCRIPTION: Check if a buffer index argument to a create buffer field + * operation is beyond the end of the target buffer. + * + * Validates these AML operators: + * + * AML_CREATE_FIELD_OP + * AML_CREATE_BIT_FIELD_OP + * AML_CREATE_BYTE_FIELD_OP + * AML_CREATE_WORD_FIELD_OP + * AML_CREATE_DWORD_FIELD_OP + * AML_CREATE_QWORD_FIELD_OP + * + * There are two conditions that must be satisfied in order to enable + * validation at compile time: + * + * 1) The length of the target buffer must be an integer constant + * 2) The index specified in the create* must be an integer constant + * 3) For CreateField, the bit length argument must be non-zero. + * + ******************************************************************************/ + +static void +AnValidateCreateBufferField ( + ACPI_PARSE_OBJECT *CreateBufferFieldOp) +{ + ACPI_PARSE_OBJECT *TargetBufferOp; + ACPI_PARSE_OBJECT *ArgOp; + UINT32 TargetBufferLength; + UINT32 LastFieldByteIndex; + + + /* + * 1) Get the length of the target buffer + */ + ArgOp = CreateBufferFieldOp->Asl.Child; /* Reference to target buffer */ + + /* + * If no attached Node, the target buffer may be something like an + * ArgX or LocalX and cannot be evaluated at compile time. + */ + if (!ArgOp->Asl.Node) + { + return; + } + + TargetBufferOp = ArgOp->Asl.Node->Op; + TargetBufferOp = TargetBufferOp->Asl.Child; /* Target buffer */ + TargetBufferOp = TargetBufferOp->Asl.Next; /* "Buffer" keyword */ + if (!TargetBufferOp) + { + /* Not a statement of the form NAME(XXXX, Buffer.... */ + + return; + } + + /* Get the buffer length argument. It must be an integer constant */ + + ArgOp = TargetBufferOp->Asl.Child; + if (!AnIsValidBufferConstant (ArgOp)) + { + return; + } + + TargetBufferLength = (UINT32) ArgOp->Asl.Value.Integer; + + /* + * 2) Get the value of the buffer index argument. It must be + * an integer constant. + */ + ArgOp = CreateBufferFieldOp->Asl.Child; /* Reference to target buffer */ + ArgOp = ArgOp->Asl.Next; /* Buffer Index argument*/ + if (!AnIsValidBufferConstant (ArgOp)) + { + return; + } + + LastFieldByteIndex = + (UINT32) ArgOp->Asl.Value.Integer; /* Index can be in either bytes or bits */ + + /* + * 3) Get the length of the new buffer field, in bytes. Also, + * create the final target buffer index for the last byte of the field + */ + switch (CreateBufferFieldOp->Asl.ParseOpcode) + { + case PARSEOP_CREATEBITFIELD: /* A one bit field */ + + LastFieldByteIndex = ACPI_ROUND_BITS_DOWN_TO_BYTES (LastFieldByteIndex); + break; + + case PARSEOP_CREATEBYTEFIELD: + break; + + case PARSEOP_CREATEWORDFIELD: + + LastFieldByteIndex += (sizeof (UINT16) - 1); + break; + + case PARSEOP_CREATEDWORDFIELD: + + LastFieldByteIndex += (sizeof (UINT32) - 1); + break; + + case PARSEOP_CREATEQWORDFIELD: + + LastFieldByteIndex += (sizeof (UINT64) - 1); + break; + + case PARSEOP_CREATEFIELD: /* Multi-bit field */ + + ArgOp = ArgOp->Asl.Next; /* Length argument, in bits */ + if (!AnIsValidBufferConstant (ArgOp)) + { + return; + } + + /* The buffer field length is not allowed to be zero */ + + if (ArgOp->Asl.Value.Integer == 0) + { + AslError (ASL_WARNING, ASL_MSG_BUFFER_FIELD_LENGTH, ArgOp, NULL); + return; + } + + LastFieldByteIndex += + ((UINT32) ArgOp->Asl.Value.Integer - 1); /* Create final bit index */ + + /* Convert bit index to a byte index */ + + LastFieldByteIndex = ACPI_ROUND_BITS_DOWN_TO_BYTES (LastFieldByteIndex); + break; + + default: + return; + } + + /* + * 4) Check for an access (index) beyond the end of the target buffer, + * or a zero length target buffer. + */ + if (!TargetBufferLength || (LastFieldByteIndex >= TargetBufferLength)) + { + AslError (ASL_WARNING, ASL_MSG_BUFFER_FIELD_OVERFLOW, ArgOp, NULL); + } +} + + +/******************************************************************************* + * + * FUNCTION: AnIsValidBufferConstant + * + * PARAMETERS: Op - A buffer-related operand + * + * RETURN: TRUE if operand is valid constant, FALSE otherwise + * + * DESCRIPTION: Check if the input Op is valid constant that can be used + * in compile-time analysis. + * + ******************************************************************************/ + +static BOOLEAN +AnIsValidBufferConstant ( + ACPI_PARSE_OBJECT *Op) +{ + if (!Op) + { + return (FALSE); + } + + if ((Op->Asl.ParseOpcode == PARSEOP_INTEGER) || + (Op->Asl.ParseOpcode == PARSEOP_ZERO) || + (Op->Asl.ParseOpcode == PARSEOP_ONE)) + { + return (TRUE); + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: AnAnalyzeStoreOperator + * + * PARAMETERS: Op - Store() operator + * + * RETURN: None + * + * DESCRIPTION: Analyze a store operator. Mostly for stores to/from package + * objects where there are more restrictions than other data + * types. + * + ******************************************************************************/ + +static void +AnAnalyzeStoreOperator ( + ACPI_PARSE_OBJECT *Op) +{ + ACPI_NAMESPACE_NODE *SourceNode; + ACPI_NAMESPACE_NODE *TargetNode; + ACPI_PARSE_OBJECT *SourceOperandOp; + ACPI_PARSE_OBJECT *TargetOperandOp; + UINT32 SourceOperandBtype; + UINT32 TargetOperandBtype; + + + /* Extract the two operands for STORE */ + + SourceOperandOp = Op->Asl.Child; + TargetOperandOp = SourceOperandOp->Asl.Next; + + /* + * Ignore these Source operand opcodes, they cannot be typechecked, + * the actual result is unknown here. + */ + switch (SourceOperandOp->Asl.ParseOpcode) + { + /* For these, type of the returned value is unknown at compile time */ + + case PARSEOP_DEREFOF: + case PARSEOP_METHODCALL: + case PARSEOP_STORE: + case PARSEOP_COPYOBJECT: + + return; + + case PARSEOP_INDEX: + case PARSEOP_REFOF: + + if (!AslGbl_EnableReferenceTypechecking) + { + return; + } + + /* + * These opcodes always return an object reference, and thus + * the result can only be stored to a Local, Arg, or Debug. + */ + if (TargetOperandOp->Asl.AmlOpcode == AML_DEBUG_OP) + { + return; + } + + if ((TargetOperandOp->Asl.AmlOpcode < AML_LOCAL0) || + (TargetOperandOp->Asl.AmlOpcode > AML_ARG6)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, TargetOperandOp, + "Source [Reference], Target must be [Local/Arg/Debug]"); + } + return; + + default: + break; + } + + /* + * Ignore these Target operand opcodes, they cannot be typechecked + */ + switch (TargetOperandOp->Asl.ParseOpcode) + { + case PARSEOP_DEBUG: + case PARSEOP_DEREFOF: + case PARSEOP_REFOF: + case PARSEOP_INDEX: + case PARSEOP_STORE: + + return; + + default: + break; + } + + /* + * Ignore typecheck for External() operands of type "UnknownObj", + * we don't know the actual type (source or target). + */ + SourceNode = SourceOperandOp->Asl.Node; + if (SourceNode && + (SourceNode->Flags & ANOBJ_IS_EXTERNAL) && + (SourceNode->Type == ACPI_TYPE_ANY)) + { + return; + } + + TargetNode = TargetOperandOp->Asl.Node; + if (TargetNode && + (TargetNode->Flags & ANOBJ_IS_EXTERNAL) && + (TargetNode->Type == ACPI_TYPE_ANY)) + { + return; + } + + /* + * A NULL node with a namepath AML opcode indicates non-existent + * name. Just return, the error message is generated elsewhere. + */ + if ((!SourceNode && (SourceOperandOp->Asl.AmlOpcode == AML_INT_NAMEPATH_OP)) || + (!TargetNode && (TargetOperandOp->Asl.AmlOpcode == AML_INT_NAMEPATH_OP))) + { + return; + } + + /* + * Simple check for source same as target via NS node. + * -- Could be expanded to locals and args. + */ + if (SourceNode && TargetNode) + { + if (SourceNode == TargetNode) + { + AslError (ASL_WARNING, ASL_MSG_DUPLICATE_ITEM, + TargetOperandOp, "Source is the same as Target"); + return; + } + } + + /* Ignore typecheck if either source or target is a local or arg */ + + if ((SourceOperandOp->Asl.AmlOpcode >= AML_LOCAL0) && + (SourceOperandOp->Asl.AmlOpcode <= AML_ARG6)) + { + return; /* Cannot type a local/arg at compile time */ + } + + if ((TargetOperandOp->Asl.AmlOpcode >= AML_LOCAL0) && + (TargetOperandOp->Asl.AmlOpcode <= AML_ARG6)) + { + return; /* Cannot type a local/arg at compile time */ + } + + /* + * Package objects are a special case because they cannot by implicitly + * converted to/from anything. Check for these two illegal cases: + * + * Store (non-package, package) + * Store (package, non-package) + */ + SourceOperandBtype = AnGetBtype (SourceOperandOp); + TargetOperandBtype = AnGetBtype (TargetOperandOp); + + /* Check source first for (package, non-package) case */ + + if (SourceOperandBtype & ACPI_BTYPE_PACKAGE) + { + /* If Source is PACKAGE-->Target must be PACKAGE */ + + if (!(TargetOperandBtype & ACPI_BTYPE_PACKAGE)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, TargetOperandOp, + "Source is [Package], Target must be a package also"); + } + } + + /* Else check target for (non-package, package) case */ + + else if (TargetOperandBtype & ACPI_BTYPE_PACKAGE) + { + /* If Target is PACKAGE, Source must be PACKAGE */ + + if (!(SourceOperandBtype & ACPI_BTYPE_PACKAGE)) + { + AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, SourceOperandOp, + "Target is [Package], Source must be a package also"); + } + } +} |