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> 53e2f7a777SLen Brown #include "accommon.h" 54e2f7a777SLen Brown #include "acparser.h" 55e2f7a777SLen Brown #include "acdispat.h" 56e2f7a777SLen 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 89*7f0c826aSLin Ming static void 90*7f0c826aSLin Ming acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id); 91*7f0c826aSLin Ming 9295b482a8SLen Brown /******************************************************************************* 9395b482a8SLen Brown * 9495b482a8SLen Brown * FUNCTION: acpi_ps_get_aml_opcode 9595b482a8SLen Brown * 9695b482a8SLen Brown * PARAMETERS: walk_state - Current state 9795b482a8SLen Brown * 9895b482a8SLen Brown * RETURN: Status 9995b482a8SLen Brown * 10095b482a8SLen Brown * DESCRIPTION: Extract the next AML opcode from the input stream. 10195b482a8SLen Brown * 10295b482a8SLen Brown ******************************************************************************/ 10395b482a8SLen Brown 10495b482a8SLen Brown static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) 10595b482a8SLen Brown { 10695b482a8SLen Brown 10795b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state); 10895b482a8SLen Brown 10995b482a8SLen Brown walk_state->aml_offset = 11095b482a8SLen Brown (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, 11195b482a8SLen Brown walk_state->parser_state.aml_start); 11295b482a8SLen Brown walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state)); 11395b482a8SLen Brown 11495b482a8SLen Brown /* 11595b482a8SLen Brown * First cut to determine what we have found: 11695b482a8SLen Brown * 1) A valid AML opcode 11795b482a8SLen Brown * 2) A name string 11895b482a8SLen Brown * 3) An unknown/invalid opcode 11995b482a8SLen Brown */ 12095b482a8SLen Brown walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); 12195b482a8SLen Brown 12295b482a8SLen Brown switch (walk_state->op_info->class) { 12395b482a8SLen Brown case AML_CLASS_ASCII: 12495b482a8SLen Brown case AML_CLASS_PREFIX: 12595b482a8SLen Brown /* 12695b482a8SLen Brown * Starts with a valid prefix or ASCII char, this is a name 12795b482a8SLen Brown * string. Convert the bare name string to a namepath. 12895b482a8SLen Brown */ 12995b482a8SLen Brown walk_state->opcode = AML_INT_NAMEPATH_OP; 13095b482a8SLen Brown walk_state->arg_types = ARGP_NAMESTRING; 13195b482a8SLen Brown break; 13295b482a8SLen Brown 13395b482a8SLen Brown case AML_CLASS_UNKNOWN: 13495b482a8SLen Brown 13595b482a8SLen Brown /* The opcode is unrecognized. Just skip unknown opcodes */ 13695b482a8SLen Brown 13795b482a8SLen Brown ACPI_ERROR((AE_INFO, 13895b482a8SLen Brown "Found unknown opcode %X at AML address %p offset %X, ignoring", 13995b482a8SLen Brown walk_state->opcode, walk_state->parser_state.aml, 14095b482a8SLen Brown walk_state->aml_offset)); 14195b482a8SLen Brown 14295b482a8SLen Brown ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); 14395b482a8SLen Brown 14495b482a8SLen Brown /* Assume one-byte bad opcode */ 14595b482a8SLen Brown 14695b482a8SLen Brown walk_state->parser_state.aml++; 14795b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); 14895b482a8SLen Brown 14995b482a8SLen Brown default: 15095b482a8SLen Brown 15195b482a8SLen Brown /* Found opcode info, this is a normal opcode */ 15295b482a8SLen Brown 15395b482a8SLen Brown walk_state->parser_state.aml += 15495b482a8SLen Brown acpi_ps_get_opcode_size(walk_state->opcode); 15595b482a8SLen Brown walk_state->arg_types = walk_state->op_info->parse_args; 15695b482a8SLen Brown break; 15795b482a8SLen Brown } 15895b482a8SLen Brown 15995b482a8SLen Brown return_ACPI_STATUS(AE_OK); 16095b482a8SLen Brown } 16195b482a8SLen Brown 16295b482a8SLen Brown /******************************************************************************* 16395b482a8SLen Brown * 16495b482a8SLen Brown * FUNCTION: acpi_ps_build_named_op 16595b482a8SLen Brown * 16695b482a8SLen Brown * PARAMETERS: walk_state - Current state 16795b482a8SLen Brown * aml_op_start - Begin of named Op in AML 16895b482a8SLen Brown * unnamed_op - Early Op (not a named Op) 16995b482a8SLen Brown * Op - Returned Op 17095b482a8SLen Brown * 17195b482a8SLen Brown * RETURN: Status 17295b482a8SLen Brown * 17395b482a8SLen Brown * DESCRIPTION: Parse a named Op 17495b482a8SLen Brown * 17595b482a8SLen Brown ******************************************************************************/ 17695b482a8SLen Brown 17795b482a8SLen Brown static acpi_status 17895b482a8SLen Brown acpi_ps_build_named_op(struct acpi_walk_state *walk_state, 17995b482a8SLen Brown u8 * aml_op_start, 18095b482a8SLen Brown union acpi_parse_object *unnamed_op, 18195b482a8SLen Brown union acpi_parse_object **op) 18295b482a8SLen Brown { 18395b482a8SLen Brown acpi_status status = AE_OK; 18495b482a8SLen Brown union acpi_parse_object *arg = NULL; 18595b482a8SLen Brown 18695b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); 18795b482a8SLen Brown 18895b482a8SLen Brown unnamed_op->common.value.arg = NULL; 18995b482a8SLen Brown unnamed_op->common.arg_list_length = 0; 19095b482a8SLen Brown unnamed_op->common.aml_opcode = walk_state->opcode; 19195b482a8SLen Brown 19295b482a8SLen Brown /* 19395b482a8SLen Brown * Get and append arguments until we find the node that contains 19495b482a8SLen Brown * the name (the type ARGP_NAME). 19595b482a8SLen Brown */ 19695b482a8SLen Brown while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && 19795b482a8SLen Brown (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) { 19895b482a8SLen Brown status = 19995b482a8SLen Brown acpi_ps_get_next_arg(walk_state, 20095b482a8SLen Brown &(walk_state->parser_state), 20195b482a8SLen Brown GET_CURRENT_ARG_TYPE(walk_state-> 20295b482a8SLen Brown arg_types), &arg); 20395b482a8SLen Brown if (ACPI_FAILURE(status)) { 20495b482a8SLen Brown return_ACPI_STATUS(status); 20595b482a8SLen Brown } 20695b482a8SLen Brown 20795b482a8SLen Brown acpi_ps_append_arg(unnamed_op, arg); 20895b482a8SLen Brown INCREMENT_ARG_LIST(walk_state->arg_types); 20995b482a8SLen Brown } 21095b482a8SLen Brown 21195b482a8SLen Brown /* 21295b482a8SLen Brown * Make sure that we found a NAME and didn't run out of arguments 21395b482a8SLen Brown */ 21495b482a8SLen Brown if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) { 21595b482a8SLen Brown return_ACPI_STATUS(AE_AML_NO_OPERAND); 21695b482a8SLen Brown } 21795b482a8SLen Brown 21895b482a8SLen Brown /* We know that this arg is a name, move to next arg */ 21995b482a8SLen Brown 22095b482a8SLen Brown INCREMENT_ARG_LIST(walk_state->arg_types); 22195b482a8SLen Brown 22295b482a8SLen Brown /* 22395b482a8SLen Brown * Find the object. This will either insert the object into 22495b482a8SLen Brown * the namespace or simply look it up 22595b482a8SLen Brown */ 22695b482a8SLen Brown walk_state->op = NULL; 22795b482a8SLen Brown 22895b482a8SLen Brown status = walk_state->descending_callback(walk_state, op); 22995b482a8SLen Brown if (ACPI_FAILURE(status)) { 23095b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog")); 23195b482a8SLen Brown return_ACPI_STATUS(status); 23295b482a8SLen Brown } 23395b482a8SLen Brown 23495b482a8SLen Brown if (!*op) { 23595b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); 23695b482a8SLen Brown } 23795b482a8SLen Brown 23895b482a8SLen Brown status = acpi_ps_next_parse_state(walk_state, *op, status); 23995b482a8SLen Brown if (ACPI_FAILURE(status)) { 24095b482a8SLen Brown if (status == AE_CTRL_PENDING) { 24195b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_PENDING); 24295b482a8SLen Brown } 24395b482a8SLen Brown return_ACPI_STATUS(status); 24495b482a8SLen Brown } 24595b482a8SLen Brown 24695b482a8SLen Brown acpi_ps_append_arg(*op, unnamed_op->common.value.arg); 24795b482a8SLen Brown acpi_gbl_depth++; 24895b482a8SLen Brown 24995b482a8SLen Brown if ((*op)->common.aml_opcode == AML_REGION_OP || 25095b482a8SLen Brown (*op)->common.aml_opcode == AML_DATA_REGION_OP) { 25195b482a8SLen Brown /* 25295b482a8SLen Brown * Defer final parsing of an operation_region body, because we don't 25395b482a8SLen Brown * have enough info in the first pass to parse it correctly (i.e., 25495b482a8SLen Brown * there may be method calls within the term_arg elements of the body.) 25595b482a8SLen Brown * 25695b482a8SLen Brown * However, we must continue parsing because the opregion is not a 25795b482a8SLen Brown * standalone package -- we don't know where the end is at this point. 25895b482a8SLen Brown * 25995b482a8SLen Brown * (Length is unknown until parse of the body complete) 26095b482a8SLen Brown */ 26195b482a8SLen Brown (*op)->named.data = aml_op_start; 26295b482a8SLen Brown (*op)->named.length = 0; 26395b482a8SLen Brown } 26495b482a8SLen Brown 26595b482a8SLen Brown return_ACPI_STATUS(AE_OK); 26695b482a8SLen Brown } 26795b482a8SLen Brown 26895b482a8SLen Brown /******************************************************************************* 26995b482a8SLen Brown * 27095b482a8SLen Brown * FUNCTION: acpi_ps_create_op 27195b482a8SLen Brown * 27295b482a8SLen Brown * PARAMETERS: walk_state - Current state 27395b482a8SLen Brown * aml_op_start - Op start in AML 27495b482a8SLen Brown * new_op - Returned Op 27595b482a8SLen Brown * 27695b482a8SLen Brown * RETURN: Status 27795b482a8SLen Brown * 27895b482a8SLen Brown * DESCRIPTION: Get Op from AML 27995b482a8SLen Brown * 28095b482a8SLen Brown ******************************************************************************/ 28195b482a8SLen Brown 28295b482a8SLen Brown static acpi_status 28395b482a8SLen Brown acpi_ps_create_op(struct acpi_walk_state *walk_state, 28495b482a8SLen Brown u8 * aml_op_start, union acpi_parse_object **new_op) 28595b482a8SLen Brown { 28695b482a8SLen Brown acpi_status status = AE_OK; 28795b482a8SLen Brown union acpi_parse_object *op; 28895b482a8SLen Brown union acpi_parse_object *named_op = NULL; 28995b482a8SLen Brown union acpi_parse_object *parent_scope; 29095b482a8SLen Brown u8 argument_count; 29195b482a8SLen Brown const struct acpi_opcode_info *op_info; 29295b482a8SLen Brown 29395b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); 29495b482a8SLen Brown 29595b482a8SLen Brown status = acpi_ps_get_aml_opcode(walk_state); 29695b482a8SLen Brown if (status == AE_CTRL_PARSE_CONTINUE) { 29795b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); 29895b482a8SLen Brown } 29995b482a8SLen Brown 30095b482a8SLen Brown /* Create Op structure and append to parent's argument list */ 30195b482a8SLen Brown 30295b482a8SLen Brown walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); 30395b482a8SLen Brown op = acpi_ps_alloc_op(walk_state->opcode); 30495b482a8SLen Brown if (!op) { 30595b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY); 30695b482a8SLen Brown } 30795b482a8SLen Brown 30895b482a8SLen Brown if (walk_state->op_info->flags & AML_NAMED) { 30995b482a8SLen Brown status = 31095b482a8SLen Brown acpi_ps_build_named_op(walk_state, aml_op_start, op, 31195b482a8SLen Brown &named_op); 31295b482a8SLen Brown acpi_ps_free_op(op); 31395b482a8SLen Brown if (ACPI_FAILURE(status)) { 31495b482a8SLen Brown return_ACPI_STATUS(status); 31595b482a8SLen Brown } 31695b482a8SLen Brown 31795b482a8SLen Brown *new_op = named_op; 31895b482a8SLen Brown return_ACPI_STATUS(AE_OK); 31995b482a8SLen Brown } 32095b482a8SLen Brown 32195b482a8SLen Brown /* Not a named opcode, just allocate Op and append to parent */ 32295b482a8SLen Brown 32395b482a8SLen Brown if (walk_state->op_info->flags & AML_CREATE) { 32495b482a8SLen Brown /* 32595b482a8SLen Brown * Backup to beginning of create_xXXfield declaration 32695b482a8SLen Brown * body_length is unknown until we parse the body 32795b482a8SLen Brown */ 32895b482a8SLen Brown op->named.data = aml_op_start; 32995b482a8SLen Brown op->named.length = 0; 33095b482a8SLen Brown } 33195b482a8SLen Brown 33295b482a8SLen Brown if (walk_state->opcode == AML_BANK_FIELD_OP) { 33395b482a8SLen Brown /* 33495b482a8SLen Brown * Backup to beginning of bank_field declaration 33595b482a8SLen Brown * body_length is unknown until we parse the body 33695b482a8SLen Brown */ 33795b482a8SLen Brown op->named.data = aml_op_start; 33895b482a8SLen Brown op->named.length = 0; 33995b482a8SLen Brown } 34095b482a8SLen Brown 34195b482a8SLen Brown parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state)); 34295b482a8SLen Brown acpi_ps_append_arg(parent_scope, op); 34395b482a8SLen Brown 34495b482a8SLen Brown if (parent_scope) { 34595b482a8SLen Brown op_info = 34695b482a8SLen Brown acpi_ps_get_opcode_info(parent_scope->common.aml_opcode); 34795b482a8SLen Brown if (op_info->flags & AML_HAS_TARGET) { 34895b482a8SLen Brown argument_count = 34995b482a8SLen Brown acpi_ps_get_argument_count(op_info->type); 35095b482a8SLen Brown if (parent_scope->common.arg_list_length > 35195b482a8SLen Brown argument_count) { 35295b482a8SLen Brown op->common.flags |= ACPI_PARSEOP_TARGET; 35395b482a8SLen Brown } 35495b482a8SLen Brown } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) { 35595b482a8SLen Brown op->common.flags |= ACPI_PARSEOP_TARGET; 35695b482a8SLen Brown } 35795b482a8SLen Brown } 35895b482a8SLen Brown 35995b482a8SLen Brown if (walk_state->descending_callback != NULL) { 36095b482a8SLen Brown /* 36195b482a8SLen Brown * Find the object. This will either insert the object into 36295b482a8SLen Brown * the namespace or simply look it up 36395b482a8SLen Brown */ 36495b482a8SLen Brown walk_state->op = *new_op = op; 36595b482a8SLen Brown 36695b482a8SLen Brown status = walk_state->descending_callback(walk_state, &op); 36795b482a8SLen Brown status = acpi_ps_next_parse_state(walk_state, op, status); 36895b482a8SLen Brown if (status == AE_CTRL_PENDING) { 36995b482a8SLen Brown status = AE_CTRL_PARSE_PENDING; 37095b482a8SLen Brown } 37195b482a8SLen Brown } 37295b482a8SLen Brown 37395b482a8SLen Brown return_ACPI_STATUS(status); 37495b482a8SLen Brown } 37595b482a8SLen Brown 37695b482a8SLen Brown /******************************************************************************* 37795b482a8SLen Brown * 37895b482a8SLen Brown * FUNCTION: acpi_ps_get_arguments 37995b482a8SLen Brown * 38095b482a8SLen Brown * PARAMETERS: walk_state - Current state 38195b482a8SLen Brown * aml_op_start - Op start in AML 38295b482a8SLen Brown * Op - Current Op 38395b482a8SLen Brown * 38495b482a8SLen Brown * RETURN: Status 38595b482a8SLen Brown * 38695b482a8SLen Brown * DESCRIPTION: Get arguments for passed Op. 38795b482a8SLen Brown * 38895b482a8SLen Brown ******************************************************************************/ 38995b482a8SLen Brown 39095b482a8SLen Brown static acpi_status 39195b482a8SLen Brown acpi_ps_get_arguments(struct acpi_walk_state *walk_state, 39295b482a8SLen Brown u8 * aml_op_start, union acpi_parse_object *op) 39395b482a8SLen Brown { 39495b482a8SLen Brown acpi_status status = AE_OK; 39595b482a8SLen Brown union acpi_parse_object *arg = NULL; 396*7f0c826aSLin Ming const struct acpi_opcode_info *op_info; 39795b482a8SLen Brown 39895b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); 39995b482a8SLen Brown 40095b482a8SLen Brown switch (op->common.aml_opcode) { 40195b482a8SLen Brown case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ 40295b482a8SLen Brown case AML_WORD_OP: /* AML_WORDDATA_ARG */ 40395b482a8SLen Brown case AML_DWORD_OP: /* AML_DWORDATA_ARG */ 40495b482a8SLen Brown case AML_QWORD_OP: /* AML_QWORDATA_ARG */ 40595b482a8SLen Brown case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ 40695b482a8SLen Brown 40795b482a8SLen Brown /* Fill in constant or string argument directly */ 40895b482a8SLen Brown 40995b482a8SLen Brown acpi_ps_get_next_simple_arg(&(walk_state->parser_state), 41095b482a8SLen Brown GET_CURRENT_ARG_TYPE(walk_state-> 41195b482a8SLen Brown arg_types), 41295b482a8SLen Brown op); 41395b482a8SLen Brown break; 41495b482a8SLen Brown 41595b482a8SLen Brown case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ 41695b482a8SLen Brown 41795b482a8SLen Brown status = 41895b482a8SLen Brown acpi_ps_get_next_namepath(walk_state, 41995b482a8SLen Brown &(walk_state->parser_state), op, 42095b482a8SLen Brown 1); 42195b482a8SLen Brown if (ACPI_FAILURE(status)) { 42295b482a8SLen Brown return_ACPI_STATUS(status); 42395b482a8SLen Brown } 42495b482a8SLen Brown 42595b482a8SLen Brown walk_state->arg_types = 0; 42695b482a8SLen Brown break; 42795b482a8SLen Brown 42895b482a8SLen Brown default: 42995b482a8SLen Brown /* 43095b482a8SLen Brown * Op is not a constant or string, append each argument to the Op 43195b482a8SLen Brown */ 43295b482a8SLen Brown while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) 43395b482a8SLen Brown && !walk_state->arg_count) { 43495b482a8SLen Brown walk_state->aml_offset = 43595b482a8SLen Brown (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, 43695b482a8SLen Brown walk_state->parser_state. 43795b482a8SLen Brown aml_start); 43895b482a8SLen Brown 43995b482a8SLen Brown status = 44095b482a8SLen Brown acpi_ps_get_next_arg(walk_state, 44195b482a8SLen Brown &(walk_state->parser_state), 44295b482a8SLen Brown GET_CURRENT_ARG_TYPE 44395b482a8SLen Brown (walk_state->arg_types), &arg); 44495b482a8SLen Brown if (ACPI_FAILURE(status)) { 44595b482a8SLen Brown return_ACPI_STATUS(status); 44695b482a8SLen Brown } 44795b482a8SLen Brown 44895b482a8SLen Brown if (arg) { 44995b482a8SLen Brown arg->common.aml_offset = walk_state->aml_offset; 45095b482a8SLen Brown acpi_ps_append_arg(op, arg); 45195b482a8SLen Brown } 45295b482a8SLen Brown 45395b482a8SLen Brown INCREMENT_ARG_LIST(walk_state->arg_types); 45495b482a8SLen Brown } 45595b482a8SLen Brown 456*7f0c826aSLin Ming /* 457*7f0c826aSLin Ming * Handle executable code at "module-level". This refers to 458*7f0c826aSLin Ming * executable opcodes that appear outside of any control method. 459*7f0c826aSLin Ming */ 460*7f0c826aSLin Ming if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2) && 46195b482a8SLen Brown ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { 46295b482a8SLen Brown /* 46395b482a8SLen Brown * We want to skip If/Else/While constructs during Pass1 because we 46495b482a8SLen Brown * want to actually conditionally execute the code during Pass2. 46595b482a8SLen Brown * 46695b482a8SLen Brown * Except for disassembly, where we always want to walk the 46795b482a8SLen Brown * If/Else/While packages 46895b482a8SLen Brown */ 46995b482a8SLen Brown switch (op->common.aml_opcode) { 47095b482a8SLen Brown case AML_IF_OP: 47195b482a8SLen Brown case AML_ELSE_OP: 47295b482a8SLen Brown case AML_WHILE_OP: 47395b482a8SLen Brown 474*7f0c826aSLin Ming /* 475*7f0c826aSLin Ming * Currently supported module-level opcodes are: 476*7f0c826aSLin Ming * IF/ELSE/WHILE. These appear to be the most common, 477*7f0c826aSLin Ming * and easiest to support since they open an AML 478*7f0c826aSLin Ming * package. 479*7f0c826aSLin Ming */ 480*7f0c826aSLin Ming if (walk_state->pass_number == 481*7f0c826aSLin Ming ACPI_IMODE_LOAD_PASS1) { 482*7f0c826aSLin Ming acpi_ps_link_module_code(aml_op_start, 483*7f0c826aSLin Ming walk_state-> 484*7f0c826aSLin Ming parser_state. 485*7f0c826aSLin Ming pkg_end - 486*7f0c826aSLin Ming aml_op_start, 487*7f0c826aSLin Ming walk_state-> 488*7f0c826aSLin Ming owner_id); 489*7f0c826aSLin Ming } 490*7f0c826aSLin Ming 49195b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 49295b482a8SLen Brown "Pass1: Skipping an If/Else/While body\n")); 49395b482a8SLen Brown 49495b482a8SLen Brown /* Skip body of if/else/while in pass 1 */ 49595b482a8SLen Brown 49695b482a8SLen Brown walk_state->parser_state.aml = 49795b482a8SLen Brown walk_state->parser_state.pkg_end; 49895b482a8SLen Brown walk_state->arg_count = 0; 49995b482a8SLen Brown break; 50095b482a8SLen Brown 50195b482a8SLen Brown default: 502*7f0c826aSLin Ming /* 503*7f0c826aSLin Ming * Check for an unsupported executable opcode at module 504*7f0c826aSLin Ming * level. We must be in PASS1, the parent must be a SCOPE, 505*7f0c826aSLin Ming * The opcode class must be EXECUTE, and the opcode must 506*7f0c826aSLin Ming * not be an argument to another opcode. 507*7f0c826aSLin Ming */ 508*7f0c826aSLin Ming if ((walk_state->pass_number == 509*7f0c826aSLin Ming ACPI_IMODE_LOAD_PASS1) 510*7f0c826aSLin Ming && (op->common.parent->common.aml_opcode == 511*7f0c826aSLin Ming AML_SCOPE_OP)) { 512*7f0c826aSLin Ming op_info = 513*7f0c826aSLin Ming acpi_ps_get_opcode_info(op->common. 514*7f0c826aSLin Ming aml_opcode); 515*7f0c826aSLin Ming if ((op_info->class == 516*7f0c826aSLin Ming AML_CLASS_EXECUTE) && (!arg)) { 517*7f0c826aSLin Ming ACPI_WARNING((AE_INFO, 518*7f0c826aSLin Ming "Detected an unsupported executable opcode " 519*7f0c826aSLin Ming "at module-level: [0x%.4X] at table offset 0x%.4X", 520*7f0c826aSLin Ming op->common.aml_opcode, 521*7f0c826aSLin Ming (u32)((aml_op_start - walk_state->parser_state.aml_start) 522*7f0c826aSLin Ming + sizeof(struct acpi_table_header)))); 523*7f0c826aSLin Ming } 524*7f0c826aSLin Ming } 52595b482a8SLen Brown break; 52695b482a8SLen Brown } 52795b482a8SLen Brown } 528*7f0c826aSLin Ming 529*7f0c826aSLin Ming /* Special processing for certain opcodes */ 53095b482a8SLen Brown 53195b482a8SLen Brown switch (op->common.aml_opcode) { 53295b482a8SLen Brown case AML_METHOD_OP: 53395b482a8SLen Brown /* 53495b482a8SLen Brown * Skip parsing of control method because we don't have enough 53595b482a8SLen Brown * info in the first pass to parse it correctly. 53695b482a8SLen Brown * 53795b482a8SLen Brown * Save the length and address of the body 53895b482a8SLen Brown */ 53995b482a8SLen Brown op->named.data = walk_state->parser_state.aml; 54095b482a8SLen Brown op->named.length = (u32) 54195b482a8SLen Brown (walk_state->parser_state.pkg_end - 54295b482a8SLen Brown walk_state->parser_state.aml); 54395b482a8SLen Brown 54495b482a8SLen Brown /* Skip body of method */ 54595b482a8SLen Brown 54695b482a8SLen Brown walk_state->parser_state.aml = 54795b482a8SLen Brown walk_state->parser_state.pkg_end; 54895b482a8SLen Brown walk_state->arg_count = 0; 54995b482a8SLen Brown break; 55095b482a8SLen Brown 55195b482a8SLen Brown case AML_BUFFER_OP: 55295b482a8SLen Brown case AML_PACKAGE_OP: 55395b482a8SLen Brown case AML_VAR_PACKAGE_OP: 55495b482a8SLen Brown 55595b482a8SLen Brown if ((op->common.parent) && 55695b482a8SLen Brown (op->common.parent->common.aml_opcode == 55795b482a8SLen Brown AML_NAME_OP) 55895b482a8SLen Brown && (walk_state->pass_number <= 55995b482a8SLen Brown ACPI_IMODE_LOAD_PASS2)) { 56095b482a8SLen Brown /* 56195b482a8SLen Brown * Skip parsing of Buffers and Packages because we don't have 56295b482a8SLen Brown * enough info in the first pass to parse them correctly. 56395b482a8SLen Brown */ 56495b482a8SLen Brown op->named.data = aml_op_start; 56595b482a8SLen Brown op->named.length = (u32) 56695b482a8SLen Brown (walk_state->parser_state.pkg_end - 56795b482a8SLen Brown aml_op_start); 56895b482a8SLen Brown 56995b482a8SLen Brown /* Skip body */ 57095b482a8SLen Brown 57195b482a8SLen Brown walk_state->parser_state.aml = 57295b482a8SLen Brown walk_state->parser_state.pkg_end; 57395b482a8SLen Brown walk_state->arg_count = 0; 57495b482a8SLen Brown } 57595b482a8SLen Brown break; 57695b482a8SLen Brown 57795b482a8SLen Brown case AML_WHILE_OP: 57895b482a8SLen Brown 57995b482a8SLen Brown if (walk_state->control_state) { 58095b482a8SLen Brown walk_state->control_state->control.package_end = 58195b482a8SLen Brown walk_state->parser_state.pkg_end; 58295b482a8SLen Brown } 58395b482a8SLen Brown break; 58495b482a8SLen Brown 58595b482a8SLen Brown default: 58695b482a8SLen Brown 58795b482a8SLen Brown /* No action for all other opcodes */ 58895b482a8SLen Brown break; 58995b482a8SLen Brown } 59095b482a8SLen Brown 59195b482a8SLen Brown break; 59295b482a8SLen Brown } 59395b482a8SLen Brown 59495b482a8SLen Brown return_ACPI_STATUS(AE_OK); 59595b482a8SLen Brown } 59695b482a8SLen Brown 59795b482a8SLen Brown /******************************************************************************* 59895b482a8SLen Brown * 599*7f0c826aSLin Ming * FUNCTION: acpi_ps_link_module_code 600*7f0c826aSLin Ming * 601*7f0c826aSLin Ming * PARAMETERS: aml_start - Pointer to the AML 602*7f0c826aSLin Ming * aml_length - Length of executable AML 603*7f0c826aSLin Ming * owner_id - owner_id of module level code 604*7f0c826aSLin Ming * 605*7f0c826aSLin Ming * RETURN: None. 606*7f0c826aSLin Ming * 607*7f0c826aSLin Ming * DESCRIPTION: Wrap the module-level code with a method object and link the 608*7f0c826aSLin Ming * object to the global list. Note, the mutex field of the method 609*7f0c826aSLin Ming * object is used to link multiple module-level code objects. 610*7f0c826aSLin Ming * 611*7f0c826aSLin Ming ******************************************************************************/ 612*7f0c826aSLin Ming 613*7f0c826aSLin Ming static void 614*7f0c826aSLin Ming acpi_ps_link_module_code(u8 *aml_start, u32 aml_length, acpi_owner_id owner_id) 615*7f0c826aSLin Ming { 616*7f0c826aSLin Ming union acpi_operand_object *prev; 617*7f0c826aSLin Ming union acpi_operand_object *next; 618*7f0c826aSLin Ming union acpi_operand_object *method_obj; 619*7f0c826aSLin Ming 620*7f0c826aSLin Ming /* Get the tail of the list */ 621*7f0c826aSLin Ming 622*7f0c826aSLin Ming prev = next = acpi_gbl_module_code_list; 623*7f0c826aSLin Ming while (next) { 624*7f0c826aSLin Ming prev = next; 625*7f0c826aSLin Ming next = next->method.mutex; 626*7f0c826aSLin Ming } 627*7f0c826aSLin Ming 628*7f0c826aSLin Ming /* 629*7f0c826aSLin Ming * Insert the module level code into the list. Merge it if it is 630*7f0c826aSLin Ming * adjacent to the previous element. 631*7f0c826aSLin Ming */ 632*7f0c826aSLin Ming if (!prev || 633*7f0c826aSLin Ming ((prev->method.aml_start + prev->method.aml_length) != aml_start)) { 634*7f0c826aSLin Ming 635*7f0c826aSLin Ming /* Create, initialize, and link a new temporary method object */ 636*7f0c826aSLin Ming 637*7f0c826aSLin Ming method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); 638*7f0c826aSLin Ming if (!method_obj) { 639*7f0c826aSLin Ming return; 640*7f0c826aSLin Ming } 641*7f0c826aSLin Ming 642*7f0c826aSLin Ming method_obj->method.aml_start = aml_start; 643*7f0c826aSLin Ming method_obj->method.aml_length = aml_length; 644*7f0c826aSLin Ming method_obj->method.owner_id = owner_id; 645*7f0c826aSLin Ming method_obj->method.flags |= AOPOBJ_MODULE_LEVEL; 646*7f0c826aSLin Ming 647*7f0c826aSLin Ming if (!prev) { 648*7f0c826aSLin Ming acpi_gbl_module_code_list = method_obj; 649*7f0c826aSLin Ming } else { 650*7f0c826aSLin Ming prev->method.mutex = method_obj; 651*7f0c826aSLin Ming } 652*7f0c826aSLin Ming } else { 653*7f0c826aSLin Ming prev->method.aml_length += aml_length; 654*7f0c826aSLin Ming } 655*7f0c826aSLin Ming } 656*7f0c826aSLin Ming 657*7f0c826aSLin Ming /******************************************************************************* 658*7f0c826aSLin Ming * 65995b482a8SLen Brown * FUNCTION: acpi_ps_complete_op 66095b482a8SLen Brown * 66195b482a8SLen Brown * PARAMETERS: walk_state - Current state 66295b482a8SLen Brown * Op - Returned Op 66395b482a8SLen Brown * Status - Parse status before complete Op 66495b482a8SLen Brown * 66595b482a8SLen Brown * RETURN: Status 66695b482a8SLen Brown * 66795b482a8SLen Brown * DESCRIPTION: Complete Op 66895b482a8SLen Brown * 66995b482a8SLen Brown ******************************************************************************/ 67095b482a8SLen Brown 67195b482a8SLen Brown static acpi_status 67295b482a8SLen Brown acpi_ps_complete_op(struct acpi_walk_state *walk_state, 67395b482a8SLen Brown union acpi_parse_object **op, acpi_status status) 67495b482a8SLen Brown { 67595b482a8SLen Brown acpi_status status2; 67695b482a8SLen Brown 67795b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state); 67895b482a8SLen Brown 67995b482a8SLen Brown /* 68095b482a8SLen Brown * Finished one argument of the containing scope 68195b482a8SLen Brown */ 68295b482a8SLen Brown walk_state->parser_state.scope->parse_scope.arg_count--; 68395b482a8SLen Brown 68495b482a8SLen Brown /* Close this Op (will result in parse subtree deletion) */ 68595b482a8SLen Brown 68695b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, *op); 68795b482a8SLen Brown if (ACPI_FAILURE(status2)) { 68895b482a8SLen Brown return_ACPI_STATUS(status2); 68995b482a8SLen Brown } 69095b482a8SLen Brown 69195b482a8SLen Brown *op = NULL; 69295b482a8SLen Brown 69395b482a8SLen Brown switch (status) { 69495b482a8SLen Brown case AE_OK: 69595b482a8SLen Brown break; 69695b482a8SLen Brown 69795b482a8SLen Brown case AE_CTRL_TRANSFER: 69895b482a8SLen Brown 69995b482a8SLen Brown /* We are about to transfer to a called method */ 70095b482a8SLen Brown 70195b482a8SLen Brown walk_state->prev_op = NULL; 70295b482a8SLen Brown walk_state->prev_arg_types = walk_state->arg_types; 70395b482a8SLen Brown return_ACPI_STATUS(status); 70495b482a8SLen Brown 70595b482a8SLen Brown case AE_CTRL_END: 70695b482a8SLen Brown 70795b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 70895b482a8SLen Brown &walk_state->arg_types, 70995b482a8SLen Brown &walk_state->arg_count); 71095b482a8SLen Brown 71195b482a8SLen Brown if (*op) { 71295b482a8SLen Brown walk_state->op = *op; 71395b482a8SLen Brown walk_state->op_info = 71495b482a8SLen Brown acpi_ps_get_opcode_info((*op)->common.aml_opcode); 71595b482a8SLen Brown walk_state->opcode = (*op)->common.aml_opcode; 71695b482a8SLen Brown 71795b482a8SLen Brown status = walk_state->ascending_callback(walk_state); 71895b482a8SLen Brown status = 71995b482a8SLen Brown acpi_ps_next_parse_state(walk_state, *op, status); 72095b482a8SLen Brown 72195b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, *op); 72295b482a8SLen Brown if (ACPI_FAILURE(status2)) { 72395b482a8SLen Brown return_ACPI_STATUS(status2); 72495b482a8SLen Brown } 72595b482a8SLen Brown } 72695b482a8SLen Brown 72795b482a8SLen Brown status = AE_OK; 72895b482a8SLen Brown break; 72995b482a8SLen Brown 73095b482a8SLen Brown case AE_CTRL_BREAK: 73195b482a8SLen Brown case AE_CTRL_CONTINUE: 73295b482a8SLen Brown 73395b482a8SLen Brown /* Pop off scopes until we find the While */ 73495b482a8SLen Brown 73595b482a8SLen Brown while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) { 73695b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 73795b482a8SLen Brown &walk_state->arg_types, 73895b482a8SLen Brown &walk_state->arg_count); 73995b482a8SLen Brown } 74095b482a8SLen Brown 74195b482a8SLen Brown /* Close this iteration of the While loop */ 74295b482a8SLen Brown 74395b482a8SLen Brown walk_state->op = *op; 74495b482a8SLen Brown walk_state->op_info = 74595b482a8SLen Brown acpi_ps_get_opcode_info((*op)->common.aml_opcode); 74695b482a8SLen Brown walk_state->opcode = (*op)->common.aml_opcode; 74795b482a8SLen Brown 74895b482a8SLen Brown status = walk_state->ascending_callback(walk_state); 74995b482a8SLen Brown status = acpi_ps_next_parse_state(walk_state, *op, status); 75095b482a8SLen Brown 75195b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, *op); 75295b482a8SLen Brown if (ACPI_FAILURE(status2)) { 75395b482a8SLen Brown return_ACPI_STATUS(status2); 75495b482a8SLen Brown } 75595b482a8SLen Brown 75695b482a8SLen Brown status = AE_OK; 75795b482a8SLen Brown break; 75895b482a8SLen Brown 75995b482a8SLen Brown case AE_CTRL_TERMINATE: 76095b482a8SLen Brown 76195b482a8SLen Brown /* Clean up */ 76295b482a8SLen Brown do { 76395b482a8SLen Brown if (*op) { 76495b482a8SLen Brown status2 = 76595b482a8SLen Brown acpi_ps_complete_this_op(walk_state, *op); 76695b482a8SLen Brown if (ACPI_FAILURE(status2)) { 76795b482a8SLen Brown return_ACPI_STATUS(status2); 76895b482a8SLen Brown } 76995b482a8SLen Brown 77095b482a8SLen Brown acpi_ut_delete_generic_state 77195b482a8SLen Brown (acpi_ut_pop_generic_state 77295b482a8SLen Brown (&walk_state->control_state)); 77395b482a8SLen Brown } 77495b482a8SLen Brown 77595b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 77695b482a8SLen Brown &walk_state->arg_types, 77795b482a8SLen Brown &walk_state->arg_count); 77895b482a8SLen Brown 77995b482a8SLen Brown } while (*op); 78095b482a8SLen Brown 78195b482a8SLen Brown return_ACPI_STATUS(AE_OK); 78295b482a8SLen Brown 78395b482a8SLen Brown default: /* All other non-AE_OK status */ 78495b482a8SLen Brown 78595b482a8SLen Brown do { 78695b482a8SLen Brown if (*op) { 78795b482a8SLen Brown status2 = 78895b482a8SLen Brown acpi_ps_complete_this_op(walk_state, *op); 78995b482a8SLen Brown if (ACPI_FAILURE(status2)) { 79095b482a8SLen Brown return_ACPI_STATUS(status2); 79195b482a8SLen Brown } 79295b482a8SLen Brown } 79395b482a8SLen Brown 79495b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 79595b482a8SLen Brown &walk_state->arg_types, 79695b482a8SLen Brown &walk_state->arg_count); 79795b482a8SLen Brown 79895b482a8SLen Brown } while (*op); 79995b482a8SLen Brown 80095b482a8SLen Brown #if 0 80195b482a8SLen Brown /* 80295b482a8SLen Brown * TBD: Cleanup parse ops on error 80395b482a8SLen Brown */ 80495b482a8SLen Brown if (*op == NULL) { 80595b482a8SLen Brown acpi_ps_pop_scope(parser_state, op, 80695b482a8SLen Brown &walk_state->arg_types, 80795b482a8SLen Brown &walk_state->arg_count); 80895b482a8SLen Brown } 80995b482a8SLen Brown #endif 81095b482a8SLen Brown walk_state->prev_op = NULL; 81195b482a8SLen Brown walk_state->prev_arg_types = walk_state->arg_types; 81295b482a8SLen Brown return_ACPI_STATUS(status); 81395b482a8SLen Brown } 81495b482a8SLen Brown 81595b482a8SLen Brown /* This scope complete? */ 81695b482a8SLen Brown 81795b482a8SLen Brown if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) { 81895b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 81995b482a8SLen Brown &walk_state->arg_types, 82095b482a8SLen Brown &walk_state->arg_count); 82195b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op)); 82295b482a8SLen Brown } else { 82395b482a8SLen Brown *op = NULL; 82495b482a8SLen Brown } 82595b482a8SLen Brown 82695b482a8SLen Brown ACPI_PREEMPTION_POINT(); 82795b482a8SLen Brown 82895b482a8SLen Brown return_ACPI_STATUS(AE_OK); 82995b482a8SLen Brown } 83095b482a8SLen Brown 83195b482a8SLen Brown /******************************************************************************* 83295b482a8SLen Brown * 83395b482a8SLen Brown * FUNCTION: acpi_ps_complete_final_op 83495b482a8SLen Brown * 83595b482a8SLen Brown * PARAMETERS: walk_state - Current state 83695b482a8SLen Brown * Op - Current Op 83795b482a8SLen Brown * Status - Current parse status before complete last 83895b482a8SLen Brown * Op 83995b482a8SLen Brown * 84095b482a8SLen Brown * RETURN: Status 84195b482a8SLen Brown * 84295b482a8SLen Brown * DESCRIPTION: Complete last Op. 84395b482a8SLen Brown * 84495b482a8SLen Brown ******************************************************************************/ 84595b482a8SLen Brown 84695b482a8SLen Brown static acpi_status 84795b482a8SLen Brown acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, 84895b482a8SLen Brown union acpi_parse_object *op, acpi_status status) 84995b482a8SLen Brown { 85095b482a8SLen Brown acpi_status status2; 85195b482a8SLen Brown 85295b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state); 85395b482a8SLen Brown 85495b482a8SLen Brown /* 85595b482a8SLen Brown * Complete the last Op (if not completed), and clear the scope stack. 85695b482a8SLen Brown * It is easily possible to end an AML "package" with an unbounded number 85795b482a8SLen Brown * of open scopes (such as when several ASL blocks are closed with 85895b482a8SLen Brown * sequential closing braces). We want to terminate each one cleanly. 85995b482a8SLen Brown */ 86095b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n", 86195b482a8SLen Brown op)); 86295b482a8SLen Brown do { 86395b482a8SLen Brown if (op) { 86495b482a8SLen Brown if (walk_state->ascending_callback != NULL) { 86595b482a8SLen Brown walk_state->op = op; 86695b482a8SLen Brown walk_state->op_info = 86795b482a8SLen Brown acpi_ps_get_opcode_info(op->common. 86895b482a8SLen Brown aml_opcode); 86995b482a8SLen Brown walk_state->opcode = op->common.aml_opcode; 87095b482a8SLen Brown 87195b482a8SLen Brown status = 87295b482a8SLen Brown walk_state->ascending_callback(walk_state); 87395b482a8SLen Brown status = 87495b482a8SLen Brown acpi_ps_next_parse_state(walk_state, op, 87595b482a8SLen Brown status); 87695b482a8SLen Brown if (status == AE_CTRL_PENDING) { 87795b482a8SLen Brown status = 87895b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 87995b482a8SLen Brown AE_OK); 88095b482a8SLen Brown if (ACPI_FAILURE(status)) { 88195b482a8SLen Brown return_ACPI_STATUS(status); 88295b482a8SLen Brown } 88395b482a8SLen Brown } 88495b482a8SLen Brown 88595b482a8SLen Brown if (status == AE_CTRL_TERMINATE) { 88695b482a8SLen Brown status = AE_OK; 88795b482a8SLen Brown 88895b482a8SLen Brown /* Clean up */ 88995b482a8SLen Brown do { 89095b482a8SLen Brown if (op) { 89195b482a8SLen Brown status2 = 89295b482a8SLen Brown acpi_ps_complete_this_op 89395b482a8SLen Brown (walk_state, op); 89495b482a8SLen Brown if (ACPI_FAILURE 89595b482a8SLen Brown (status2)) { 89695b482a8SLen Brown return_ACPI_STATUS 89795b482a8SLen Brown (status2); 89895b482a8SLen Brown } 89995b482a8SLen Brown } 90095b482a8SLen Brown 90195b482a8SLen Brown acpi_ps_pop_scope(& 90295b482a8SLen Brown (walk_state-> 90395b482a8SLen Brown parser_state), 90495b482a8SLen Brown &op, 90595b482a8SLen Brown &walk_state-> 90695b482a8SLen Brown arg_types, 90795b482a8SLen Brown &walk_state-> 90895b482a8SLen Brown arg_count); 90995b482a8SLen Brown 91095b482a8SLen Brown } while (op); 91195b482a8SLen Brown 91295b482a8SLen Brown return_ACPI_STATUS(status); 91395b482a8SLen Brown } 91495b482a8SLen Brown 91595b482a8SLen Brown else if (ACPI_FAILURE(status)) { 91695b482a8SLen Brown 91795b482a8SLen Brown /* First error is most important */ 91895b482a8SLen Brown 91995b482a8SLen Brown (void) 92095b482a8SLen Brown acpi_ps_complete_this_op(walk_state, 92195b482a8SLen Brown op); 92295b482a8SLen Brown return_ACPI_STATUS(status); 92395b482a8SLen Brown } 92495b482a8SLen Brown } 92595b482a8SLen Brown 92695b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, op); 92795b482a8SLen Brown if (ACPI_FAILURE(status2)) { 92895b482a8SLen Brown return_ACPI_STATUS(status2); 92995b482a8SLen Brown } 93095b482a8SLen Brown } 93195b482a8SLen Brown 93295b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), &op, 93395b482a8SLen Brown &walk_state->arg_types, 93495b482a8SLen Brown &walk_state->arg_count); 93595b482a8SLen Brown 93695b482a8SLen Brown } while (op); 93795b482a8SLen Brown 93895b482a8SLen Brown return_ACPI_STATUS(status); 93995b482a8SLen Brown } 94095b482a8SLen Brown 94195b482a8SLen Brown /******************************************************************************* 94295b482a8SLen Brown * 94395b482a8SLen Brown * FUNCTION: acpi_ps_parse_loop 94495b482a8SLen Brown * 94595b482a8SLen Brown * PARAMETERS: walk_state - Current state 94695b482a8SLen Brown * 94795b482a8SLen Brown * RETURN: Status 94895b482a8SLen Brown * 94995b482a8SLen Brown * DESCRIPTION: Parse AML (pointed to by the current parser state) and return 95095b482a8SLen Brown * a tree of ops. 95195b482a8SLen Brown * 95295b482a8SLen Brown ******************************************************************************/ 95395b482a8SLen Brown 95495b482a8SLen Brown acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) 95595b482a8SLen Brown { 95695b482a8SLen Brown acpi_status status = AE_OK; 95795b482a8SLen Brown union acpi_parse_object *op = NULL; /* current op */ 95895b482a8SLen Brown struct acpi_parse_state *parser_state; 95995b482a8SLen Brown u8 *aml_op_start = NULL; 96095b482a8SLen Brown 96195b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state); 96295b482a8SLen Brown 96395b482a8SLen Brown if (walk_state->descending_callback == NULL) { 96495b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 96595b482a8SLen Brown } 96695b482a8SLen Brown 96795b482a8SLen Brown parser_state = &walk_state->parser_state; 96895b482a8SLen Brown walk_state->arg_types = 0; 96995b482a8SLen Brown 97095b482a8SLen Brown #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) 97195b482a8SLen Brown 97295b482a8SLen Brown if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { 97395b482a8SLen Brown 97495b482a8SLen Brown /* We are restarting a preempted control method */ 97595b482a8SLen Brown 97695b482a8SLen Brown if (acpi_ps_has_completed_scope(parser_state)) { 97795b482a8SLen Brown /* 97895b482a8SLen Brown * We must check if a predicate to an IF or WHILE statement 97995b482a8SLen Brown * was just completed 98095b482a8SLen Brown */ 98195b482a8SLen Brown if ((parser_state->scope->parse_scope.op) && 98295b482a8SLen Brown ((parser_state->scope->parse_scope.op->common. 98395b482a8SLen Brown aml_opcode == AML_IF_OP) 98495b482a8SLen Brown || (parser_state->scope->parse_scope.op->common. 98595b482a8SLen Brown aml_opcode == AML_WHILE_OP)) 98695b482a8SLen Brown && (walk_state->control_state) 98795b482a8SLen Brown && (walk_state->control_state->common.state == 98895b482a8SLen Brown ACPI_CONTROL_PREDICATE_EXECUTING)) { 98995b482a8SLen Brown /* 99095b482a8SLen Brown * A predicate was just completed, get the value of the 99195b482a8SLen Brown * predicate and branch based on that value 99295b482a8SLen Brown */ 99395b482a8SLen Brown walk_state->op = NULL; 99495b482a8SLen Brown status = 99595b482a8SLen Brown acpi_ds_get_predicate_value(walk_state, 99695b482a8SLen Brown ACPI_TO_POINTER 99795b482a8SLen Brown (TRUE)); 99895b482a8SLen Brown if (ACPI_FAILURE(status) 99995b482a8SLen Brown && ((status & AE_CODE_MASK) != 100095b482a8SLen Brown AE_CODE_CONTROL)) { 100195b482a8SLen Brown if (status == AE_AML_NO_RETURN_VALUE) { 100295b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, 100395b482a8SLen Brown "Invoked method did not return a value")); 100495b482a8SLen Brown 100595b482a8SLen Brown } 100695b482a8SLen Brown 100795b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, 100895b482a8SLen Brown "GetPredicate Failed")); 100995b482a8SLen Brown return_ACPI_STATUS(status); 101095b482a8SLen Brown } 101195b482a8SLen Brown 101295b482a8SLen Brown status = 101395b482a8SLen Brown acpi_ps_next_parse_state(walk_state, op, 101495b482a8SLen Brown status); 101595b482a8SLen Brown } 101695b482a8SLen Brown 101795b482a8SLen Brown acpi_ps_pop_scope(parser_state, &op, 101895b482a8SLen Brown &walk_state->arg_types, 101995b482a8SLen Brown &walk_state->arg_count); 102095b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 102195b482a8SLen Brown "Popped scope, Op=%p\n", op)); 102295b482a8SLen Brown } else if (walk_state->prev_op) { 102395b482a8SLen Brown 102495b482a8SLen Brown /* We were in the middle of an op */ 102595b482a8SLen Brown 102695b482a8SLen Brown op = walk_state->prev_op; 102795b482a8SLen Brown walk_state->arg_types = walk_state->prev_arg_types; 102895b482a8SLen Brown } 102995b482a8SLen Brown } 103095b482a8SLen Brown #endif 103195b482a8SLen Brown 103295b482a8SLen Brown /* Iterative parsing loop, while there is more AML to process: */ 103395b482a8SLen Brown 103495b482a8SLen Brown while ((parser_state->aml < parser_state->aml_end) || (op)) { 103595b482a8SLen Brown aml_op_start = parser_state->aml; 103695b482a8SLen Brown if (!op) { 103795b482a8SLen Brown status = 103895b482a8SLen Brown acpi_ps_create_op(walk_state, aml_op_start, &op); 103995b482a8SLen Brown if (ACPI_FAILURE(status)) { 104095b482a8SLen Brown if (status == AE_CTRL_PARSE_CONTINUE) { 104195b482a8SLen Brown continue; 104295b482a8SLen Brown } 104395b482a8SLen Brown 104495b482a8SLen Brown if (status == AE_CTRL_PARSE_PENDING) { 104595b482a8SLen Brown status = AE_OK; 104695b482a8SLen Brown } 104795b482a8SLen Brown 104895b482a8SLen Brown status = 104995b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 105095b482a8SLen Brown status); 105195b482a8SLen Brown if (ACPI_FAILURE(status)) { 105295b482a8SLen Brown return_ACPI_STATUS(status); 105395b482a8SLen Brown } 105495b482a8SLen Brown 105595b482a8SLen Brown continue; 105695b482a8SLen Brown } 105795b482a8SLen Brown 105895b482a8SLen Brown op->common.aml_offset = walk_state->aml_offset; 105995b482a8SLen Brown 106095b482a8SLen Brown if (walk_state->op_info) { 106195b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 106295b482a8SLen Brown "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", 106395b482a8SLen Brown (u32) op->common.aml_opcode, 106495b482a8SLen Brown walk_state->op_info->name, op, 106595b482a8SLen Brown parser_state->aml, 106695b482a8SLen Brown op->common.aml_offset)); 106795b482a8SLen Brown } 106895b482a8SLen Brown } 106995b482a8SLen Brown 107095b482a8SLen Brown /* 107195b482a8SLen Brown * Start arg_count at zero because we don't know if there are 107295b482a8SLen Brown * any args yet 107395b482a8SLen Brown */ 107495b482a8SLen Brown walk_state->arg_count = 0; 107595b482a8SLen Brown 107695b482a8SLen Brown /* Are there any arguments that must be processed? */ 107795b482a8SLen Brown 107895b482a8SLen Brown if (walk_state->arg_types) { 107995b482a8SLen Brown 108095b482a8SLen Brown /* Get arguments */ 108195b482a8SLen Brown 108295b482a8SLen Brown status = 108395b482a8SLen Brown acpi_ps_get_arguments(walk_state, aml_op_start, op); 108495b482a8SLen Brown if (ACPI_FAILURE(status)) { 108595b482a8SLen Brown status = 108695b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 108795b482a8SLen Brown status); 108895b482a8SLen Brown if (ACPI_FAILURE(status)) { 108995b482a8SLen Brown return_ACPI_STATUS(status); 109095b482a8SLen Brown } 109195b482a8SLen Brown 109295b482a8SLen Brown continue; 109395b482a8SLen Brown } 109495b482a8SLen Brown } 109595b482a8SLen Brown 109695b482a8SLen Brown /* Check for arguments that need to be processed */ 109795b482a8SLen Brown 109895b482a8SLen Brown if (walk_state->arg_count) { 109995b482a8SLen Brown /* 110095b482a8SLen Brown * There are arguments (complex ones), push Op and 110195b482a8SLen Brown * prepare for argument 110295b482a8SLen Brown */ 110395b482a8SLen Brown status = acpi_ps_push_scope(parser_state, op, 110495b482a8SLen Brown walk_state->arg_types, 110595b482a8SLen Brown walk_state->arg_count); 110695b482a8SLen Brown if (ACPI_FAILURE(status)) { 110795b482a8SLen Brown status = 110895b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 110995b482a8SLen Brown status); 111095b482a8SLen Brown if (ACPI_FAILURE(status)) { 111195b482a8SLen Brown return_ACPI_STATUS(status); 111295b482a8SLen Brown } 111395b482a8SLen Brown 111495b482a8SLen Brown continue; 111595b482a8SLen Brown } 111695b482a8SLen Brown 111795b482a8SLen Brown op = NULL; 111895b482a8SLen Brown continue; 111995b482a8SLen Brown } 112095b482a8SLen Brown 112195b482a8SLen Brown /* 112295b482a8SLen Brown * All arguments have been processed -- Op is complete, 112395b482a8SLen Brown * prepare for next 112495b482a8SLen Brown */ 112595b482a8SLen Brown walk_state->op_info = 112695b482a8SLen Brown acpi_ps_get_opcode_info(op->common.aml_opcode); 112795b482a8SLen Brown if (walk_state->op_info->flags & AML_NAMED) { 112895b482a8SLen Brown if (acpi_gbl_depth) { 112995b482a8SLen Brown acpi_gbl_depth--; 113095b482a8SLen Brown } 113195b482a8SLen Brown 113295b482a8SLen Brown if (op->common.aml_opcode == AML_REGION_OP || 113395b482a8SLen Brown op->common.aml_opcode == AML_DATA_REGION_OP) { 113495b482a8SLen Brown /* 113595b482a8SLen Brown * Skip parsing of control method or opregion body, 113695b482a8SLen Brown * because we don't have enough info in the first pass 113795b482a8SLen Brown * to parse them correctly. 113895b482a8SLen Brown * 113995b482a8SLen Brown * Completed parsing an op_region declaration, we now 114095b482a8SLen Brown * know the length. 114195b482a8SLen Brown */ 114295b482a8SLen Brown op->named.length = 114395b482a8SLen Brown (u32) (parser_state->aml - op->named.data); 114495b482a8SLen Brown } 114595b482a8SLen Brown } 114695b482a8SLen Brown 114795b482a8SLen Brown if (walk_state->op_info->flags & AML_CREATE) { 114895b482a8SLen Brown /* 114995b482a8SLen Brown * Backup to beginning of create_xXXfield declaration (1 for 115095b482a8SLen Brown * Opcode) 115195b482a8SLen Brown * 115295b482a8SLen Brown * body_length is unknown until we parse the body 115395b482a8SLen Brown */ 115495b482a8SLen Brown op->named.length = 115595b482a8SLen Brown (u32) (parser_state->aml - op->named.data); 115695b482a8SLen Brown } 115795b482a8SLen Brown 115895b482a8SLen Brown if (op->common.aml_opcode == AML_BANK_FIELD_OP) { 115995b482a8SLen Brown /* 116095b482a8SLen Brown * Backup to beginning of bank_field declaration 116195b482a8SLen Brown * 116295b482a8SLen Brown * body_length is unknown until we parse the body 116395b482a8SLen Brown */ 116495b482a8SLen Brown op->named.length = 116595b482a8SLen Brown (u32) (parser_state->aml - op->named.data); 116695b482a8SLen Brown } 116795b482a8SLen Brown 116895b482a8SLen Brown /* This op complete, notify the dispatcher */ 116995b482a8SLen Brown 117095b482a8SLen Brown if (walk_state->ascending_callback != NULL) { 117195b482a8SLen Brown walk_state->op = op; 117295b482a8SLen Brown walk_state->opcode = op->common.aml_opcode; 117395b482a8SLen Brown 117495b482a8SLen Brown status = walk_state->ascending_callback(walk_state); 117595b482a8SLen Brown status = 117695b482a8SLen Brown acpi_ps_next_parse_state(walk_state, op, status); 117795b482a8SLen Brown if (status == AE_CTRL_PENDING) { 117895b482a8SLen Brown status = AE_OK; 117995b482a8SLen Brown } 118095b482a8SLen Brown } 118195b482a8SLen Brown 118295b482a8SLen Brown status = acpi_ps_complete_op(walk_state, &op, status); 118395b482a8SLen Brown if (ACPI_FAILURE(status)) { 118495b482a8SLen Brown return_ACPI_STATUS(status); 118595b482a8SLen Brown } 118695b482a8SLen Brown 118795b482a8SLen Brown } /* while parser_state->Aml */ 118895b482a8SLen Brown 118995b482a8SLen Brown status = acpi_ps_complete_final_op(walk_state, op, status); 119095b482a8SLen Brown return_ACPI_STATUS(status); 119195b482a8SLen Brown } 1192