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