Path: blob/main/sys/contrib/dev/acpica/components/parser/psloop.c
48524 views
/******************************************************************************1*2* Module Name: psloop - Main AML parse loop3*4*****************************************************************************/56/******************************************************************************7*8* 1. Copyright Notice9*10* Some or all of this work - Copyright (c) 1999 - 2025, Intel Corp.11* All rights reserved.12*13* 2. License14*15* 2.1. This is your license from Intel Corp. under its intellectual property16* rights. You may have additional license terms from the party that provided17* you this software, covering your right to use that party's intellectual18* property rights.19*20* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a21* copy of the source code appearing in this file ("Covered Code") an22* irrevocable, perpetual, worldwide license under Intel's copyrights in the23* base code distributed originally by Intel ("Original Intel Code") to copy,24* make derivatives, distribute, use and display any portion of the Covered25* Code in any form, with the right to sublicense such rights; and26*27* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent28* license (with the right to sublicense), under only those claims of Intel29* patents that are infringed by the Original Intel Code, to make, use, sell,30* offer to sell, and import the Covered Code and derivative works thereof31* solely to the minimum extent necessary to exercise the above copyright32* license, and in no event shall the patent license extend to any additions33* to or modifications of the Original Intel Code. No other license or right34* is granted directly or by implication, estoppel or otherwise;35*36* The above copyright and patent license is granted only if the following37* conditions are met:38*39* 3. Conditions40*41* 3.1. Redistribution of Source with Rights to Further Distribute Source.42* Redistribution of source code of any substantial portion of the Covered43* Code or modification with rights to further distribute source must include44* the above Copyright Notice, the above License, this list of Conditions,45* and the following Disclaimer and Export Compliance provision. In addition,46* Licensee must cause all Covered Code to which Licensee contributes to47* contain a file documenting the changes Licensee made to create that Covered48* Code and the date of any change. Licensee must include in that file the49* documentation of any changes made by any predecessor Licensee. Licensee50* must include a prominent statement that the modification is derived,51* directly or indirectly, from Original Intel Code.52*53* 3.2. Redistribution of Source with no Rights to Further Distribute Source.54* Redistribution of source code of any substantial portion of the Covered55* Code or modification without rights to further distribute source must56* include the following Disclaimer and Export Compliance provision in the57* documentation and/or other materials provided with distribution. In58* addition, Licensee may not authorize further sublicense of source of any59* portion of the Covered Code, and must include terms to the effect that the60* license from Licensee to its licensee is limited to the intellectual61* property embodied in the software Licensee provides to its licensee, and62* not to intellectual property embodied in modifications its licensee may63* make.64*65* 3.3. Redistribution of Executable. Redistribution in executable form of any66* substantial portion of the Covered Code or modification must reproduce the67* above Copyright Notice, and the following Disclaimer and Export Compliance68* provision in the documentation and/or other materials provided with the69* distribution.70*71* 3.4. Intel retains all right, title, and interest in and to the Original72* Intel Code.73*74* 3.5. Neither the name Intel nor any other trademark owned or controlled by75* Intel shall be used in advertising or otherwise to promote the sale, use or76* other dealings in products derived from or relating to the Covered Code77* without prior written authorization from Intel.78*79* 4. Disclaimer and Export Compliance80*81* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED82* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE83* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,84* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY85* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY86* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A87* PARTICULAR PURPOSE.88*89* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES90* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR91* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,92* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY93* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL94* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS95* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY96* LIMITED REMEDY.97*98* 4.3. Licensee shall not export, either directly or indirectly, any of this99* software or system incorporating such software without first obtaining any100* required license or other approval from the U. S. Department of Commerce or101* any other agency or department of the United States Government. In the102* event Licensee exports any such software from the United States or103* re-exports any such software from a foreign destination, Licensee shall104* ensure that the distribution and export/re-export of the software is in105* compliance with all laws, regulations, orders, or other restrictions of the106* U.S. Export Administration Regulations. Licensee agrees that neither it nor107* any of its subsidiaries will export/re-export any technical data, process,108* software, or service, directly or indirectly, to any country for which the109* United States government or any agency thereof requires an export license,110* other governmental approval, or letter of assurance, without first obtaining111* such license, approval or letter.112*113*****************************************************************************114*115* Alternatively, you may choose to be licensed under the terms of the116* following license:117*118* Redistribution and use in source and binary forms, with or without119* modification, are permitted provided that the following conditions120* are met:121* 1. Redistributions of source code must retain the above copyright122* notice, this list of conditions, and the following disclaimer,123* without modification.124* 2. Redistributions in binary form must reproduce at minimum a disclaimer125* substantially similar to the "NO WARRANTY" disclaimer below126* ("Disclaimer") and any redistribution must be conditioned upon127* including a substantially similar Disclaimer requirement for further128* binary redistribution.129* 3. Neither the names of the above-listed copyright holders nor the names130* of any contributors may be used to endorse or promote products derived131* from this software without specific prior written permission.132*133* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS134* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT135* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR136* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT137* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,138* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT139* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,140* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY141* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT142* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE143* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.144*145* Alternatively, you may choose to be licensed under the terms of the146* GNU General Public License ("GPL") version 2 as published by the Free147* Software Foundation.148*149*****************************************************************************/150151/*152* Parse the AML and build an operation tree as most interpreters, (such as153* Perl) do. Parsing is done by hand rather than with a YACC generated parser154* to tightly constrain stack and dynamic memory usage. Parsing is kept155* flexible and the code fairly compact by parsing based on a list of AML156* opcode templates in AmlOpInfo[].157*/158159#include <contrib/dev/acpica/include/acpi.h>160#include <contrib/dev/acpica/include/accommon.h>161#include <contrib/dev/acpica/include/acinterp.h>162#include <contrib/dev/acpica/include/acparser.h>163#include <contrib/dev/acpica/include/acdispat.h>164#include <contrib/dev/acpica/include/amlcode.h>165#include <contrib/dev/acpica/include/acconvert.h>166#include <contrib/dev/acpica/include/acnamesp.h>167168#define _COMPONENT ACPI_PARSER169ACPI_MODULE_NAME ("psloop")170171172/* Local prototypes */173174static ACPI_STATUS175AcpiPsGetArguments (176ACPI_WALK_STATE *WalkState,177UINT8 *AmlOpStart,178ACPI_PARSE_OBJECT *Op);179180181/*******************************************************************************182*183* FUNCTION: AcpiPsGetArguments184*185* PARAMETERS: WalkState - Current state186* AmlOpStart - Op start in AML187* Op - Current Op188*189* RETURN: Status190*191* DESCRIPTION: Get arguments for passed Op.192*193******************************************************************************/194195static ACPI_STATUS196AcpiPsGetArguments (197ACPI_WALK_STATE *WalkState,198UINT8 *AmlOpStart,199ACPI_PARSE_OBJECT *Op)200{201ACPI_STATUS Status = AE_OK;202ACPI_PARSE_OBJECT *Arg = NULL;203204205ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState);206207208ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,209"Get arguments for opcode [%s]\n", Op->Common.AmlOpName));210211switch (Op->Common.AmlOpcode)212{213case AML_BYTE_OP: /* AML_BYTEDATA_ARG */214case AML_WORD_OP: /* AML_WORDDATA_ARG */215case AML_DWORD_OP: /* AML_DWORDATA_ARG */216case AML_QWORD_OP: /* AML_QWORDATA_ARG */217case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */218219/* Fill in constant or string argument directly */220221AcpiPsGetNextSimpleArg (&(WalkState->ParserState),222GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op);223break;224225case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */226227Status = AcpiPsGetNextNamepath (WalkState,228&(WalkState->ParserState), Op, ACPI_POSSIBLE_METHOD_CALL);229if (ACPI_FAILURE (Status))230{231return_ACPI_STATUS (Status);232}233234WalkState->ArgTypes = 0;235break;236237default:238/*239* Op is not a constant or string, append each argument to the Op240*/241while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) &&242!WalkState->ArgCount)243{244WalkState->Aml = WalkState->ParserState.Aml;245246switch (Op->Common.AmlOpcode)247{248case AML_METHOD_OP:249case AML_BUFFER_OP:250case AML_PACKAGE_OP:251case AML_VARIABLE_PACKAGE_OP:252case AML_WHILE_OP:253254break;255256default:257258ASL_CV_CAPTURE_COMMENTS (WalkState);259break;260}261262Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState),263GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg);264if (ACPI_FAILURE (Status))265{266return_ACPI_STATUS (Status);267}268269if (Arg)270{271AcpiPsAppendArg (Op, Arg);272}273274INCREMENT_ARG_LIST (WalkState->ArgTypes);275}276277ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,278"Final argument count: %8.8X pass %u\n",279WalkState->ArgCount, WalkState->PassNumber));280281/* Special processing for certain opcodes */282283switch (Op->Common.AmlOpcode)284{285case AML_METHOD_OP:286/*287* Skip parsing of control method because we don't have enough288* info in the first pass to parse it correctly.289*290* Save the length and address of the body291*/292Op->Named.Data = WalkState->ParserState.Aml;293Op->Named.Length = (UINT32)294(WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml);295296/* Skip body of method */297298WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;299WalkState->ArgCount = 0;300break;301302case AML_BUFFER_OP:303case AML_PACKAGE_OP:304case AML_VARIABLE_PACKAGE_OP:305306if ((Op->Common.Parent) &&307(Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&308(WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))309{310ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,311"Setup Package/Buffer: Pass %u, AML Ptr: %p\n",312WalkState->PassNumber, AmlOpStart));313314/*315* Skip parsing of Buffers and Packages because we don't have316* enough info in the first pass to parse them correctly.317*/318Op->Named.Data = AmlOpStart;319Op->Named.Length = (UINT32)320(WalkState->ParserState.PkgEnd - AmlOpStart);321322/* Skip body */323324WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;325WalkState->ArgCount = 0;326}327break;328329case AML_WHILE_OP:330331if (WalkState->ControlState)332{333WalkState->ControlState->Control.PackageEnd =334WalkState->ParserState.PkgEnd;335}336break;337338default:339340/* No action for all other opcodes */341342break;343}344345break;346}347348return_ACPI_STATUS (AE_OK);349}350351352/*******************************************************************************353*354* FUNCTION: AcpiPsParseLoop355*356* PARAMETERS: WalkState - Current state357*358* RETURN: Status359*360* DESCRIPTION: Parse AML (pointed to by the current parser state) and return361* a tree of ops.362*363******************************************************************************/364365ACPI_STATUS366AcpiPsParseLoop (367ACPI_WALK_STATE *WalkState)368{369ACPI_STATUS Status = AE_OK;370ACPI_PARSE_OBJECT *Op = NULL; /* current op */371ACPI_PARSE_STATE *ParserState;372UINT8 *AmlOpStart = NULL;373UINT8 OpcodeLength;374375376ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState);377378379if (WalkState->DescendingCallback == NULL)380{381return_ACPI_STATUS (AE_BAD_PARAMETER);382}383384ParserState = &WalkState->ParserState;385WalkState->ArgTypes = 0;386387#ifndef ACPI_CONSTANT_EVAL_ONLY388389if (WalkState->WalkType & ACPI_WALK_METHOD_RESTART)390{391/* We are restarting a preempted control method */392393if (AcpiPsHasCompletedScope (ParserState))394{395/*396* We must check if a predicate to an IF or WHILE statement397* was just completed398*/399if ((ParserState->Scope->ParseScope.Op) &&400((ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_IF_OP) ||401(ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) &&402(WalkState->ControlState) &&403(WalkState->ControlState->Common.State ==404ACPI_CONTROL_PREDICATE_EXECUTING))405{406/*407* A predicate was just completed, get the value of the408* predicate and branch based on that value409*/410WalkState->Op = NULL;411Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE));412if (ACPI_FAILURE (Status) && !ACPI_CNTL_EXCEPTION (Status))413{414if (Status == AE_AML_NO_RETURN_VALUE)415{416ACPI_EXCEPTION ((AE_INFO, Status,417"Invoked method did not return a value"));418}419420ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed"));421return_ACPI_STATUS (Status);422}423424Status = AcpiPsNextParseState (WalkState, Op, Status);425}426427AcpiPsPopScope (ParserState, &Op,428&WalkState->ArgTypes, &WalkState->ArgCount);429ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op));430}431else if (WalkState->PrevOp)432{433/* We were in the middle of an op */434435Op = WalkState->PrevOp;436WalkState->ArgTypes = WalkState->PrevArgTypes;437}438}439#endif440441/* Iterative parsing loop, while there is more AML to process: */442443while ((ParserState->Aml < ParserState->AmlEnd) || (Op))444{445ASL_CV_CAPTURE_COMMENTS (WalkState);446447AmlOpStart = ParserState->Aml;448if (!Op)449{450Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op);451if (ACPI_FAILURE (Status))452{453/*454* ACPI_PARSE_MODULE_LEVEL means that we are loading a table by455* executing it as a control method. However, if we encounter456* an error while loading the table, we need to keep trying to457* load the table rather than aborting the table load. Set the458* status to AE_OK to proceed with the table load.459*/460if ((WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL) &&461((Status == AE_ALREADY_EXISTS) || (Status == AE_NOT_FOUND)))462{463Status = AE_OK;464}465if (Status == AE_CTRL_PARSE_CONTINUE)466{467continue;468}469470if (Status == AE_CTRL_PARSE_PENDING)471{472Status = AE_OK;473}474475if (Status == AE_CTRL_TERMINATE)476{477return_ACPI_STATUS (Status);478}479480Status = AcpiPsCompleteOp (WalkState, &Op, Status);481if (ACPI_FAILURE (Status))482{483return_ACPI_STATUS (Status);484}485if (AcpiNsOpensScope (486AcpiPsGetOpcodeInfo (WalkState->Opcode)->ObjectType))487{488/*489* If the scope/device op fails to parse, skip the body of490* the scope op because the parse failure indicates that491* the device may not exist.492*/493ACPI_INFO (("Skipping parse of AML opcode: %s (0x%4.4X)",494AcpiPsGetOpcodeName (WalkState->Opcode), WalkState->Opcode));495496/*497* Determine the opcode length before skipping the opcode.498* An opcode can be 1 byte or 2 bytes in length.499*/500OpcodeLength = 1;501if ((WalkState->Opcode & 0xFF00) == AML_EXTENDED_OPCODE)502{503OpcodeLength = 2;504}505WalkState->ParserState.Aml = WalkState->Aml + OpcodeLength;506507WalkState->ParserState.Aml =508AcpiPsGetNextPackageEnd(&WalkState->ParserState);509WalkState->Aml = WalkState->ParserState.Aml;510}511512continue;513}514515AcpiExStartTraceOpcode (Op, WalkState);516}517518/*519* Start ArgCount at zero because we don't know if there are520* any args yet521*/522WalkState->ArgCount = 0;523524switch (Op->Common.AmlOpcode)525{526case AML_BYTE_OP:527case AML_WORD_OP:528case AML_DWORD_OP:529case AML_QWORD_OP:530531break;532533default:534535ASL_CV_CAPTURE_COMMENTS (WalkState);536break;537}538539/* Are there any arguments that must be processed? */540541if (WalkState->ArgTypes)542{543/* Get arguments */544545Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op);546if (ACPI_FAILURE (Status))547{548Status = AcpiPsCompleteOp (WalkState, &Op, Status);549if (ACPI_FAILURE (Status))550{551return_ACPI_STATUS (Status);552}553if ((WalkState->ControlState) &&554((WalkState->ControlState->Control.Opcode == AML_IF_OP) ||555(WalkState->ControlState->Control.Opcode == AML_WHILE_OP)))556{557/*558* If the if/while op fails to parse, we will skip parsing559* the body of the op.560*/561ParserState->Aml =562WalkState->ControlState->Control.AmlPredicateStart + 1;563ParserState->Aml =564AcpiPsGetNextPackageEnd (ParserState);565WalkState->Aml = ParserState->Aml;566567ACPI_ERROR ((AE_INFO, "Skipping While/If block"));568if (*WalkState->Aml == AML_ELSE_OP)569{570ACPI_ERROR ((AE_INFO, "Skipping Else block"));571WalkState->ParserState.Aml = WalkState->Aml + 1;572WalkState->ParserState.Aml =573AcpiPsGetNextPackageEnd (ParserState);574WalkState->Aml = ParserState->Aml;575}576ACPI_FREE(AcpiUtPopGenericState (&WalkState->ControlState));577}578Op = NULL;579continue;580}581}582583/* Check for arguments that need to be processed */584585ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,586"Parseloop: argument count: %8.8X\n", WalkState->ArgCount));587588if (WalkState->ArgCount)589{590/*591* There are arguments (complex ones), push Op and592* prepare for argument593*/594Status = AcpiPsPushScope (ParserState, Op,595WalkState->ArgTypes, WalkState->ArgCount);596if (ACPI_FAILURE (Status))597{598Status = AcpiPsCompleteOp (WalkState, &Op, Status);599if (ACPI_FAILURE (Status))600{601return_ACPI_STATUS (Status);602}603604continue;605}606607Op = NULL;608continue;609}610611/*612* All arguments have been processed -- Op is complete,613* prepare for next614*/615WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);616if (WalkState->OpInfo->Flags & AML_NAMED)617{618if (Op->Common.AmlOpcode == AML_REGION_OP ||619Op->Common.AmlOpcode == AML_DATA_REGION_OP)620{621/*622* Skip parsing of control method or opregion body,623* because we don't have enough info in the first pass624* to parse them correctly.625*626* Completed parsing an OpRegion declaration, we now627* know the length.628*/629Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);630}631}632633if (WalkState->OpInfo->Flags & AML_CREATE)634{635/*636* Backup to beginning of CreateXXXfield declaration (1 for637* Opcode)638*639* BodyLength is unknown until we parse the body640*/641Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);642}643644if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP)645{646/*647* Backup to beginning of BankField declaration648*649* BodyLength is unknown until we parse the body650*/651Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);652}653654/* This op complete, notify the dispatcher */655656if (WalkState->AscendingCallback != NULL)657{658WalkState->Op = Op;659WalkState->Opcode = Op->Common.AmlOpcode;660661Status = WalkState->AscendingCallback (WalkState);662Status = AcpiPsNextParseState (WalkState, Op, Status);663if (Status == AE_CTRL_PENDING)664{665Status = AE_OK;666}667else if ((WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL) &&668(ACPI_AML_EXCEPTION(Status) || Status == AE_ALREADY_EXISTS ||669Status == AE_NOT_FOUND))670{671/*672* ACPI_PARSE_MODULE_LEVEL flag means that we are currently673* loading a table by executing it as a control method.674* However, if we encounter an error while loading the table,675* we need to keep trying to load the table rather than676* aborting the table load (setting the status to AE_OK677* continues the table load). If we get a failure at this678* point, it means that the dispatcher got an error while679* trying to execute the Op.680*/681Status = AE_OK;682}683}684685Status = AcpiPsCompleteOp (WalkState, &Op, Status);686if (ACPI_FAILURE (Status))687{688return_ACPI_STATUS (Status);689}690691} /* while ParserState->Aml */692693Status = AcpiPsCompleteFinalOp (WalkState, Op, Status);694return_ACPI_STATUS (Status);695}696697698