195b482a8SLen Brown /****************************************************************************** 295b482a8SLen Brown * 395b482a8SLen Brown * Module Name: psloop - Main AML parse loop 495b482a8SLen Brown * 595b482a8SLen Brown *****************************************************************************/ 695b482a8SLen Brown 795b482a8SLen Brown /* 895b482a8SLen Brown * Copyright (C) 2000 - 2008, Intel Corp. 995b482a8SLen Brown * All rights reserved. 1095b482a8SLen Brown * 1195b482a8SLen Brown * Redistribution and use in source and binary forms, with or without 1295b482a8SLen Brown * modification, are permitted provided that the following conditions 1395b482a8SLen Brown * are met: 1495b482a8SLen Brown * 1. Redistributions of source code must retain the above copyright 1595b482a8SLen Brown * notice, this list of conditions, and the following disclaimer, 1695b482a8SLen Brown * without modification. 1795b482a8SLen Brown * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1895b482a8SLen Brown * substantially similar to the "NO WARRANTY" disclaimer below 1995b482a8SLen Brown * ("Disclaimer") and any redistribution must be conditioned upon 2095b482a8SLen Brown * including a substantially similar Disclaimer requirement for further 2195b482a8SLen Brown * binary redistribution. 2295b482a8SLen Brown * 3. Neither the names of the above-listed copyright holders nor the names 2395b482a8SLen Brown * of any contributors may be used to endorse or promote products derived 2495b482a8SLen Brown * from this software without specific prior written permission. 2595b482a8SLen Brown * 2695b482a8SLen Brown * Alternatively, this software may be distributed under the terms of the 2795b482a8SLen Brown * GNU General Public License ("GPL") version 2 as published by the Free 2895b482a8SLen Brown * Software Foundation. 2995b482a8SLen Brown * 3095b482a8SLen Brown * NO WARRANTY 3195b482a8SLen Brown * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3295b482a8SLen Brown * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3395b482a8SLen Brown * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3495b482a8SLen Brown * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3595b482a8SLen Brown * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3695b482a8SLen Brown * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3795b482a8SLen Brown * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3895b482a8SLen Brown * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3995b482a8SLen Brown * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4095b482a8SLen Brown * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4195b482a8SLen Brown * POSSIBILITY OF SUCH DAMAGES. 4295b482a8SLen Brown */ 4395b482a8SLen Brown 4495b482a8SLen Brown /* 4595b482a8SLen Brown * Parse the AML and build an operation tree as most interpreters, (such as 4695b482a8SLen Brown * Perl) do. Parsing is done by hand rather than with a YACC generated parser 4795b482a8SLen Brown * to tightly constrain stack and dynamic memory usage. Parsing is kept 4895b482a8SLen Brown * flexible and the code fairly compact by parsing based on a list of AML 4995b482a8SLen Brown * opcode templates in aml_op_info[]. 5095b482a8SLen Brown */ 5195b482a8SLen Brown 5295b482a8SLen Brown #include <acpi/acpi.h> 53*e2f7a777SLen Brown #include "accommon.h" 54*e2f7a777SLen Brown #include "acparser.h" 55*e2f7a777SLen Brown #include "acdispat.h" 56*e2f7a777SLen Brown #include "amlcode.h" 5795b482a8SLen Brown 5895b482a8SLen Brown #define _COMPONENT ACPI_PARSER 5995b482a8SLen Brown ACPI_MODULE_NAME("psloop") 6095b482a8SLen Brown 6195b482a8SLen Brown static u32 acpi_gbl_depth = 0; 6295b482a8SLen Brown 6395b482a8SLen Brown /* Local prototypes */ 6495b482a8SLen Brown 6595b482a8SLen Brown static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state); 6695b482a8SLen Brown 6795b482a8SLen Brown static acpi_status 6895b482a8SLen Brown acpi_ps_build_named_op(struct acpi_walk_state *walk_state, 6995b482a8SLen Brown u8 * aml_op_start, 7095b482a8SLen Brown union acpi_parse_object *unnamed_op, 7195b482a8SLen Brown union acpi_parse_object **op); 7295b482a8SLen Brown 7395b482a8SLen Brown static acpi_status 7495b482a8SLen Brown acpi_ps_create_op(struct acpi_walk_state *walk_state, 7595b482a8SLen Brown u8 * aml_op_start, union acpi_parse_object **new_op); 7695b482a8SLen Brown 7795b482a8SLen Brown static acpi_status 7895b482a8SLen Brown acpi_ps_get_arguments(struct acpi_walk_state *walk_state, 7995b482a8SLen Brown u8 * aml_op_start, union acpi_parse_object *op); 8095b482a8SLen Brown 8195b482a8SLen Brown static acpi_status 8295b482a8SLen Brown acpi_ps_complete_op(struct acpi_walk_state *walk_state, 8395b482a8SLen Brown union acpi_parse_object **op, acpi_status status); 8495b482a8SLen Brown 8595b482a8SLen Brown static acpi_status 8695b482a8SLen Brown acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, 8795b482a8SLen Brown union acpi_parse_object *op, acpi_status status); 8895b482a8SLen Brown 8995b482a8SLen Brown /******************************************************************************* 9095b482a8SLen Brown * 9195b482a8SLen Brown * FUNCTION: acpi_ps_get_aml_opcode 9295b482a8SLen Brown * 9395b482a8SLen Brown * PARAMETERS: walk_state - Current state 9495b482a8SLen Brown * 9595b482a8SLen Brown * RETURN: Status 9695b482a8SLen Brown * 9795b482a8SLen Brown * DESCRIPTION: Extract the next AML opcode from the input stream. 9895b482a8SLen Brown * 9995b482a8SLen Brown ******************************************************************************/ 10095b482a8SLen Brown 10195b482a8SLen Brown static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) 10295b482a8SLen Brown { 10395b482a8SLen Brown 10495b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state); 10595b482a8SLen Brown 10695b482a8SLen Brown walk_state->aml_offset = 10795b482a8SLen Brown (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, 10895b482a8SLen Brown walk_state->parser_state.aml_start); 10995b482a8SLen Brown walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state)); 11095b482a8SLen Brown 11195b482a8SLen Brown /* 11295b482a8SLen Brown * First cut to determine what we have found: 11395b482a8SLen Brown * 1) A valid AML opcode 11495b482a8SLen Brown * 2) A name string 11595b482a8SLen Brown * 3) An unknown/invalid opcode 11695b482a8SLen Brown */ 11795b482a8SLen Brown walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); 11895b482a8SLen Brown 11995b482a8SLen Brown switch (walk_state->op_info->class) { 12095b482a8SLen Brown case AML_CLASS_ASCII: 12195b482a8SLen Brown case AML_CLASS_PREFIX: 12295b482a8SLen Brown /* 12395b482a8SLen Brown * Starts with a valid prefix or ASCII char, this is a name 12495b482a8SLen Brown * string. Convert the bare name string to a namepath. 12595b482a8SLen Brown */ 12695b482a8SLen Brown walk_state->opcode = AML_INT_NAMEPATH_OP; 12795b482a8SLen Brown walk_state->arg_types = ARGP_NAMESTRING; 12895b482a8SLen Brown break; 12995b482a8SLen Brown 13095b482a8SLen Brown case AML_CLASS_UNKNOWN: 13195b482a8SLen Brown 13295b482a8SLen Brown /* The opcode is unrecognized. Just skip unknown opcodes */ 13395b482a8SLen Brown 13495b482a8SLen Brown ACPI_ERROR((AE_INFO, 13595b482a8SLen Brown "Found unknown opcode %X at AML address %p offset %X, ignoring", 13695b482a8SLen Brown walk_state->opcode, walk_state->parser_state.aml, 13795b482a8SLen Brown walk_state->aml_offset)); 13895b482a8SLen Brown 13995b482a8SLen Brown ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); 14095b482a8SLen Brown 14195b482a8SLen Brown /* Assume one-byte bad opcode */ 14295b482a8SLen Brown 14395b482a8SLen Brown walk_state->parser_state.aml++; 14495b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); 14595b482a8SLen Brown 14695b482a8SLen Brown default: 14795b482a8SLen Brown 14895b482a8SLen Brown /* Found opcode info, this is a normal opcode */ 14995b482a8SLen Brown 15095b482a8SLen Brown walk_state->parser_state.aml += 15195b482a8SLen Brown acpi_ps_get_opcode_size(walk_state->opcode); 15295b482a8SLen Brown walk_state->arg_types = walk_state->op_info->parse_args; 15395b482a8SLen Brown break; 15495b482a8SLen Brown } 15595b482a8SLen Brown 15695b482a8SLen Brown return_ACPI_STATUS(AE_OK); 15795b482a8SLen Brown } 15895b482a8SLen Brown 15995b482a8SLen Brown /******************************************************************************* 16095b482a8SLen Brown * 16195b482a8SLen Brown * FUNCTION: acpi_ps_build_named_op 16295b482a8SLen Brown * 16395b482a8SLen Brown * PARAMETERS: walk_state - Current state 16495b482a8SLen Brown * aml_op_start - Begin of named Op in AML 16595b482a8SLen Brown * unnamed_op - Early Op (not a named Op) 16695b482a8SLen Brown * Op - Returned Op 16795b482a8SLen Brown * 16895b482a8SLen Brown * RETURN: Status 16995b482a8SLen Brown * 17095b482a8SLen Brown * DESCRIPTION: Parse a named Op 17195b482a8SLen Brown * 17295b482a8SLen Brown ******************************************************************************/ 17395b482a8SLen Brown 17495b482a8SLen Brown static acpi_status 17595b482a8SLen Brown acpi_ps_build_named_op(struct acpi_walk_state *walk_state, 17695b482a8SLen Brown u8 * aml_op_start, 17795b482a8SLen Brown union acpi_parse_object *unnamed_op, 17895b482a8SLen Brown union acpi_parse_object **op) 17995b482a8SLen Brown { 18095b482a8SLen Brown acpi_status status = AE_OK; 18195b482a8SLen Brown union acpi_parse_object *arg = NULL; 18295b482a8SLen Brown 18395b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); 18495b482a8SLen Brown 18595b482a8SLen Brown unnamed_op->common.value.arg = NULL; 18695b482a8SLen Brown unnamed_op->common.arg_list_length = 0; 18795b482a8SLen Brown unnamed_op->common.aml_opcode = walk_state->opcode; 18895b482a8SLen Brown 18995b482a8SLen Brown /* 19095b482a8SLen Brown * Get and append arguments until we find the node that contains 19195b482a8SLen Brown * the name (the type ARGP_NAME). 19295b482a8SLen Brown */ 19395b482a8SLen Brown while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && 19495b482a8SLen Brown (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) { 19595b482a8SLen Brown status = 19695b482a8SLen Brown acpi_ps_get_next_arg(walk_state, 19795b482a8SLen Brown &(walk_state->parser_state), 19895b482a8SLen Brown GET_CURRENT_ARG_TYPE(walk_state-> 19995b482a8SLen Brown arg_types), &arg); 20095b482a8SLen Brown if (ACPI_FAILURE(status)) { 20195b482a8SLen Brown return_ACPI_STATUS(status); 20295b482a8SLen Brown } 20395b482a8SLen Brown 20495b482a8SLen Brown acpi_ps_append_arg(unnamed_op, arg); 20595b482a8SLen Brown INCREMENT_ARG_LIST(walk_state->arg_types); 20695b482a8SLen Brown } 20795b482a8SLen Brown 20895b482a8SLen Brown /* 20995b482a8SLen Brown * Make sure that we found a NAME and didn't run out of arguments 21095b482a8SLen Brown */ 21195b482a8SLen Brown if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) { 21295b482a8SLen Brown return_ACPI_STATUS(AE_AML_NO_OPERAND); 21395b482a8SLen Brown } 21495b482a8SLen Brown 21595b482a8SLen Brown /* We know that this arg is a name, move to next arg */ 21695b482a8SLen Brown 21795b482a8SLen Brown INCREMENT_ARG_LIST(walk_state->arg_types); 21895b482a8SLen Brown 21995b482a8SLen Brown /* 22095b482a8SLen Brown * Find the object. This will either insert the object into 22195b482a8SLen Brown * the namespace or simply look it up 22295b482a8SLen Brown */ 22395b482a8SLen Brown walk_state->op = NULL; 22495b482a8SLen Brown 22595b482a8SLen Brown status = walk_state->descending_callback(walk_state, op); 22695b482a8SLen Brown if (ACPI_FAILURE(status)) { 22795b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog")); 22895b482a8SLen Brown return_ACPI_STATUS(status); 22995b482a8SLen Brown } 23095b482a8SLen Brown 23195b482a8SLen Brown if (!*op) { 23295b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); 23395b482a8SLen Brown } 23495b482a8SLen Brown 23595b482a8SLen Brown status = acpi_ps_next_parse_state(walk_state, *op, status); 23695b482a8SLen Brown if (ACPI_FAILURE(status)) { 23795b482a8SLen Brown if (status == AE_CTRL_PENDING) { 23895b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_PENDING); 23995b482a8SLen Brown } 24095b482a8SLen Brown return_ACPI_STATUS(status); 24195b482a8SLen Brown } 24295b482a8SLen Brown 24395b482a8SLen Brown acpi_ps_append_arg(*op, unnamed_op->common.value.arg); 24495b482a8SLen Brown acpi_gbl_depth++; 24595b482a8SLen Brown 24695b482a8SLen Brown if ((*op)->common.aml_opcode == AML_REGION_OP || 24795b482a8SLen Brown (*op)->common.aml_opcode == AML_DATA_REGION_OP) { 24895b482a8SLen Brown /* 24995b482a8SLen Brown * Defer final parsing of an operation_region body, because we don't 25095b482a8SLen Brown * have enough info in the first pass to parse it correctly (i.e., 25195b482a8SLen Brown * there may be method calls within the term_arg elements of the body.) 25295b482a8SLen Brown * 25395b482a8SLen Brown * However, we must continue parsing because the opregion is not a 25495b482a8SLen Brown * standalone package -- we don't know where the end is at this point. 25595b482a8SLen Brown * 25695b482a8SLen Brown * (Length is unknown until parse of the body complete) 25795b482a8SLen Brown */ 25895b482a8SLen Brown (*op)->named.data = aml_op_start; 25995b482a8SLen Brown (*op)->named.length = 0; 26095b482a8SLen Brown } 26195b482a8SLen Brown 26295b482a8SLen Brown return_ACPI_STATUS(AE_OK); 26395b482a8SLen Brown } 26495b482a8SLen Brown 26595b482a8SLen Brown /******************************************************************************* 26695b482a8SLen Brown * 26795b482a8SLen Brown * FUNCTION: acpi_ps_create_op 26895b482a8SLen Brown * 26995b482a8SLen Brown * PARAMETERS: walk_state - Current state 27095b482a8SLen Brown * aml_op_start - Op start in AML 27195b482a8SLen Brown * new_op - Returned Op 27295b482a8SLen Brown * 27395b482a8SLen Brown * RETURN: Status 27495b482a8SLen Brown * 27595b482a8SLen Brown * DESCRIPTION: Get Op from AML 27695b482a8SLen Brown * 27795b482a8SLen Brown ******************************************************************************/ 27895b482a8SLen Brown 27995b482a8SLen Brown static acpi_status 28095b482a8SLen Brown acpi_ps_create_op(struct acpi_walk_state *walk_state, 28195b482a8SLen Brown u8 * aml_op_start, union acpi_parse_object **new_op) 28295b482a8SLen Brown { 28395b482a8SLen Brown acpi_status status = AE_OK; 28495b482a8SLen Brown union acpi_parse_object *op; 28595b482a8SLen Brown union acpi_parse_object *named_op = NULL; 28695b482a8SLen Brown union acpi_parse_object *parent_scope; 28795b482a8SLen Brown u8 argument_count; 28895b482a8SLen Brown const struct acpi_opcode_info *op_info; 28995b482a8SLen Brown 29095b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); 29195b482a8SLen Brown 29295b482a8SLen Brown status = acpi_ps_get_aml_opcode(walk_state); 29395b482a8SLen Brown if (status == AE_CTRL_PARSE_CONTINUE) { 29495b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); 29595b482a8SLen Brown } 29695b482a8SLen Brown 29795b482a8SLen Brown /* Create Op structure and append to parent's argument list */ 29895b482a8SLen Brown 29995b482a8SLen Brown walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); 30095b482a8SLen Brown op = acpi_ps_alloc_op(walk_state->opcode); 30195b482a8SLen Brown if (!op) { 30295b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY); 30395b482a8SLen Brown } 30495b482a8SLen Brown 30595b482a8SLen Brown if (walk_state->op_info->flags & AML_NAMED) { 30695b482a8SLen Brown status = 30795b482a8SLen Brown acpi_ps_build_named_op(walk_state, aml_op_start, op, 30895b482a8SLen Brown &named_op); 30995b482a8SLen Brown acpi_ps_free_op(op); 31095b482a8SLen Brown if (ACPI_FAILURE(status)) { 31195b482a8SLen Brown return_ACPI_STATUS(status); 31295b482a8SLen Brown } 31395b482a8SLen Brown 31495b482a8SLen Brown *new_op = named_op; 31595b482a8SLen Brown return_ACPI_STATUS(AE_OK); 31695b482a8SLen Brown } 31795b482a8SLen Brown 31895b482a8SLen Brown /* Not a named opcode, just allocate Op and append to parent */ 31995b482a8SLen Brown 32095b482a8SLen Brown if (walk_state->op_info->flags & AML_CREATE) { 32195b482a8SLen Brown /* 32295b482a8SLen Brown * Backup to beginning of create_xXXfield declaration 32395b482a8SLen Brown * body_length is unknown until we parse the body 32495b482a8SLen Brown */ 32595b482a8SLen Brown op->named.data = aml_op_start; 32695b482a8SLen Brown op->named.length = 0; 32795b482a8SLen Brown } 32895b482a8SLen Brown 32995b482a8SLen Brown if (walk_state->opcode == AML_BANK_FIELD_OP) { 33095b482a8SLen Brown /* 33195b482a8SLen Brown * Backup to beginning of bank_field declaration 33295b482a8SLen Brown * body_length is unknown until we parse the body 33395b482a8SLen Brown */ 33495b482a8SLen Brown op->named.data = aml_op_start; 33595b482a8SLen Brown op->named.length = 0; 33695b482a8SLen Brown } 33795b482a8SLen Brown 33895b482a8SLen Brown parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state)); 33995b482a8SLen Brown acpi_ps_append_arg(parent_scope, op); 34095b482a8SLen Brown 34195b482a8SLen Brown if (parent_scope) { 34295b482a8SLen Brown op_info = 34395b482a8SLen Brown acpi_ps_get_opcode_info(parent_scope->common.aml_opcode); 34495b482a8SLen Brown if (op_info->flags & AML_HAS_TARGET) { 34595b482a8SLen Brown argument_count = 34695b482a8SLen Brown acpi_ps_get_argument_count(op_info->type); 34795b482a8SLen Brown if (parent_scope->common.arg_list_length > 34895b482a8SLen Brown argument_count) { 34995b482a8SLen Brown op->common.flags |= ACPI_PARSEOP_TARGET; 35095b482a8SLen Brown } 35195b482a8SLen Brown } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) { 35295b482a8SLen Brown op->common.flags |= ACPI_PARSEOP_TARGET; 35395b482a8SLen Brown } 35495b482a8SLen Brown } 35595b482a8SLen Brown 35695b482a8SLen Brown if (walk_state->descending_callback != NULL) { 35795b482a8SLen Brown /* 35895b482a8SLen Brown * Find the object. This will either insert the object into 35995b482a8SLen Brown * the namespace or simply look it up 36095b482a8SLen Brown */ 36195b482a8SLen Brown walk_state->op = *new_op = op; 36295b482a8SLen Brown 36395b482a8SLen Brown status = walk_state->descending_callback(walk_state, &op); 36495b482a8SLen Brown status = acpi_ps_next_parse_state(walk_state, op, status); 36595b482a8SLen Brown if (status == AE_CTRL_PENDING) { 36695b482a8SLen Brown status = AE_CTRL_PARSE_PENDING; 36795b482a8SLen Brown } 36895b482a8SLen Brown } 36995b482a8SLen Brown 37095b482a8SLen Brown return_ACPI_STATUS(status); 37195b482a8SLen Brown } 37295b482a8SLen Brown 37395b482a8SLen Brown /******************************************************************************* 37495b482a8SLen Brown * 37595b482a8SLen Brown * FUNCTION: acpi_ps_get_arguments 37695b482a8SLen Brown * 37795b482a8SLen Brown * PARAMETERS: walk_state - Current state 37895b482a8SLen Brown * aml_op_start - Op start in AML 37995b482a8SLen Brown * Op - Current Op 38095b482a8SLen Brown * 38195b482a8SLen Brown * RETURN: Status 38295b482a8SLen Brown * 38395b482a8SLen Brown * DESCRIPTION: Get arguments for passed Op. 38495b482a8SLen Brown * 38595b482a8SLen Brown ******************************************************************************/ 38695b482a8SLen Brown 38795b482a8SLen Brown static acpi_status 38895b482a8SLen Brown acpi_ps_get_arguments(struct acpi_walk_state *walk_state, 38995b482a8SLen Brown u8 * aml_op_start, union acpi_parse_object *op) 39095b482a8SLen Brown { 39195b482a8SLen Brown acpi_status status = AE_OK; 39295b482a8SLen Brown union acpi_parse_object *arg = NULL; 39395b482a8SLen Brown 39495b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); 39595b482a8SLen Brown 39695b482a8SLen Brown switch (op->common.aml_opcode) { 39795b482a8SLen Brown case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ 39895b482a8SLen Brown case AML_WORD_OP: /* AML_WORDDATA_ARG */ 39995b482a8SLen Brown case AML_DWORD_OP: /* AML_DWORDATA_ARG */ 40095b482a8SLen Brown case AML_QWORD_OP: /* AML_QWORDATA_ARG */ 40195b482a8SLen Brown case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ 40295b482a8SLen Brown 40395b482a8SLen Brown /* Fill in constant or string argument directly */ 40495b482a8SLen Brown 40595b482a8SLen Brown acpi_ps_get_next_simple_arg(&(walk_state->parser_state), 40695b482a8SLen Brown GET_CURRENT_ARG_TYPE(walk_state-> 40795b482a8SLen Brown arg_types), 40895b482a8SLen Brown op); 40995b482a8SLen Brown break; 41095b482a8SLen Brown 41195b482a8SLen Brown case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ 41295b482a8SLen Brown 41395b482a8SLen Brown status = 41495b482a8SLen Brown acpi_ps_get_next_namepath(walk_state, 41595b482a8SLen Brown &(walk_state->parser_state), op, 41695b482a8SLen Brown 1); 41795b482a8SLen Brown if (ACPI_FAILURE(status)) { 41895b482a8SLen Brown return_ACPI_STATUS(status); 41995b482a8SLen Brown } 42095b482a8SLen Brown 42195b482a8SLen Brown walk_state->arg_types = 0; 42295b482a8SLen Brown break; 42395b482a8SLen Brown 42495b482a8SLen Brown default: 42595b482a8SLen Brown /* 42695b482a8SLen Brown * Op is not a constant or string, append each argument to the Op 42795b482a8SLen Brown */ 42895b482a8SLen Brown while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) 42995b482a8SLen Brown && !walk_state->arg_count) { 43095b482a8SLen Brown walk_state->aml_offset = 43195b482a8SLen Brown (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, 43295b482a8SLen Brown walk_state->parser_state. 43395b482a8SLen Brown aml_start); 43495b482a8SLen Brown 43595b482a8SLen Brown status = 43695b482a8SLen Brown acpi_ps_get_next_arg(walk_state, 43795b482a8SLen Brown &(walk_state->parser_state), 43895b482a8SLen Brown GET_CURRENT_ARG_TYPE 43995b482a8SLen Brown (walk_state->arg_types), &arg); 44095b482a8SLen Brown if (ACPI_FAILURE(status)) { 44195b482a8SLen Brown return_ACPI_STATUS(status); 44295b482a8SLen Brown } 44395b482a8SLen Brown 44495b482a8SLen Brown if (arg) { 44595b482a8SLen Brown arg->common.aml_offset = walk_state->aml_offset; 44695b482a8SLen Brown acpi_ps_append_arg(op, arg); 44795b482a8SLen Brown } 44895b482a8SLen Brown 44995b482a8SLen Brown INCREMENT_ARG_LIST(walk_state->arg_types); 45095b482a8SLen Brown } 45195b482a8SLen Brown 45295b482a8SLen Brown /* Special processing for certain opcodes */ 45395b482a8SLen Brown 45495b482a8SLen Brown /* TBD (remove): Temporary mechanism to disable this code if needed */ 45595b482a8SLen Brown 45695b482a8SLen Brown #ifdef ACPI_ENABLE_MODULE_LEVEL_CODE 45795b482a8SLen Brown 45895b482a8SLen Brown if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) && 45995b482a8SLen Brown ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { 46095b482a8SLen Brown /* 46195b482a8SLen Brown * We want to skip If/Else/While constructs during Pass1 because we 46295b482a8SLen Brown * want to actually conditionally execute the code during Pass2. 46395b482a8SLen Brown * 46495b482a8SLen Brown * Except for disassembly, where we always want to walk the 46595b482a8SLen Brown * If/Else/While packages 46695b482a8SLen Brown */ 46795b482a8SLen Brown switch (op->common.aml_opcode) { 46895b482a8SLen Brown case AML_IF_OP: 46995b482a8SLen Brown case AML_ELSE_OP: 47095b482a8SLen Brown case AML_WHILE_OP: 47195b482a8SLen Brown 47295b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 47395b482a8SLen Brown "Pass1: Skipping an If/Else/While body\n")); 47495b482a8SLen Brown 47595b482a8SLen Brown /* Skip body of if/else/while in pass 1 */ 47695b482a8SLen Brown 47795b482a8SLen Brown walk_state->parser_state.aml = 47895b482a8SLen Brown walk_state->parser_state.pkg_end; 47995b482a8SLen Brown walk_state->arg_count = 0; 48095b482a8SLen Brown break; 48195b482a8SLen Brown 48295b482a8SLen Brown default: 48395b482a8SLen Brown break; 48495b482a8SLen Brown } 48595b482a8SLen Brown } 48695b482a8SLen Brown #endif 48795b482a8SLen Brown 48895b482a8SLen Brown switch (op->common.aml_opcode) { 48995b482a8SLen Brown case AML_METHOD_OP: 49095b482a8SLen Brown /* 49195b482a8SLen Brown * Skip parsing of control method because we don't have enough 49295b482a8SLen Brown * info in the first pass to parse it correctly. 49395b482a8SLen Brown * 49495b482a8SLen Brown * Save the length and address of the body 49595b482a8SLen Brown */ 49695b482a8SLen Brown op->named.data = walk_state->parser_state.aml; 49795b482a8SLen Brown op->named.length = (u32) 49895b482a8SLen Brown (walk_state->parser_state.pkg_end - 49995b482a8SLen Brown walk_state->parser_state.aml); 50095b482a8SLen Brown 50195b482a8SLen Brown /* Skip body of method */ 50295b482a8SLen Brown 50395b482a8SLen Brown walk_state->parser_state.aml = 50495b482a8SLen Brown walk_state->parser_state.pkg_end; 50595b482a8SLen Brown walk_state->arg_count = 0; 50695b482a8SLen Brown break; 50795b482a8SLen Brown 50895b482a8SLen Brown case AML_BUFFER_OP: 50995b482a8SLen Brown case AML_PACKAGE_OP: 51095b482a8SLen Brown case AML_VAR_PACKAGE_OP: 51195b482a8SLen Brown 51295b482a8SLen Brown if ((op->common.parent) && 51395b482a8SLen Brown (op->common.parent->common.aml_opcode == 51495b482a8SLen Brown AML_NAME_OP) 51595b482a8SLen Brown && (walk_state->pass_number <= 51695b482a8SLen Brown ACPI_IMODE_LOAD_PASS2)) { 51795b482a8SLen Brown /* 51895b482a8SLen Brown * Skip parsing of Buffers and Packages because we don't have 51995b482a8SLen Brown * enough info in the first pass to parse them correctly. 52095b482a8SLen Brown */ 52195b482a8SLen Brown op->named.data = aml_op_start; 52295b482a8SLen Brown op->named.length = (u32) 52395b482a8SLen Brown (walk_state->parser_state.pkg_end - 52495b482a8SLen Brown aml_op_start); 52595b482a8SLen Brown 52695b482a8SLen Brown /* Skip body */ 52795b482a8SLen Brown 52895b482a8SLen Brown walk_state->parser_state.aml = 52995b482a8SLen Brown walk_state->parser_state.pkg_end; 53095b482a8SLen Brown walk_state->arg_count = 0; 53195b482a8SLen Brown } 53295b482a8SLen Brown break; 53395b482a8SLen Brown 53495b482a8SLen Brown case AML_WHILE_OP: 53595b482a8SLen Brown 53695b482a8SLen Brown if (walk_state->control_state) { 53795b482a8SLen Brown walk_state->control_state->control.package_end = 53895b482a8SLen Brown walk_state->parser_state.pkg_end; 53995b482a8SLen Brown } 54095b482a8SLen Brown break; 54195b482a8SLen Brown 54295b482a8SLen Brown default: 54395b482a8SLen Brown 54495b482a8SLen Brown /* No action for all other opcodes */ 54595b482a8SLen Brown break; 54695b482a8SLen Brown } 54795b482a8SLen Brown 54895b482a8SLen Brown break; 54995b482a8SLen Brown } 55095b482a8SLen Brown 55195b482a8SLen Brown return_ACPI_STATUS(AE_OK); 55295b482a8SLen Brown } 55395b482a8SLen Brown 55495b482a8SLen Brown /******************************************************************************* 55595b482a8SLen Brown * 55695b482a8SLen Brown * FUNCTION: acpi_ps_complete_op 55795b482a8SLen Brown * 55895b482a8SLen Brown * PARAMETERS: walk_state - Current state 55995b482a8SLen Brown * Op - Returned Op 56095b482a8SLen Brown * Status - Parse status before complete Op 56195b482a8SLen Brown * 56295b482a8SLen Brown * RETURN: Status 56395b482a8SLen Brown * 56495b482a8SLen Brown * DESCRIPTION: Complete Op 56595b482a8SLen Brown * 56695b482a8SLen Brown ******************************************************************************/ 56795b482a8SLen Brown 56895b482a8SLen Brown static acpi_status 56995b482a8SLen Brown acpi_ps_complete_op(struct acpi_walk_state *walk_state, 57095b482a8SLen Brown union acpi_parse_object **op, acpi_status status) 57195b482a8SLen Brown { 57295b482a8SLen Brown acpi_status status2; 57395b482a8SLen Brown 57495b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state); 57595b482a8SLen Brown 57695b482a8SLen Brown /* 57795b482a8SLen Brown * Finished one argument of the containing scope 57895b482a8SLen Brown */ 57995b482a8SLen Brown walk_state->parser_state.scope->parse_scope.arg_count--; 58095b482a8SLen Brown 58195b482a8SLen Brown /* Close this Op (will result in parse subtree deletion) */ 58295b482a8SLen Brown 58395b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, *op); 58495b482a8SLen Brown if (ACPI_FAILURE(status2)) { 58595b482a8SLen Brown return_ACPI_STATUS(status2); 58695b482a8SLen Brown } 58795b482a8SLen Brown 58895b482a8SLen Brown *op = NULL; 58995b482a8SLen Brown 59095b482a8SLen Brown switch (status) { 59195b482a8SLen Brown case AE_OK: 59295b482a8SLen Brown break; 59395b482a8SLen Brown 59495b482a8SLen Brown case AE_CTRL_TRANSFER: 59595b482a8SLen Brown 59695b482a8SLen Brown /* We are about to transfer to a called method */ 59795b482a8SLen Brown 59895b482a8SLen Brown walk_state->prev_op = NULL; 59995b482a8SLen Brown walk_state->prev_arg_types = walk_state->arg_types; 60095b482a8SLen Brown return_ACPI_STATUS(status); 60195b482a8SLen Brown 60295b482a8SLen Brown case AE_CTRL_END: 60395b482a8SLen Brown 60495b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 60595b482a8SLen Brown &walk_state->arg_types, 60695b482a8SLen Brown &walk_state->arg_count); 60795b482a8SLen Brown 60895b482a8SLen Brown if (*op) { 60995b482a8SLen Brown walk_state->op = *op; 61095b482a8SLen Brown walk_state->op_info = 61195b482a8SLen Brown acpi_ps_get_opcode_info((*op)->common.aml_opcode); 61295b482a8SLen Brown walk_state->opcode = (*op)->common.aml_opcode; 61395b482a8SLen Brown 61495b482a8SLen Brown status = walk_state->ascending_callback(walk_state); 61595b482a8SLen Brown status = 61695b482a8SLen Brown acpi_ps_next_parse_state(walk_state, *op, status); 61795b482a8SLen Brown 61895b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, *op); 61995b482a8SLen Brown if (ACPI_FAILURE(status2)) { 62095b482a8SLen Brown return_ACPI_STATUS(status2); 62195b482a8SLen Brown } 62295b482a8SLen Brown } 62395b482a8SLen Brown 62495b482a8SLen Brown status = AE_OK; 62595b482a8SLen Brown break; 62695b482a8SLen Brown 62795b482a8SLen Brown case AE_CTRL_BREAK: 62895b482a8SLen Brown case AE_CTRL_CONTINUE: 62995b482a8SLen Brown 63095b482a8SLen Brown /* Pop off scopes until we find the While */ 63195b482a8SLen Brown 63295b482a8SLen Brown while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) { 63395b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 63495b482a8SLen Brown &walk_state->arg_types, 63595b482a8SLen Brown &walk_state->arg_count); 63695b482a8SLen Brown } 63795b482a8SLen Brown 63895b482a8SLen Brown /* Close this iteration of the While loop */ 63995b482a8SLen Brown 64095b482a8SLen Brown walk_state->op = *op; 64195b482a8SLen Brown walk_state->op_info = 64295b482a8SLen Brown acpi_ps_get_opcode_info((*op)->common.aml_opcode); 64395b482a8SLen Brown walk_state->opcode = (*op)->common.aml_opcode; 64495b482a8SLen Brown 64595b482a8SLen Brown status = walk_state->ascending_callback(walk_state); 64695b482a8SLen Brown status = acpi_ps_next_parse_state(walk_state, *op, status); 64795b482a8SLen Brown 64895b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, *op); 64995b482a8SLen Brown if (ACPI_FAILURE(status2)) { 65095b482a8SLen Brown return_ACPI_STATUS(status2); 65195b482a8SLen Brown } 65295b482a8SLen Brown 65395b482a8SLen Brown status = AE_OK; 65495b482a8SLen Brown break; 65595b482a8SLen Brown 65695b482a8SLen Brown case AE_CTRL_TERMINATE: 65795b482a8SLen Brown 65895b482a8SLen Brown /* Clean up */ 65995b482a8SLen Brown do { 66095b482a8SLen Brown if (*op) { 66195b482a8SLen Brown status2 = 66295b482a8SLen Brown acpi_ps_complete_this_op(walk_state, *op); 66395b482a8SLen Brown if (ACPI_FAILURE(status2)) { 66495b482a8SLen Brown return_ACPI_STATUS(status2); 66595b482a8SLen Brown } 66695b482a8SLen Brown 66795b482a8SLen Brown acpi_ut_delete_generic_state 66895b482a8SLen Brown (acpi_ut_pop_generic_state 66995b482a8SLen Brown (&walk_state->control_state)); 67095b482a8SLen Brown } 67195b482a8SLen Brown 67295b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 67395b482a8SLen Brown &walk_state->arg_types, 67495b482a8SLen Brown &walk_state->arg_count); 67595b482a8SLen Brown 67695b482a8SLen Brown } while (*op); 67795b482a8SLen Brown 67895b482a8SLen Brown return_ACPI_STATUS(AE_OK); 67995b482a8SLen Brown 68095b482a8SLen Brown default: /* All other non-AE_OK status */ 68195b482a8SLen Brown 68295b482a8SLen Brown do { 68395b482a8SLen Brown if (*op) { 68495b482a8SLen Brown status2 = 68595b482a8SLen Brown acpi_ps_complete_this_op(walk_state, *op); 68695b482a8SLen Brown if (ACPI_FAILURE(status2)) { 68795b482a8SLen Brown return_ACPI_STATUS(status2); 68895b482a8SLen Brown } 68995b482a8SLen Brown } 69095b482a8SLen Brown 69195b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 69295b482a8SLen Brown &walk_state->arg_types, 69395b482a8SLen Brown &walk_state->arg_count); 69495b482a8SLen Brown 69595b482a8SLen Brown } while (*op); 69695b482a8SLen Brown 69795b482a8SLen Brown #if 0 69895b482a8SLen Brown /* 69995b482a8SLen Brown * TBD: Cleanup parse ops on error 70095b482a8SLen Brown */ 70195b482a8SLen Brown if (*op == NULL) { 70295b482a8SLen Brown acpi_ps_pop_scope(parser_state, op, 70395b482a8SLen Brown &walk_state->arg_types, 70495b482a8SLen Brown &walk_state->arg_count); 70595b482a8SLen Brown } 70695b482a8SLen Brown #endif 70795b482a8SLen Brown walk_state->prev_op = NULL; 70895b482a8SLen Brown walk_state->prev_arg_types = walk_state->arg_types; 70995b482a8SLen Brown return_ACPI_STATUS(status); 71095b482a8SLen Brown } 71195b482a8SLen Brown 71295b482a8SLen Brown /* This scope complete? */ 71395b482a8SLen Brown 71495b482a8SLen Brown if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) { 71595b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 71695b482a8SLen Brown &walk_state->arg_types, 71795b482a8SLen Brown &walk_state->arg_count); 71895b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op)); 71995b482a8SLen Brown } else { 72095b482a8SLen Brown *op = NULL; 72195b482a8SLen Brown } 72295b482a8SLen Brown 72395b482a8SLen Brown ACPI_PREEMPTION_POINT(); 72495b482a8SLen Brown 72595b482a8SLen Brown return_ACPI_STATUS(AE_OK); 72695b482a8SLen Brown } 72795b482a8SLen Brown 72895b482a8SLen Brown /******************************************************************************* 72995b482a8SLen Brown * 73095b482a8SLen Brown * FUNCTION: acpi_ps_complete_final_op 73195b482a8SLen Brown * 73295b482a8SLen Brown * PARAMETERS: walk_state - Current state 73395b482a8SLen Brown * Op - Current Op 73495b482a8SLen Brown * Status - Current parse status before complete last 73595b482a8SLen Brown * Op 73695b482a8SLen Brown * 73795b482a8SLen Brown * RETURN: Status 73895b482a8SLen Brown * 73995b482a8SLen Brown * DESCRIPTION: Complete last Op. 74095b482a8SLen Brown * 74195b482a8SLen Brown ******************************************************************************/ 74295b482a8SLen Brown 74395b482a8SLen Brown static acpi_status 74495b482a8SLen Brown acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, 74595b482a8SLen Brown union acpi_parse_object *op, acpi_status status) 74695b482a8SLen Brown { 74795b482a8SLen Brown acpi_status status2; 74895b482a8SLen Brown 74995b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state); 75095b482a8SLen Brown 75195b482a8SLen Brown /* 75295b482a8SLen Brown * Complete the last Op (if not completed), and clear the scope stack. 75395b482a8SLen Brown * It is easily possible to end an AML "package" with an unbounded number 75495b482a8SLen Brown * of open scopes (such as when several ASL blocks are closed with 75595b482a8SLen Brown * sequential closing braces). We want to terminate each one cleanly. 75695b482a8SLen Brown */ 75795b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n", 75895b482a8SLen Brown op)); 75995b482a8SLen Brown do { 76095b482a8SLen Brown if (op) { 76195b482a8SLen Brown if (walk_state->ascending_callback != NULL) { 76295b482a8SLen Brown walk_state->op = op; 76395b482a8SLen Brown walk_state->op_info = 76495b482a8SLen Brown acpi_ps_get_opcode_info(op->common. 76595b482a8SLen Brown aml_opcode); 76695b482a8SLen Brown walk_state->opcode = op->common.aml_opcode; 76795b482a8SLen Brown 76895b482a8SLen Brown status = 76995b482a8SLen Brown walk_state->ascending_callback(walk_state); 77095b482a8SLen Brown status = 77195b482a8SLen Brown acpi_ps_next_parse_state(walk_state, op, 77295b482a8SLen Brown status); 77395b482a8SLen Brown if (status == AE_CTRL_PENDING) { 77495b482a8SLen Brown status = 77595b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 77695b482a8SLen Brown AE_OK); 77795b482a8SLen Brown if (ACPI_FAILURE(status)) { 77895b482a8SLen Brown return_ACPI_STATUS(status); 77995b482a8SLen Brown } 78095b482a8SLen Brown } 78195b482a8SLen Brown 78295b482a8SLen Brown if (status == AE_CTRL_TERMINATE) { 78395b482a8SLen Brown status = AE_OK; 78495b482a8SLen Brown 78595b482a8SLen Brown /* Clean up */ 78695b482a8SLen Brown do { 78795b482a8SLen Brown if (op) { 78895b482a8SLen Brown status2 = 78995b482a8SLen Brown acpi_ps_complete_this_op 79095b482a8SLen Brown (walk_state, op); 79195b482a8SLen Brown if (ACPI_FAILURE 79295b482a8SLen Brown (status2)) { 79395b482a8SLen Brown return_ACPI_STATUS 79495b482a8SLen Brown (status2); 79595b482a8SLen Brown } 79695b482a8SLen Brown } 79795b482a8SLen Brown 79895b482a8SLen Brown acpi_ps_pop_scope(& 79995b482a8SLen Brown (walk_state-> 80095b482a8SLen Brown parser_state), 80195b482a8SLen Brown &op, 80295b482a8SLen Brown &walk_state-> 80395b482a8SLen Brown arg_types, 80495b482a8SLen Brown &walk_state-> 80595b482a8SLen Brown arg_count); 80695b482a8SLen Brown 80795b482a8SLen Brown } while (op); 80895b482a8SLen Brown 80995b482a8SLen Brown return_ACPI_STATUS(status); 81095b482a8SLen Brown } 81195b482a8SLen Brown 81295b482a8SLen Brown else if (ACPI_FAILURE(status)) { 81395b482a8SLen Brown 81495b482a8SLen Brown /* First error is most important */ 81595b482a8SLen Brown 81695b482a8SLen Brown (void) 81795b482a8SLen Brown acpi_ps_complete_this_op(walk_state, 81895b482a8SLen Brown op); 81995b482a8SLen Brown return_ACPI_STATUS(status); 82095b482a8SLen Brown } 82195b482a8SLen Brown } 82295b482a8SLen Brown 82395b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, op); 82495b482a8SLen Brown if (ACPI_FAILURE(status2)) { 82595b482a8SLen Brown return_ACPI_STATUS(status2); 82695b482a8SLen Brown } 82795b482a8SLen Brown } 82895b482a8SLen Brown 82995b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), &op, 83095b482a8SLen Brown &walk_state->arg_types, 83195b482a8SLen Brown &walk_state->arg_count); 83295b482a8SLen Brown 83395b482a8SLen Brown } while (op); 83495b482a8SLen Brown 83595b482a8SLen Brown return_ACPI_STATUS(status); 83695b482a8SLen Brown } 83795b482a8SLen Brown 83895b482a8SLen Brown /******************************************************************************* 83995b482a8SLen Brown * 84095b482a8SLen Brown * FUNCTION: acpi_ps_parse_loop 84195b482a8SLen Brown * 84295b482a8SLen Brown * PARAMETERS: walk_state - Current state 84395b482a8SLen Brown * 84495b482a8SLen Brown * RETURN: Status 84595b482a8SLen Brown * 84695b482a8SLen Brown * DESCRIPTION: Parse AML (pointed to by the current parser state) and return 84795b482a8SLen Brown * a tree of ops. 84895b482a8SLen Brown * 84995b482a8SLen Brown ******************************************************************************/ 85095b482a8SLen Brown 85195b482a8SLen Brown acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) 85295b482a8SLen Brown { 85395b482a8SLen Brown acpi_status status = AE_OK; 85495b482a8SLen Brown union acpi_parse_object *op = NULL; /* current op */ 85595b482a8SLen Brown struct acpi_parse_state *parser_state; 85695b482a8SLen Brown u8 *aml_op_start = NULL; 85795b482a8SLen Brown 85895b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state); 85995b482a8SLen Brown 86095b482a8SLen Brown if (walk_state->descending_callback == NULL) { 86195b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 86295b482a8SLen Brown } 86395b482a8SLen Brown 86495b482a8SLen Brown parser_state = &walk_state->parser_state; 86595b482a8SLen Brown walk_state->arg_types = 0; 86695b482a8SLen Brown 86795b482a8SLen Brown #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) 86895b482a8SLen Brown 86995b482a8SLen Brown if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { 87095b482a8SLen Brown 87195b482a8SLen Brown /* We are restarting a preempted control method */ 87295b482a8SLen Brown 87395b482a8SLen Brown if (acpi_ps_has_completed_scope(parser_state)) { 87495b482a8SLen Brown /* 87595b482a8SLen Brown * We must check if a predicate to an IF or WHILE statement 87695b482a8SLen Brown * was just completed 87795b482a8SLen Brown */ 87895b482a8SLen Brown if ((parser_state->scope->parse_scope.op) && 87995b482a8SLen Brown ((parser_state->scope->parse_scope.op->common. 88095b482a8SLen Brown aml_opcode == AML_IF_OP) 88195b482a8SLen Brown || (parser_state->scope->parse_scope.op->common. 88295b482a8SLen Brown aml_opcode == AML_WHILE_OP)) 88395b482a8SLen Brown && (walk_state->control_state) 88495b482a8SLen Brown && (walk_state->control_state->common.state == 88595b482a8SLen Brown ACPI_CONTROL_PREDICATE_EXECUTING)) { 88695b482a8SLen Brown /* 88795b482a8SLen Brown * A predicate was just completed, get the value of the 88895b482a8SLen Brown * predicate and branch based on that value 88995b482a8SLen Brown */ 89095b482a8SLen Brown walk_state->op = NULL; 89195b482a8SLen Brown status = 89295b482a8SLen Brown acpi_ds_get_predicate_value(walk_state, 89395b482a8SLen Brown ACPI_TO_POINTER 89495b482a8SLen Brown (TRUE)); 89595b482a8SLen Brown if (ACPI_FAILURE(status) 89695b482a8SLen Brown && ((status & AE_CODE_MASK) != 89795b482a8SLen Brown AE_CODE_CONTROL)) { 89895b482a8SLen Brown if (status == AE_AML_NO_RETURN_VALUE) { 89995b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, 90095b482a8SLen Brown "Invoked method did not return a value")); 90195b482a8SLen Brown 90295b482a8SLen Brown } 90395b482a8SLen Brown 90495b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, 90595b482a8SLen Brown "GetPredicate Failed")); 90695b482a8SLen Brown return_ACPI_STATUS(status); 90795b482a8SLen Brown } 90895b482a8SLen Brown 90995b482a8SLen Brown status = 91095b482a8SLen Brown acpi_ps_next_parse_state(walk_state, op, 91195b482a8SLen Brown status); 91295b482a8SLen Brown } 91395b482a8SLen Brown 91495b482a8SLen Brown acpi_ps_pop_scope(parser_state, &op, 91595b482a8SLen Brown &walk_state->arg_types, 91695b482a8SLen Brown &walk_state->arg_count); 91795b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 91895b482a8SLen Brown "Popped scope, Op=%p\n", op)); 91995b482a8SLen Brown } else if (walk_state->prev_op) { 92095b482a8SLen Brown 92195b482a8SLen Brown /* We were in the middle of an op */ 92295b482a8SLen Brown 92395b482a8SLen Brown op = walk_state->prev_op; 92495b482a8SLen Brown walk_state->arg_types = walk_state->prev_arg_types; 92595b482a8SLen Brown } 92695b482a8SLen Brown } 92795b482a8SLen Brown #endif 92895b482a8SLen Brown 92995b482a8SLen Brown /* Iterative parsing loop, while there is more AML to process: */ 93095b482a8SLen Brown 93195b482a8SLen Brown while ((parser_state->aml < parser_state->aml_end) || (op)) { 93295b482a8SLen Brown aml_op_start = parser_state->aml; 93395b482a8SLen Brown if (!op) { 93495b482a8SLen Brown status = 93595b482a8SLen Brown acpi_ps_create_op(walk_state, aml_op_start, &op); 93695b482a8SLen Brown if (ACPI_FAILURE(status)) { 93795b482a8SLen Brown if (status == AE_CTRL_PARSE_CONTINUE) { 93895b482a8SLen Brown continue; 93995b482a8SLen Brown } 94095b482a8SLen Brown 94195b482a8SLen Brown if (status == AE_CTRL_PARSE_PENDING) { 94295b482a8SLen Brown status = AE_OK; 94395b482a8SLen Brown } 94495b482a8SLen Brown 94595b482a8SLen Brown status = 94695b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 94795b482a8SLen Brown status); 94895b482a8SLen Brown if (ACPI_FAILURE(status)) { 94995b482a8SLen Brown return_ACPI_STATUS(status); 95095b482a8SLen Brown } 95195b482a8SLen Brown 95295b482a8SLen Brown continue; 95395b482a8SLen Brown } 95495b482a8SLen Brown 95595b482a8SLen Brown op->common.aml_offset = walk_state->aml_offset; 95695b482a8SLen Brown 95795b482a8SLen Brown if (walk_state->op_info) { 95895b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 95995b482a8SLen Brown "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", 96095b482a8SLen Brown (u32) op->common.aml_opcode, 96195b482a8SLen Brown walk_state->op_info->name, op, 96295b482a8SLen Brown parser_state->aml, 96395b482a8SLen Brown op->common.aml_offset)); 96495b482a8SLen Brown } 96595b482a8SLen Brown } 96695b482a8SLen Brown 96795b482a8SLen Brown /* 96895b482a8SLen Brown * Start arg_count at zero because we don't know if there are 96995b482a8SLen Brown * any args yet 97095b482a8SLen Brown */ 97195b482a8SLen Brown walk_state->arg_count = 0; 97295b482a8SLen Brown 97395b482a8SLen Brown /* Are there any arguments that must be processed? */ 97495b482a8SLen Brown 97595b482a8SLen Brown if (walk_state->arg_types) { 97695b482a8SLen Brown 97795b482a8SLen Brown /* Get arguments */ 97895b482a8SLen Brown 97995b482a8SLen Brown status = 98095b482a8SLen Brown acpi_ps_get_arguments(walk_state, aml_op_start, op); 98195b482a8SLen Brown if (ACPI_FAILURE(status)) { 98295b482a8SLen Brown status = 98395b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 98495b482a8SLen Brown status); 98595b482a8SLen Brown if (ACPI_FAILURE(status)) { 98695b482a8SLen Brown return_ACPI_STATUS(status); 98795b482a8SLen Brown } 98895b482a8SLen Brown 98995b482a8SLen Brown continue; 99095b482a8SLen Brown } 99195b482a8SLen Brown } 99295b482a8SLen Brown 99395b482a8SLen Brown /* Check for arguments that need to be processed */ 99495b482a8SLen Brown 99595b482a8SLen Brown if (walk_state->arg_count) { 99695b482a8SLen Brown /* 99795b482a8SLen Brown * There are arguments (complex ones), push Op and 99895b482a8SLen Brown * prepare for argument 99995b482a8SLen Brown */ 100095b482a8SLen Brown status = acpi_ps_push_scope(parser_state, op, 100195b482a8SLen Brown walk_state->arg_types, 100295b482a8SLen Brown walk_state->arg_count); 100395b482a8SLen Brown if (ACPI_FAILURE(status)) { 100495b482a8SLen Brown status = 100595b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 100695b482a8SLen Brown status); 100795b482a8SLen Brown if (ACPI_FAILURE(status)) { 100895b482a8SLen Brown return_ACPI_STATUS(status); 100995b482a8SLen Brown } 101095b482a8SLen Brown 101195b482a8SLen Brown continue; 101295b482a8SLen Brown } 101395b482a8SLen Brown 101495b482a8SLen Brown op = NULL; 101595b482a8SLen Brown continue; 101695b482a8SLen Brown } 101795b482a8SLen Brown 101895b482a8SLen Brown /* 101995b482a8SLen Brown * All arguments have been processed -- Op is complete, 102095b482a8SLen Brown * prepare for next 102195b482a8SLen Brown */ 102295b482a8SLen Brown walk_state->op_info = 102395b482a8SLen Brown acpi_ps_get_opcode_info(op->common.aml_opcode); 102495b482a8SLen Brown if (walk_state->op_info->flags & AML_NAMED) { 102595b482a8SLen Brown if (acpi_gbl_depth) { 102695b482a8SLen Brown acpi_gbl_depth--; 102795b482a8SLen Brown } 102895b482a8SLen Brown 102995b482a8SLen Brown if (op->common.aml_opcode == AML_REGION_OP || 103095b482a8SLen Brown op->common.aml_opcode == AML_DATA_REGION_OP) { 103195b482a8SLen Brown /* 103295b482a8SLen Brown * Skip parsing of control method or opregion body, 103395b482a8SLen Brown * because we don't have enough info in the first pass 103495b482a8SLen Brown * to parse them correctly. 103595b482a8SLen Brown * 103695b482a8SLen Brown * Completed parsing an op_region declaration, we now 103795b482a8SLen Brown * know the length. 103895b482a8SLen Brown */ 103995b482a8SLen Brown op->named.length = 104095b482a8SLen Brown (u32) (parser_state->aml - op->named.data); 104195b482a8SLen Brown } 104295b482a8SLen Brown } 104395b482a8SLen Brown 104495b482a8SLen Brown if (walk_state->op_info->flags & AML_CREATE) { 104595b482a8SLen Brown /* 104695b482a8SLen Brown * Backup to beginning of create_xXXfield declaration (1 for 104795b482a8SLen Brown * Opcode) 104895b482a8SLen Brown * 104995b482a8SLen Brown * body_length is unknown until we parse the body 105095b482a8SLen Brown */ 105195b482a8SLen Brown op->named.length = 105295b482a8SLen Brown (u32) (parser_state->aml - op->named.data); 105395b482a8SLen Brown } 105495b482a8SLen Brown 105595b482a8SLen Brown if (op->common.aml_opcode == AML_BANK_FIELD_OP) { 105695b482a8SLen Brown /* 105795b482a8SLen Brown * Backup to beginning of bank_field declaration 105895b482a8SLen Brown * 105995b482a8SLen Brown * body_length is unknown until we parse the body 106095b482a8SLen Brown */ 106195b482a8SLen Brown op->named.length = 106295b482a8SLen Brown (u32) (parser_state->aml - op->named.data); 106395b482a8SLen Brown } 106495b482a8SLen Brown 106595b482a8SLen Brown /* This op complete, notify the dispatcher */ 106695b482a8SLen Brown 106795b482a8SLen Brown if (walk_state->ascending_callback != NULL) { 106895b482a8SLen Brown walk_state->op = op; 106995b482a8SLen Brown walk_state->opcode = op->common.aml_opcode; 107095b482a8SLen Brown 107195b482a8SLen Brown status = walk_state->ascending_callback(walk_state); 107295b482a8SLen Brown status = 107395b482a8SLen Brown acpi_ps_next_parse_state(walk_state, op, status); 107495b482a8SLen Brown if (status == AE_CTRL_PENDING) { 107595b482a8SLen Brown status = AE_OK; 107695b482a8SLen Brown } 107795b482a8SLen Brown } 107895b482a8SLen Brown 107995b482a8SLen Brown status = acpi_ps_complete_op(walk_state, &op, status); 108095b482a8SLen Brown if (ACPI_FAILURE(status)) { 108195b482a8SLen Brown return_ACPI_STATUS(status); 108295b482a8SLen Brown } 108395b482a8SLen Brown 108495b482a8SLen Brown } /* while parser_state->Aml */ 108595b482a8SLen Brown 108695b482a8SLen Brown status = acpi_ps_complete_final_op(walk_state, op, status); 108795b482a8SLen Brown return_ACPI_STATUS(status); 108895b482a8SLen Brown } 1089