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 138*00eb3255SBob Moore if (walk_state->pass_number == 2) { 13995b482a8SLen Brown ACPI_ERROR((AE_INFO, 140*00eb3255SBob Moore "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring", 141*00eb3255SBob Moore walk_state->opcode, 142*00eb3255SBob Moore walk_state->aml_offset + 143*00eb3255SBob Moore sizeof(struct acpi_table_header))); 14495b482a8SLen Brown 14595b482a8SLen Brown ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); 14695b482a8SLen Brown 147*00eb3255SBob Moore #ifdef ACPI_ASL_COMPILER 148*00eb3255SBob Moore 149*00eb3255SBob Moore acpi_os_printf 150*00eb3255SBob Moore ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n", 151*00eb3255SBob Moore walk_state->opcode, 152*00eb3255SBob Moore walk_state->aml_offset + 153*00eb3255SBob Moore sizeof(struct acpi_table_header)); 154*00eb3255SBob Moore 155*00eb3255SBob Moore /* TBD: Pass current offset to dump_buffer */ 156*00eb3255SBob Moore 157*00eb3255SBob Moore acpi_ut_dump_buffer2(((u8 *)walk_state->parser_state. 158*00eb3255SBob Moore aml - 16), 48, DB_BYTE_DISPLAY); 159*00eb3255SBob Moore acpi_os_printf(" */\n"); 160*00eb3255SBob Moore #endif 161*00eb3255SBob Moore } 162*00eb3255SBob Moore 163*00eb3255SBob Moore /* Increment past one or two-byte opcode */ 16495b482a8SLen Brown 16595b482a8SLen Brown walk_state->parser_state.aml++; 166*00eb3255SBob Moore if (walk_state->opcode > 0xFF) { 167*00eb3255SBob Moore walk_state->parser_state.aml++; 168*00eb3255SBob Moore } 169*00eb3255SBob Moore 17095b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); 17195b482a8SLen Brown 17295b482a8SLen Brown default: 17395b482a8SLen Brown 17495b482a8SLen Brown /* Found opcode info, this is a normal opcode */ 17595b482a8SLen Brown 17695b482a8SLen Brown walk_state->parser_state.aml += 17795b482a8SLen Brown acpi_ps_get_opcode_size(walk_state->opcode); 17895b482a8SLen Brown walk_state->arg_types = walk_state->op_info->parse_args; 17995b482a8SLen Brown break; 18095b482a8SLen Brown } 18195b482a8SLen Brown 18295b482a8SLen Brown return_ACPI_STATUS(AE_OK); 18395b482a8SLen Brown } 18495b482a8SLen Brown 18595b482a8SLen Brown /******************************************************************************* 18695b482a8SLen Brown * 18795b482a8SLen Brown * FUNCTION: acpi_ps_build_named_op 18895b482a8SLen Brown * 18995b482a8SLen Brown * PARAMETERS: walk_state - Current state 19095b482a8SLen Brown * aml_op_start - Begin of named Op in AML 19195b482a8SLen Brown * unnamed_op - Early Op (not a named Op) 192ba494beeSBob Moore * op - Returned Op 19395b482a8SLen Brown * 19495b482a8SLen Brown * RETURN: Status 19595b482a8SLen Brown * 19695b482a8SLen Brown * DESCRIPTION: Parse a named Op 19795b482a8SLen Brown * 19895b482a8SLen Brown ******************************************************************************/ 19995b482a8SLen Brown 20095b482a8SLen Brown static acpi_status 20195b482a8SLen Brown acpi_ps_build_named_op(struct acpi_walk_state *walk_state, 20295b482a8SLen Brown u8 * aml_op_start, 20395b482a8SLen Brown union acpi_parse_object *unnamed_op, 20495b482a8SLen Brown union acpi_parse_object **op) 20595b482a8SLen Brown { 20695b482a8SLen Brown acpi_status status = AE_OK; 20795b482a8SLen Brown union acpi_parse_object *arg = NULL; 20895b482a8SLen Brown 20995b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); 21095b482a8SLen Brown 21195b482a8SLen Brown unnamed_op->common.value.arg = NULL; 21295b482a8SLen Brown unnamed_op->common.arg_list_length = 0; 21395b482a8SLen Brown unnamed_op->common.aml_opcode = walk_state->opcode; 21495b482a8SLen Brown 21595b482a8SLen Brown /* 21695b482a8SLen Brown * Get and append arguments until we find the node that contains 21795b482a8SLen Brown * the name (the type ARGP_NAME). 21895b482a8SLen Brown */ 21995b482a8SLen Brown while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && 22095b482a8SLen Brown (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) { 22195b482a8SLen Brown status = 22295b482a8SLen Brown acpi_ps_get_next_arg(walk_state, 22395b482a8SLen Brown &(walk_state->parser_state), 22495b482a8SLen Brown GET_CURRENT_ARG_TYPE(walk_state-> 22595b482a8SLen Brown arg_types), &arg); 22695b482a8SLen Brown if (ACPI_FAILURE(status)) { 22795b482a8SLen Brown return_ACPI_STATUS(status); 22895b482a8SLen Brown } 22995b482a8SLen Brown 23095b482a8SLen Brown acpi_ps_append_arg(unnamed_op, arg); 23195b482a8SLen Brown INCREMENT_ARG_LIST(walk_state->arg_types); 23295b482a8SLen Brown } 23395b482a8SLen Brown 23495b482a8SLen Brown /* 23595b482a8SLen Brown * Make sure that we found a NAME and didn't run out of arguments 23695b482a8SLen Brown */ 23795b482a8SLen Brown if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) { 23895b482a8SLen Brown return_ACPI_STATUS(AE_AML_NO_OPERAND); 23995b482a8SLen Brown } 24095b482a8SLen Brown 24195b482a8SLen Brown /* We know that this arg is a name, move to next arg */ 24295b482a8SLen Brown 24395b482a8SLen Brown INCREMENT_ARG_LIST(walk_state->arg_types); 24495b482a8SLen Brown 24595b482a8SLen Brown /* 24695b482a8SLen Brown * Find the object. This will either insert the object into 24795b482a8SLen Brown * the namespace or simply look it up 24895b482a8SLen Brown */ 24995b482a8SLen Brown walk_state->op = NULL; 25095b482a8SLen Brown 25195b482a8SLen Brown status = walk_state->descending_callback(walk_state, op); 25295b482a8SLen Brown if (ACPI_FAILURE(status)) { 25395b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog")); 25495b482a8SLen Brown return_ACPI_STATUS(status); 25595b482a8SLen Brown } 25695b482a8SLen Brown 25795b482a8SLen Brown if (!*op) { 25895b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); 25995b482a8SLen Brown } 26095b482a8SLen Brown 26195b482a8SLen Brown status = acpi_ps_next_parse_state(walk_state, *op, status); 26295b482a8SLen Brown if (ACPI_FAILURE(status)) { 26395b482a8SLen Brown if (status == AE_CTRL_PENDING) { 26495b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_PENDING); 26595b482a8SLen Brown } 26695b482a8SLen Brown return_ACPI_STATUS(status); 26795b482a8SLen Brown } 26895b482a8SLen Brown 26995b482a8SLen Brown acpi_ps_append_arg(*op, unnamed_op->common.value.arg); 27095b482a8SLen Brown acpi_gbl_depth++; 27195b482a8SLen Brown 27295b482a8SLen Brown if ((*op)->common.aml_opcode == AML_REGION_OP || 27395b482a8SLen Brown (*op)->common.aml_opcode == AML_DATA_REGION_OP) { 27495b482a8SLen Brown /* 27595b482a8SLen Brown * Defer final parsing of an operation_region body, because we don't 27695b482a8SLen Brown * have enough info in the first pass to parse it correctly (i.e., 27795b482a8SLen Brown * there may be method calls within the term_arg elements of the body.) 27895b482a8SLen Brown * 27995b482a8SLen Brown * However, we must continue parsing because the opregion is not a 28095b482a8SLen Brown * standalone package -- we don't know where the end is at this point. 28195b482a8SLen Brown * 28295b482a8SLen Brown * (Length is unknown until parse of the body complete) 28395b482a8SLen Brown */ 28495b482a8SLen Brown (*op)->named.data = aml_op_start; 28595b482a8SLen Brown (*op)->named.length = 0; 28695b482a8SLen Brown } 28795b482a8SLen Brown 28895b482a8SLen Brown return_ACPI_STATUS(AE_OK); 28995b482a8SLen Brown } 29095b482a8SLen Brown 29195b482a8SLen Brown /******************************************************************************* 29295b482a8SLen Brown * 29395b482a8SLen Brown * FUNCTION: acpi_ps_create_op 29495b482a8SLen Brown * 29595b482a8SLen Brown * PARAMETERS: walk_state - Current state 29695b482a8SLen Brown * aml_op_start - Op start in AML 29795b482a8SLen Brown * new_op - Returned Op 29895b482a8SLen Brown * 29995b482a8SLen Brown * RETURN: Status 30095b482a8SLen Brown * 30195b482a8SLen Brown * DESCRIPTION: Get Op from AML 30295b482a8SLen Brown * 30395b482a8SLen Brown ******************************************************************************/ 30495b482a8SLen Brown 30595b482a8SLen Brown static acpi_status 30695b482a8SLen Brown acpi_ps_create_op(struct acpi_walk_state *walk_state, 30795b482a8SLen Brown u8 * aml_op_start, union acpi_parse_object **new_op) 30895b482a8SLen Brown { 30995b482a8SLen Brown acpi_status status = AE_OK; 31095b482a8SLen Brown union acpi_parse_object *op; 31195b482a8SLen Brown union acpi_parse_object *named_op = NULL; 31295b482a8SLen Brown union acpi_parse_object *parent_scope; 31395b482a8SLen Brown u8 argument_count; 31495b482a8SLen Brown const struct acpi_opcode_info *op_info; 31595b482a8SLen Brown 31695b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); 31795b482a8SLen Brown 31895b482a8SLen Brown status = acpi_ps_get_aml_opcode(walk_state); 31995b482a8SLen Brown if (status == AE_CTRL_PARSE_CONTINUE) { 32095b482a8SLen Brown return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); 32195b482a8SLen Brown } 32295b482a8SLen Brown 32395b482a8SLen Brown /* Create Op structure and append to parent's argument list */ 32495b482a8SLen Brown 32595b482a8SLen Brown walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); 32695b482a8SLen Brown op = acpi_ps_alloc_op(walk_state->opcode); 32795b482a8SLen Brown if (!op) { 32895b482a8SLen Brown return_ACPI_STATUS(AE_NO_MEMORY); 32995b482a8SLen Brown } 33095b482a8SLen Brown 33195b482a8SLen Brown if (walk_state->op_info->flags & AML_NAMED) { 33295b482a8SLen Brown status = 33395b482a8SLen Brown acpi_ps_build_named_op(walk_state, aml_op_start, op, 33495b482a8SLen Brown &named_op); 33595b482a8SLen Brown acpi_ps_free_op(op); 33695b482a8SLen Brown if (ACPI_FAILURE(status)) { 33795b482a8SLen Brown return_ACPI_STATUS(status); 33895b482a8SLen Brown } 33995b482a8SLen Brown 34095b482a8SLen Brown *new_op = named_op; 34195b482a8SLen Brown return_ACPI_STATUS(AE_OK); 34295b482a8SLen Brown } 34395b482a8SLen Brown 34495b482a8SLen Brown /* Not a named opcode, just allocate Op and append to parent */ 34595b482a8SLen Brown 34695b482a8SLen Brown if (walk_state->op_info->flags & AML_CREATE) { 34795b482a8SLen Brown /* 348ba494beeSBob Moore * Backup to beginning of create_XXXfield declaration 34995b482a8SLen Brown * body_length is unknown until we parse the body 35095b482a8SLen Brown */ 35195b482a8SLen Brown op->named.data = aml_op_start; 35295b482a8SLen Brown op->named.length = 0; 35395b482a8SLen Brown } 35495b482a8SLen Brown 35595b482a8SLen Brown if (walk_state->opcode == AML_BANK_FIELD_OP) { 35695b482a8SLen Brown /* 35795b482a8SLen Brown * Backup to beginning of bank_field declaration 35895b482a8SLen Brown * body_length is unknown until we parse the body 35995b482a8SLen Brown */ 36095b482a8SLen Brown op->named.data = aml_op_start; 36195b482a8SLen Brown op->named.length = 0; 36295b482a8SLen Brown } 36395b482a8SLen Brown 36495b482a8SLen Brown parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state)); 36595b482a8SLen Brown acpi_ps_append_arg(parent_scope, op); 36695b482a8SLen Brown 36795b482a8SLen Brown if (parent_scope) { 36895b482a8SLen Brown op_info = 36995b482a8SLen Brown acpi_ps_get_opcode_info(parent_scope->common.aml_opcode); 37095b482a8SLen Brown if (op_info->flags & AML_HAS_TARGET) { 37195b482a8SLen Brown argument_count = 37295b482a8SLen Brown acpi_ps_get_argument_count(op_info->type); 37395b482a8SLen Brown if (parent_scope->common.arg_list_length > 37495b482a8SLen Brown argument_count) { 37595b482a8SLen Brown op->common.flags |= ACPI_PARSEOP_TARGET; 37695b482a8SLen Brown } 37795b482a8SLen Brown } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) { 37895b482a8SLen Brown op->common.flags |= ACPI_PARSEOP_TARGET; 37995b482a8SLen Brown } 38095b482a8SLen Brown } 38195b482a8SLen Brown 38295b482a8SLen Brown if (walk_state->descending_callback != NULL) { 38395b482a8SLen Brown /* 38495b482a8SLen Brown * Find the object. This will either insert the object into 38595b482a8SLen Brown * the namespace or simply look it up 38695b482a8SLen Brown */ 38795b482a8SLen Brown walk_state->op = *new_op = op; 38895b482a8SLen Brown 38995b482a8SLen Brown status = walk_state->descending_callback(walk_state, &op); 39095b482a8SLen Brown status = acpi_ps_next_parse_state(walk_state, op, status); 39195b482a8SLen Brown if (status == AE_CTRL_PENDING) { 39295b482a8SLen Brown status = AE_CTRL_PARSE_PENDING; 39395b482a8SLen Brown } 39495b482a8SLen Brown } 39595b482a8SLen Brown 39695b482a8SLen Brown return_ACPI_STATUS(status); 39795b482a8SLen Brown } 39895b482a8SLen Brown 39995b482a8SLen Brown /******************************************************************************* 40095b482a8SLen Brown * 40195b482a8SLen Brown * FUNCTION: acpi_ps_get_arguments 40295b482a8SLen Brown * 40395b482a8SLen Brown * PARAMETERS: walk_state - Current state 40495b482a8SLen Brown * aml_op_start - Op start in AML 405ba494beeSBob Moore * op - Current Op 40695b482a8SLen Brown * 40795b482a8SLen Brown * RETURN: Status 40895b482a8SLen Brown * 40995b482a8SLen Brown * DESCRIPTION: Get arguments for passed Op. 41095b482a8SLen Brown * 41195b482a8SLen Brown ******************************************************************************/ 41295b482a8SLen Brown 41395b482a8SLen Brown static acpi_status 41495b482a8SLen Brown acpi_ps_get_arguments(struct acpi_walk_state *walk_state, 41595b482a8SLen Brown u8 * aml_op_start, union acpi_parse_object *op) 41695b482a8SLen Brown { 41795b482a8SLen Brown acpi_status status = AE_OK; 41895b482a8SLen Brown union acpi_parse_object *arg = NULL; 4197f0c826aSLin Ming const struct acpi_opcode_info *op_info; 42095b482a8SLen Brown 42195b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); 42295b482a8SLen Brown 42395b482a8SLen Brown switch (op->common.aml_opcode) { 42495b482a8SLen Brown case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ 42595b482a8SLen Brown case AML_WORD_OP: /* AML_WORDDATA_ARG */ 42695b482a8SLen Brown case AML_DWORD_OP: /* AML_DWORDATA_ARG */ 42795b482a8SLen Brown case AML_QWORD_OP: /* AML_QWORDATA_ARG */ 42895b482a8SLen Brown case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ 42995b482a8SLen Brown 43095b482a8SLen Brown /* Fill in constant or string argument directly */ 43195b482a8SLen Brown 43295b482a8SLen Brown acpi_ps_get_next_simple_arg(&(walk_state->parser_state), 43395b482a8SLen Brown GET_CURRENT_ARG_TYPE(walk_state-> 43495b482a8SLen Brown arg_types), 43595b482a8SLen Brown op); 43695b482a8SLen Brown break; 43795b482a8SLen Brown 43895b482a8SLen Brown case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ 43995b482a8SLen Brown 44095b482a8SLen Brown status = 44195b482a8SLen Brown acpi_ps_get_next_namepath(walk_state, 44295b482a8SLen Brown &(walk_state->parser_state), op, 44395b482a8SLen Brown 1); 44495b482a8SLen Brown if (ACPI_FAILURE(status)) { 44595b482a8SLen Brown return_ACPI_STATUS(status); 44695b482a8SLen Brown } 44795b482a8SLen Brown 44895b482a8SLen Brown walk_state->arg_types = 0; 44995b482a8SLen Brown break; 45095b482a8SLen Brown 45195b482a8SLen Brown default: 45295b482a8SLen Brown /* 45395b482a8SLen Brown * Op is not a constant or string, append each argument to the Op 45495b482a8SLen Brown */ 45595b482a8SLen Brown while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) 45695b482a8SLen Brown && !walk_state->arg_count) { 45795b482a8SLen Brown walk_state->aml_offset = 45895b482a8SLen Brown (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, 45995b482a8SLen Brown walk_state->parser_state. 46095b482a8SLen Brown aml_start); 46195b482a8SLen Brown 46295b482a8SLen Brown status = 46395b482a8SLen Brown acpi_ps_get_next_arg(walk_state, 46495b482a8SLen Brown &(walk_state->parser_state), 46595b482a8SLen Brown GET_CURRENT_ARG_TYPE 46695b482a8SLen Brown (walk_state->arg_types), &arg); 46795b482a8SLen Brown if (ACPI_FAILURE(status)) { 46895b482a8SLen Brown return_ACPI_STATUS(status); 46995b482a8SLen Brown } 47095b482a8SLen Brown 47195b482a8SLen Brown if (arg) { 47295b482a8SLen Brown arg->common.aml_offset = walk_state->aml_offset; 47395b482a8SLen Brown acpi_ps_append_arg(op, arg); 47495b482a8SLen Brown } 47595b482a8SLen Brown 47695b482a8SLen Brown INCREMENT_ARG_LIST(walk_state->arg_types); 47795b482a8SLen Brown } 47895b482a8SLen Brown 4797f0c826aSLin Ming /* 4807f0c826aSLin Ming * Handle executable code at "module-level". This refers to 4817f0c826aSLin Ming * executable opcodes that appear outside of any control method. 4827f0c826aSLin Ming */ 4837f0c826aSLin Ming if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2) && 48495b482a8SLen Brown ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { 48595b482a8SLen Brown /* 48695b482a8SLen Brown * We want to skip If/Else/While constructs during Pass1 because we 48795b482a8SLen Brown * want to actually conditionally execute the code during Pass2. 48895b482a8SLen Brown * 48995b482a8SLen Brown * Except for disassembly, where we always want to walk the 49095b482a8SLen Brown * If/Else/While packages 49195b482a8SLen Brown */ 49295b482a8SLen Brown switch (op->common.aml_opcode) { 49395b482a8SLen Brown case AML_IF_OP: 49495b482a8SLen Brown case AML_ELSE_OP: 49595b482a8SLen Brown case AML_WHILE_OP: 49695b482a8SLen Brown 4977f0c826aSLin Ming /* 4987f0c826aSLin Ming * Currently supported module-level opcodes are: 4997f0c826aSLin Ming * IF/ELSE/WHILE. These appear to be the most common, 5007f0c826aSLin Ming * and easiest to support since they open an AML 5017f0c826aSLin Ming * package. 5027f0c826aSLin Ming */ 5037f0c826aSLin Ming if (walk_state->pass_number == 5047f0c826aSLin Ming ACPI_IMODE_LOAD_PASS1) { 5059a884ab6SLin Ming acpi_ps_link_module_code(op->common. 5069a884ab6SLin Ming parent, 5079a884ab6SLin Ming aml_op_start, 5089a884ab6SLin Ming (u32) 5099a884ab6SLin Ming (walk_state-> 5107f0c826aSLin Ming parser_state. 5117f0c826aSLin Ming pkg_end - 5129a884ab6SLin Ming aml_op_start), 5137f0c826aSLin Ming walk_state-> 5147f0c826aSLin Ming owner_id); 5157f0c826aSLin Ming } 5167f0c826aSLin Ming 51795b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 51895b482a8SLen Brown "Pass1: Skipping an If/Else/While body\n")); 51995b482a8SLen Brown 52095b482a8SLen Brown /* Skip body of if/else/while in pass 1 */ 52195b482a8SLen Brown 52295b482a8SLen Brown walk_state->parser_state.aml = 52395b482a8SLen Brown walk_state->parser_state.pkg_end; 52495b482a8SLen Brown walk_state->arg_count = 0; 52595b482a8SLen Brown break; 52695b482a8SLen Brown 52795b482a8SLen Brown default: 5287f0c826aSLin Ming /* 5297f0c826aSLin Ming * Check for an unsupported executable opcode at module 5307f0c826aSLin Ming * level. We must be in PASS1, the parent must be a SCOPE, 5317f0c826aSLin Ming * The opcode class must be EXECUTE, and the opcode must 5327f0c826aSLin Ming * not be an argument to another opcode. 5337f0c826aSLin Ming */ 5347f0c826aSLin Ming if ((walk_state->pass_number == 5357f0c826aSLin Ming ACPI_IMODE_LOAD_PASS1) 5367f0c826aSLin Ming && (op->common.parent->common.aml_opcode == 5377f0c826aSLin Ming AML_SCOPE_OP)) { 5387f0c826aSLin Ming op_info = 5397f0c826aSLin Ming acpi_ps_get_opcode_info(op->common. 5407f0c826aSLin Ming aml_opcode); 5417f0c826aSLin Ming if ((op_info->class == 5427f0c826aSLin Ming AML_CLASS_EXECUTE) && (!arg)) { 5437f0c826aSLin Ming ACPI_WARNING((AE_INFO, 544*00eb3255SBob Moore "Unsupported module-level executable opcode " 545*00eb3255SBob Moore "0x%.2X at table offset 0x%.4X", 546*00eb3255SBob Moore op->common. 547*00eb3255SBob Moore aml_opcode, 548*00eb3255SBob Moore (u32) 549*00eb3255SBob Moore (ACPI_PTR_DIFF 550*00eb3255SBob Moore (aml_op_start, 551*00eb3255SBob Moore walk_state-> 552*00eb3255SBob Moore parser_state. 553*00eb3255SBob Moore aml_start) + 554*00eb3255SBob Moore sizeof(struct 555*00eb3255SBob Moore acpi_table_header)))); 5567f0c826aSLin Ming } 5577f0c826aSLin Ming } 55895b482a8SLen Brown break; 55995b482a8SLen Brown } 56095b482a8SLen Brown } 5617f0c826aSLin Ming 5627f0c826aSLin Ming /* Special processing for certain opcodes */ 56395b482a8SLen Brown 56495b482a8SLen Brown switch (op->common.aml_opcode) { 56595b482a8SLen Brown case AML_METHOD_OP: 56695b482a8SLen Brown /* 56795b482a8SLen Brown * Skip parsing of control method because we don't have enough 56895b482a8SLen Brown * info in the first pass to parse it correctly. 56995b482a8SLen Brown * 57095b482a8SLen Brown * Save the length and address of the body 57195b482a8SLen Brown */ 57295b482a8SLen Brown op->named.data = walk_state->parser_state.aml; 57395b482a8SLen Brown op->named.length = (u32) 57495b482a8SLen Brown (walk_state->parser_state.pkg_end - 57595b482a8SLen Brown walk_state->parser_state.aml); 57695b482a8SLen Brown 57795b482a8SLen Brown /* Skip body of method */ 57895b482a8SLen Brown 57995b482a8SLen Brown walk_state->parser_state.aml = 58095b482a8SLen Brown walk_state->parser_state.pkg_end; 58195b482a8SLen Brown walk_state->arg_count = 0; 58295b482a8SLen Brown break; 58395b482a8SLen Brown 58495b482a8SLen Brown case AML_BUFFER_OP: 58595b482a8SLen Brown case AML_PACKAGE_OP: 58695b482a8SLen Brown case AML_VAR_PACKAGE_OP: 58795b482a8SLen Brown 58895b482a8SLen Brown if ((op->common.parent) && 58995b482a8SLen Brown (op->common.parent->common.aml_opcode == 59095b482a8SLen Brown AML_NAME_OP) 59195b482a8SLen Brown && (walk_state->pass_number <= 59295b482a8SLen Brown ACPI_IMODE_LOAD_PASS2)) { 59395b482a8SLen Brown /* 59495b482a8SLen Brown * Skip parsing of Buffers and Packages because we don't have 59595b482a8SLen Brown * enough info in the first pass to parse them correctly. 59695b482a8SLen Brown */ 59795b482a8SLen Brown op->named.data = aml_op_start; 59895b482a8SLen Brown op->named.length = (u32) 59995b482a8SLen Brown (walk_state->parser_state.pkg_end - 60095b482a8SLen Brown aml_op_start); 60195b482a8SLen Brown 60295b482a8SLen Brown /* Skip body */ 60395b482a8SLen Brown 60495b482a8SLen Brown walk_state->parser_state.aml = 60595b482a8SLen Brown walk_state->parser_state.pkg_end; 60695b482a8SLen Brown walk_state->arg_count = 0; 60795b482a8SLen Brown } 60895b482a8SLen Brown break; 60995b482a8SLen Brown 61095b482a8SLen Brown case AML_WHILE_OP: 61195b482a8SLen Brown 61295b482a8SLen Brown if (walk_state->control_state) { 61395b482a8SLen Brown walk_state->control_state->control.package_end = 61495b482a8SLen Brown walk_state->parser_state.pkg_end; 61595b482a8SLen Brown } 61695b482a8SLen Brown break; 61795b482a8SLen Brown 61895b482a8SLen Brown default: 61995b482a8SLen Brown 62095b482a8SLen Brown /* No action for all other opcodes */ 62195b482a8SLen Brown break; 62295b482a8SLen Brown } 62395b482a8SLen Brown 62495b482a8SLen Brown break; 62595b482a8SLen Brown } 62695b482a8SLen Brown 62795b482a8SLen Brown return_ACPI_STATUS(AE_OK); 62895b482a8SLen Brown } 62995b482a8SLen Brown 63095b482a8SLen Brown /******************************************************************************* 63195b482a8SLen Brown * 6327f0c826aSLin Ming * FUNCTION: acpi_ps_link_module_code 6337f0c826aSLin Ming * 6349a884ab6SLin Ming * PARAMETERS: parent_op - Parent parser op 6359a884ab6SLin Ming * aml_start - Pointer to the AML 6367f0c826aSLin Ming * aml_length - Length of executable AML 6377f0c826aSLin Ming * owner_id - owner_id of module level code 6387f0c826aSLin Ming * 6397f0c826aSLin Ming * RETURN: None. 6407f0c826aSLin Ming * 6417f0c826aSLin Ming * DESCRIPTION: Wrap the module-level code with a method object and link the 6427f0c826aSLin Ming * object to the global list. Note, the mutex field of the method 6437f0c826aSLin Ming * object is used to link multiple module-level code objects. 6447f0c826aSLin Ming * 6457f0c826aSLin Ming ******************************************************************************/ 6467f0c826aSLin Ming 6477f0c826aSLin Ming static void 6489a884ab6SLin Ming acpi_ps_link_module_code(union acpi_parse_object *parent_op, 6499a884ab6SLin Ming u8 *aml_start, u32 aml_length, acpi_owner_id owner_id) 6507f0c826aSLin Ming { 6517f0c826aSLin Ming union acpi_operand_object *prev; 6527f0c826aSLin Ming union acpi_operand_object *next; 6537f0c826aSLin Ming union acpi_operand_object *method_obj; 6549a884ab6SLin Ming struct acpi_namespace_node *parent_node; 6557f0c826aSLin Ming 6567f0c826aSLin Ming /* Get the tail of the list */ 6577f0c826aSLin Ming 6587f0c826aSLin Ming prev = next = acpi_gbl_module_code_list; 6597f0c826aSLin Ming while (next) { 6607f0c826aSLin Ming prev = next; 6617f0c826aSLin Ming next = next->method.mutex; 6627f0c826aSLin Ming } 6637f0c826aSLin Ming 6647f0c826aSLin Ming /* 6657f0c826aSLin Ming * Insert the module level code into the list. Merge it if it is 6667f0c826aSLin Ming * adjacent to the previous element. 6677f0c826aSLin Ming */ 6687f0c826aSLin Ming if (!prev || 6697f0c826aSLin Ming ((prev->method.aml_start + prev->method.aml_length) != aml_start)) { 6707f0c826aSLin Ming 6717f0c826aSLin Ming /* Create, initialize, and link a new temporary method object */ 6727f0c826aSLin Ming 6737f0c826aSLin Ming method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); 6747f0c826aSLin Ming if (!method_obj) { 6757f0c826aSLin Ming return; 6767f0c826aSLin Ming } 6777f0c826aSLin Ming 6789a884ab6SLin Ming if (parent_op->common.node) { 6799a884ab6SLin Ming parent_node = parent_op->common.node; 6809a884ab6SLin Ming } else { 6819a884ab6SLin Ming parent_node = acpi_gbl_root_node; 6829a884ab6SLin Ming } 6839a884ab6SLin Ming 6847f0c826aSLin Ming method_obj->method.aml_start = aml_start; 6857f0c826aSLin Ming method_obj->method.aml_length = aml_length; 6867f0c826aSLin Ming method_obj->method.owner_id = owner_id; 68726294842SLin Ming method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL; 6887f0c826aSLin Ming 6899a884ab6SLin Ming /* 6909a884ab6SLin Ming * Save the parent node in next_object. This is cheating, but we 6919a884ab6SLin Ming * don't want to expand the method object. 6929a884ab6SLin Ming */ 6939a884ab6SLin Ming method_obj->method.next_object = 6949a884ab6SLin Ming ACPI_CAST_PTR(union acpi_operand_object, parent_node); 6959a884ab6SLin Ming 6967f0c826aSLin Ming if (!prev) { 6977f0c826aSLin Ming acpi_gbl_module_code_list = method_obj; 6987f0c826aSLin Ming } else { 6997f0c826aSLin Ming prev->method.mutex = method_obj; 7007f0c826aSLin Ming } 7017f0c826aSLin Ming } else { 7027f0c826aSLin Ming prev->method.aml_length += aml_length; 7037f0c826aSLin Ming } 7047f0c826aSLin Ming } 7057f0c826aSLin Ming 7067f0c826aSLin Ming /******************************************************************************* 7077f0c826aSLin Ming * 70895b482a8SLen Brown * FUNCTION: acpi_ps_complete_op 70995b482a8SLen Brown * 71095b482a8SLen Brown * PARAMETERS: walk_state - Current state 711ba494beeSBob Moore * op - Returned Op 712ba494beeSBob Moore * status - Parse status before complete Op 71395b482a8SLen Brown * 71495b482a8SLen Brown * RETURN: Status 71595b482a8SLen Brown * 71695b482a8SLen Brown * DESCRIPTION: Complete Op 71795b482a8SLen Brown * 71895b482a8SLen Brown ******************************************************************************/ 71995b482a8SLen Brown 72095b482a8SLen Brown static acpi_status 72195b482a8SLen Brown acpi_ps_complete_op(struct acpi_walk_state *walk_state, 72295b482a8SLen Brown union acpi_parse_object **op, acpi_status status) 72395b482a8SLen Brown { 72495b482a8SLen Brown acpi_status status2; 72595b482a8SLen Brown 72695b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state); 72795b482a8SLen Brown 72895b482a8SLen Brown /* 72995b482a8SLen Brown * Finished one argument of the containing scope 73095b482a8SLen Brown */ 73195b482a8SLen Brown walk_state->parser_state.scope->parse_scope.arg_count--; 73295b482a8SLen Brown 73395b482a8SLen Brown /* Close this Op (will result in parse subtree deletion) */ 73495b482a8SLen Brown 73595b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, *op); 73695b482a8SLen Brown if (ACPI_FAILURE(status2)) { 73795b482a8SLen Brown return_ACPI_STATUS(status2); 73895b482a8SLen Brown } 73995b482a8SLen Brown 74095b482a8SLen Brown *op = NULL; 74195b482a8SLen Brown 74295b482a8SLen Brown switch (status) { 74395b482a8SLen Brown case AE_OK: 74495b482a8SLen Brown break; 74595b482a8SLen Brown 74695b482a8SLen Brown case AE_CTRL_TRANSFER: 74795b482a8SLen Brown 74895b482a8SLen Brown /* We are about to transfer to a called method */ 74995b482a8SLen Brown 75095b482a8SLen Brown walk_state->prev_op = NULL; 75195b482a8SLen Brown walk_state->prev_arg_types = walk_state->arg_types; 75295b482a8SLen Brown return_ACPI_STATUS(status); 75395b482a8SLen Brown 75495b482a8SLen Brown case AE_CTRL_END: 75595b482a8SLen Brown 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 if (*op) { 76195b482a8SLen Brown walk_state->op = *op; 76295b482a8SLen Brown walk_state->op_info = 76395b482a8SLen Brown acpi_ps_get_opcode_info((*op)->common.aml_opcode); 76495b482a8SLen Brown walk_state->opcode = (*op)->common.aml_opcode; 76595b482a8SLen Brown 76695b482a8SLen Brown status = walk_state->ascending_callback(walk_state); 76795b482a8SLen Brown status = 76895b482a8SLen Brown acpi_ps_next_parse_state(walk_state, *op, status); 76995b482a8SLen Brown 77095b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, *op); 77195b482a8SLen Brown if (ACPI_FAILURE(status2)) { 77295b482a8SLen Brown return_ACPI_STATUS(status2); 77395b482a8SLen Brown } 77495b482a8SLen Brown } 77595b482a8SLen Brown 77695b482a8SLen Brown status = AE_OK; 77795b482a8SLen Brown break; 77895b482a8SLen Brown 77995b482a8SLen Brown case AE_CTRL_BREAK: 78095b482a8SLen Brown case AE_CTRL_CONTINUE: 78195b482a8SLen Brown 78295b482a8SLen Brown /* Pop off scopes until we find the While */ 78395b482a8SLen Brown 78495b482a8SLen Brown while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) { 78595b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 78695b482a8SLen Brown &walk_state->arg_types, 78795b482a8SLen Brown &walk_state->arg_count); 78895b482a8SLen Brown } 78995b482a8SLen Brown 79095b482a8SLen Brown /* Close this iteration of the While loop */ 79195b482a8SLen Brown 79295b482a8SLen Brown walk_state->op = *op; 79395b482a8SLen Brown walk_state->op_info = 79495b482a8SLen Brown acpi_ps_get_opcode_info((*op)->common.aml_opcode); 79595b482a8SLen Brown walk_state->opcode = (*op)->common.aml_opcode; 79695b482a8SLen Brown 79795b482a8SLen Brown status = walk_state->ascending_callback(walk_state); 79895b482a8SLen Brown status = acpi_ps_next_parse_state(walk_state, *op, status); 79995b482a8SLen Brown 80095b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, *op); 80195b482a8SLen Brown if (ACPI_FAILURE(status2)) { 80295b482a8SLen Brown return_ACPI_STATUS(status2); 80395b482a8SLen Brown } 80495b482a8SLen Brown 80595b482a8SLen Brown status = AE_OK; 80695b482a8SLen Brown break; 80795b482a8SLen Brown 80895b482a8SLen Brown case AE_CTRL_TERMINATE: 80995b482a8SLen Brown 81095b482a8SLen Brown /* Clean up */ 81195b482a8SLen Brown do { 81295b482a8SLen Brown if (*op) { 81395b482a8SLen Brown status2 = 81495b482a8SLen Brown acpi_ps_complete_this_op(walk_state, *op); 81595b482a8SLen Brown if (ACPI_FAILURE(status2)) { 81695b482a8SLen Brown return_ACPI_STATUS(status2); 81795b482a8SLen Brown } 81895b482a8SLen Brown 81995b482a8SLen Brown acpi_ut_delete_generic_state 82095b482a8SLen Brown (acpi_ut_pop_generic_state 82195b482a8SLen Brown (&walk_state->control_state)); 82295b482a8SLen Brown } 82395b482a8SLen Brown 82495b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 82595b482a8SLen Brown &walk_state->arg_types, 82695b482a8SLen Brown &walk_state->arg_count); 82795b482a8SLen Brown 82895b482a8SLen Brown } while (*op); 82995b482a8SLen Brown 83095b482a8SLen Brown return_ACPI_STATUS(AE_OK); 83195b482a8SLen Brown 83295b482a8SLen Brown default: /* All other non-AE_OK status */ 83395b482a8SLen Brown 83495b482a8SLen Brown do { 83595b482a8SLen Brown if (*op) { 83695b482a8SLen Brown status2 = 83795b482a8SLen Brown acpi_ps_complete_this_op(walk_state, *op); 83895b482a8SLen Brown if (ACPI_FAILURE(status2)) { 83995b482a8SLen Brown return_ACPI_STATUS(status2); 84095b482a8SLen Brown } 84195b482a8SLen Brown } 84295b482a8SLen Brown 84395b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 84495b482a8SLen Brown &walk_state->arg_types, 84595b482a8SLen Brown &walk_state->arg_count); 84695b482a8SLen Brown 84795b482a8SLen Brown } while (*op); 84895b482a8SLen Brown 84995b482a8SLen Brown #if 0 85095b482a8SLen Brown /* 85195b482a8SLen Brown * TBD: Cleanup parse ops on error 85295b482a8SLen Brown */ 85395b482a8SLen Brown if (*op == NULL) { 85495b482a8SLen Brown acpi_ps_pop_scope(parser_state, op, 85595b482a8SLen Brown &walk_state->arg_types, 85695b482a8SLen Brown &walk_state->arg_count); 85795b482a8SLen Brown } 85895b482a8SLen Brown #endif 85995b482a8SLen Brown walk_state->prev_op = NULL; 86095b482a8SLen Brown walk_state->prev_arg_types = walk_state->arg_types; 86195b482a8SLen Brown return_ACPI_STATUS(status); 86295b482a8SLen Brown } 86395b482a8SLen Brown 86495b482a8SLen Brown /* This scope complete? */ 86595b482a8SLen Brown 86695b482a8SLen Brown if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) { 86795b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), op, 86895b482a8SLen Brown &walk_state->arg_types, 86995b482a8SLen Brown &walk_state->arg_count); 87095b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op)); 87195b482a8SLen Brown } else { 87295b482a8SLen Brown *op = NULL; 87395b482a8SLen Brown } 87495b482a8SLen Brown 87595b482a8SLen Brown return_ACPI_STATUS(AE_OK); 87695b482a8SLen Brown } 87795b482a8SLen Brown 87895b482a8SLen Brown /******************************************************************************* 87995b482a8SLen Brown * 88095b482a8SLen Brown * FUNCTION: acpi_ps_complete_final_op 88195b482a8SLen Brown * 88295b482a8SLen Brown * PARAMETERS: walk_state - Current state 883ba494beeSBob Moore * op - Current Op 884ba494beeSBob Moore * status - Current parse status before complete last 88595b482a8SLen Brown * Op 88695b482a8SLen Brown * 88795b482a8SLen Brown * RETURN: Status 88895b482a8SLen Brown * 88995b482a8SLen Brown * DESCRIPTION: Complete last Op. 89095b482a8SLen Brown * 89195b482a8SLen Brown ******************************************************************************/ 89295b482a8SLen Brown 89395b482a8SLen Brown static acpi_status 89495b482a8SLen Brown acpi_ps_complete_final_op(struct acpi_walk_state *walk_state, 89595b482a8SLen Brown union acpi_parse_object *op, acpi_status status) 89695b482a8SLen Brown { 89795b482a8SLen Brown acpi_status status2; 89895b482a8SLen Brown 89995b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state); 90095b482a8SLen Brown 90195b482a8SLen Brown /* 90295b482a8SLen Brown * Complete the last Op (if not completed), and clear the scope stack. 90395b482a8SLen Brown * It is easily possible to end an AML "package" with an unbounded number 90495b482a8SLen Brown * of open scopes (such as when several ASL blocks are closed with 90595b482a8SLen Brown * sequential closing braces). We want to terminate each one cleanly. 90695b482a8SLen Brown */ 90795b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n", 90895b482a8SLen Brown op)); 90995b482a8SLen Brown do { 91095b482a8SLen Brown if (op) { 91195b482a8SLen Brown if (walk_state->ascending_callback != NULL) { 91295b482a8SLen Brown walk_state->op = op; 91395b482a8SLen Brown walk_state->op_info = 91495b482a8SLen Brown acpi_ps_get_opcode_info(op->common. 91595b482a8SLen Brown aml_opcode); 91695b482a8SLen Brown walk_state->opcode = op->common.aml_opcode; 91795b482a8SLen Brown 91895b482a8SLen Brown status = 91995b482a8SLen Brown walk_state->ascending_callback(walk_state); 92095b482a8SLen Brown status = 92195b482a8SLen Brown acpi_ps_next_parse_state(walk_state, op, 92295b482a8SLen Brown status); 92395b482a8SLen Brown if (status == AE_CTRL_PENDING) { 92495b482a8SLen Brown status = 92595b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 92695b482a8SLen Brown AE_OK); 92795b482a8SLen Brown if (ACPI_FAILURE(status)) { 92895b482a8SLen Brown return_ACPI_STATUS(status); 92995b482a8SLen Brown } 93095b482a8SLen Brown } 93195b482a8SLen Brown 93295b482a8SLen Brown if (status == AE_CTRL_TERMINATE) { 93395b482a8SLen Brown status = AE_OK; 93495b482a8SLen Brown 93595b482a8SLen Brown /* Clean up */ 93695b482a8SLen Brown do { 93795b482a8SLen Brown if (op) { 93895b482a8SLen Brown status2 = 93995b482a8SLen Brown acpi_ps_complete_this_op 94095b482a8SLen Brown (walk_state, op); 94195b482a8SLen Brown if (ACPI_FAILURE 94295b482a8SLen Brown (status2)) { 94395b482a8SLen Brown return_ACPI_STATUS 94495b482a8SLen Brown (status2); 94595b482a8SLen Brown } 94695b482a8SLen Brown } 94795b482a8SLen Brown 94895b482a8SLen Brown acpi_ps_pop_scope(& 94995b482a8SLen Brown (walk_state-> 95095b482a8SLen Brown parser_state), 95195b482a8SLen Brown &op, 95295b482a8SLen Brown &walk_state-> 95395b482a8SLen Brown arg_types, 95495b482a8SLen Brown &walk_state-> 95595b482a8SLen Brown arg_count); 95695b482a8SLen Brown 95795b482a8SLen Brown } while (op); 95895b482a8SLen Brown 95995b482a8SLen Brown return_ACPI_STATUS(status); 96095b482a8SLen Brown } 96195b482a8SLen Brown 96295b482a8SLen Brown else if (ACPI_FAILURE(status)) { 96395b482a8SLen Brown 96495b482a8SLen Brown /* First error is most important */ 96595b482a8SLen Brown 96695b482a8SLen Brown (void) 96795b482a8SLen Brown acpi_ps_complete_this_op(walk_state, 96895b482a8SLen Brown op); 96995b482a8SLen Brown return_ACPI_STATUS(status); 97095b482a8SLen Brown } 97195b482a8SLen Brown } 97295b482a8SLen Brown 97395b482a8SLen Brown status2 = acpi_ps_complete_this_op(walk_state, op); 97495b482a8SLen Brown if (ACPI_FAILURE(status2)) { 97595b482a8SLen Brown return_ACPI_STATUS(status2); 97695b482a8SLen Brown } 97795b482a8SLen Brown } 97895b482a8SLen Brown 97995b482a8SLen Brown acpi_ps_pop_scope(&(walk_state->parser_state), &op, 98095b482a8SLen Brown &walk_state->arg_types, 98195b482a8SLen Brown &walk_state->arg_count); 98295b482a8SLen Brown 98395b482a8SLen Brown } while (op); 98495b482a8SLen Brown 98595b482a8SLen Brown return_ACPI_STATUS(status); 98695b482a8SLen Brown } 98795b482a8SLen Brown 98895b482a8SLen Brown /******************************************************************************* 98995b482a8SLen Brown * 99095b482a8SLen Brown * FUNCTION: acpi_ps_parse_loop 99195b482a8SLen Brown * 99295b482a8SLen Brown * PARAMETERS: walk_state - Current state 99395b482a8SLen Brown * 99495b482a8SLen Brown * RETURN: Status 99595b482a8SLen Brown * 99695b482a8SLen Brown * DESCRIPTION: Parse AML (pointed to by the current parser state) and return 99795b482a8SLen Brown * a tree of ops. 99895b482a8SLen Brown * 99995b482a8SLen Brown ******************************************************************************/ 100095b482a8SLen Brown 100195b482a8SLen Brown acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) 100295b482a8SLen Brown { 100395b482a8SLen Brown acpi_status status = AE_OK; 100495b482a8SLen Brown union acpi_parse_object *op = NULL; /* current op */ 100595b482a8SLen Brown struct acpi_parse_state *parser_state; 100695b482a8SLen Brown u8 *aml_op_start = NULL; 100795b482a8SLen Brown 100895b482a8SLen Brown ACPI_FUNCTION_TRACE_PTR(ps_parse_loop, walk_state); 100995b482a8SLen Brown 101095b482a8SLen Brown if (walk_state->descending_callback == NULL) { 101195b482a8SLen Brown return_ACPI_STATUS(AE_BAD_PARAMETER); 101295b482a8SLen Brown } 101395b482a8SLen Brown 101495b482a8SLen Brown parser_state = &walk_state->parser_state; 101595b482a8SLen Brown walk_state->arg_types = 0; 101695b482a8SLen Brown 101795b482a8SLen Brown #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) 101895b482a8SLen Brown 101995b482a8SLen Brown if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) { 102095b482a8SLen Brown 102195b482a8SLen Brown /* We are restarting a preempted control method */ 102295b482a8SLen Brown 102395b482a8SLen Brown if (acpi_ps_has_completed_scope(parser_state)) { 102495b482a8SLen Brown /* 102595b482a8SLen Brown * We must check if a predicate to an IF or WHILE statement 102695b482a8SLen Brown * was just completed 102795b482a8SLen Brown */ 102895b482a8SLen Brown if ((parser_state->scope->parse_scope.op) && 102995b482a8SLen Brown ((parser_state->scope->parse_scope.op->common. 103095b482a8SLen Brown aml_opcode == AML_IF_OP) 103195b482a8SLen Brown || (parser_state->scope->parse_scope.op->common. 103295b482a8SLen Brown aml_opcode == AML_WHILE_OP)) 103395b482a8SLen Brown && (walk_state->control_state) 103495b482a8SLen Brown && (walk_state->control_state->common.state == 103595b482a8SLen Brown ACPI_CONTROL_PREDICATE_EXECUTING)) { 103695b482a8SLen Brown /* 103795b482a8SLen Brown * A predicate was just completed, get the value of the 103895b482a8SLen Brown * predicate and branch based on that value 103995b482a8SLen Brown */ 104095b482a8SLen Brown walk_state->op = NULL; 104195b482a8SLen Brown status = 104295b482a8SLen Brown acpi_ds_get_predicate_value(walk_state, 104395b482a8SLen Brown ACPI_TO_POINTER 104495b482a8SLen Brown (TRUE)); 104595b482a8SLen Brown if (ACPI_FAILURE(status) 104695b482a8SLen Brown && ((status & AE_CODE_MASK) != 104795b482a8SLen Brown AE_CODE_CONTROL)) { 104895b482a8SLen Brown if (status == AE_AML_NO_RETURN_VALUE) { 104995b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, 105095b482a8SLen Brown "Invoked method did not return a value")); 105195b482a8SLen Brown } 105295b482a8SLen Brown 105395b482a8SLen Brown ACPI_EXCEPTION((AE_INFO, status, 105495b482a8SLen Brown "GetPredicate Failed")); 105595b482a8SLen Brown return_ACPI_STATUS(status); 105695b482a8SLen Brown } 105795b482a8SLen Brown 105895b482a8SLen Brown status = 105995b482a8SLen Brown acpi_ps_next_parse_state(walk_state, op, 106095b482a8SLen Brown status); 106195b482a8SLen Brown } 106295b482a8SLen Brown 106395b482a8SLen Brown acpi_ps_pop_scope(parser_state, &op, 106495b482a8SLen Brown &walk_state->arg_types, 106595b482a8SLen Brown &walk_state->arg_count); 106695b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 106795b482a8SLen Brown "Popped scope, Op=%p\n", op)); 106895b482a8SLen Brown } else if (walk_state->prev_op) { 106995b482a8SLen Brown 107095b482a8SLen Brown /* We were in the middle of an op */ 107195b482a8SLen Brown 107295b482a8SLen Brown op = walk_state->prev_op; 107395b482a8SLen Brown walk_state->arg_types = walk_state->prev_arg_types; 107495b482a8SLen Brown } 107595b482a8SLen Brown } 107695b482a8SLen Brown #endif 107795b482a8SLen Brown 107895b482a8SLen Brown /* Iterative parsing loop, while there is more AML to process: */ 107995b482a8SLen Brown 108095b482a8SLen Brown while ((parser_state->aml < parser_state->aml_end) || (op)) { 108195b482a8SLen Brown aml_op_start = parser_state->aml; 108295b482a8SLen Brown if (!op) { 108395b482a8SLen Brown status = 108495b482a8SLen Brown acpi_ps_create_op(walk_state, aml_op_start, &op); 108595b482a8SLen Brown if (ACPI_FAILURE(status)) { 108695b482a8SLen Brown if (status == AE_CTRL_PARSE_CONTINUE) { 108795b482a8SLen Brown continue; 108895b482a8SLen Brown } 108995b482a8SLen Brown 109095b482a8SLen Brown if (status == AE_CTRL_PARSE_PENDING) { 109195b482a8SLen Brown status = AE_OK; 109295b482a8SLen Brown } 109395b482a8SLen Brown 109495b482a8SLen Brown status = 109595b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 109695b482a8SLen Brown status); 109795b482a8SLen Brown if (ACPI_FAILURE(status)) { 109895b482a8SLen Brown return_ACPI_STATUS(status); 109995b482a8SLen Brown } 110095b482a8SLen Brown 110195b482a8SLen Brown continue; 110295b482a8SLen Brown } 110395b482a8SLen Brown 110495b482a8SLen Brown op->common.aml_offset = walk_state->aml_offset; 110595b482a8SLen Brown 110695b482a8SLen Brown if (walk_state->op_info) { 110795b482a8SLen Brown ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 110895b482a8SLen Brown "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", 110995b482a8SLen Brown (u32) op->common.aml_opcode, 111095b482a8SLen Brown walk_state->op_info->name, op, 111195b482a8SLen Brown parser_state->aml, 111295b482a8SLen Brown op->common.aml_offset)); 111395b482a8SLen Brown } 111495b482a8SLen Brown } 111595b482a8SLen Brown 111695b482a8SLen Brown /* 111795b482a8SLen Brown * Start arg_count at zero because we don't know if there are 111895b482a8SLen Brown * any args yet 111995b482a8SLen Brown */ 112095b482a8SLen Brown walk_state->arg_count = 0; 112195b482a8SLen Brown 112295b482a8SLen Brown /* Are there any arguments that must be processed? */ 112395b482a8SLen Brown 112495b482a8SLen Brown if (walk_state->arg_types) { 112595b482a8SLen Brown 112695b482a8SLen Brown /* Get arguments */ 112795b482a8SLen Brown 112895b482a8SLen Brown status = 112995b482a8SLen Brown acpi_ps_get_arguments(walk_state, aml_op_start, op); 113095b482a8SLen Brown if (ACPI_FAILURE(status)) { 113195b482a8SLen Brown status = 113295b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 113395b482a8SLen Brown status); 113495b482a8SLen Brown if (ACPI_FAILURE(status)) { 113595b482a8SLen Brown return_ACPI_STATUS(status); 113695b482a8SLen Brown } 113795b482a8SLen Brown 113895b482a8SLen Brown continue; 113995b482a8SLen Brown } 114095b482a8SLen Brown } 114195b482a8SLen Brown 114295b482a8SLen Brown /* Check for arguments that need to be processed */ 114395b482a8SLen Brown 114495b482a8SLen Brown if (walk_state->arg_count) { 114595b482a8SLen Brown /* 114695b482a8SLen Brown * There are arguments (complex ones), push Op and 114795b482a8SLen Brown * prepare for argument 114895b482a8SLen Brown */ 114995b482a8SLen Brown status = acpi_ps_push_scope(parser_state, op, 115095b482a8SLen Brown walk_state->arg_types, 115195b482a8SLen Brown walk_state->arg_count); 115295b482a8SLen Brown if (ACPI_FAILURE(status)) { 115395b482a8SLen Brown status = 115495b482a8SLen Brown acpi_ps_complete_op(walk_state, &op, 115595b482a8SLen Brown status); 115695b482a8SLen Brown if (ACPI_FAILURE(status)) { 115795b482a8SLen Brown return_ACPI_STATUS(status); 115895b482a8SLen Brown } 115995b482a8SLen Brown 116095b482a8SLen Brown continue; 116195b482a8SLen Brown } 116295b482a8SLen Brown 116395b482a8SLen Brown op = NULL; 116495b482a8SLen Brown continue; 116595b482a8SLen Brown } 116695b482a8SLen Brown 116795b482a8SLen Brown /* 116895b482a8SLen Brown * All arguments have been processed -- Op is complete, 116995b482a8SLen Brown * prepare for next 117095b482a8SLen Brown */ 117195b482a8SLen Brown walk_state->op_info = 117295b482a8SLen Brown acpi_ps_get_opcode_info(op->common.aml_opcode); 117395b482a8SLen Brown if (walk_state->op_info->flags & AML_NAMED) { 117495b482a8SLen Brown if (acpi_gbl_depth) { 117595b482a8SLen Brown acpi_gbl_depth--; 117695b482a8SLen Brown } 117795b482a8SLen Brown 117895b482a8SLen Brown if (op->common.aml_opcode == AML_REGION_OP || 117995b482a8SLen Brown op->common.aml_opcode == AML_DATA_REGION_OP) { 118095b482a8SLen Brown /* 118195b482a8SLen Brown * Skip parsing of control method or opregion body, 118295b482a8SLen Brown * because we don't have enough info in the first pass 118395b482a8SLen Brown * to parse them correctly. 118495b482a8SLen Brown * 118595b482a8SLen Brown * Completed parsing an op_region declaration, we now 118695b482a8SLen Brown * know the length. 118795b482a8SLen Brown */ 118895b482a8SLen Brown op->named.length = 118995b482a8SLen Brown (u32) (parser_state->aml - op->named.data); 119095b482a8SLen Brown } 119195b482a8SLen Brown } 119295b482a8SLen Brown 119395b482a8SLen Brown if (walk_state->op_info->flags & AML_CREATE) { 119495b482a8SLen Brown /* 1195ba494beeSBob Moore * Backup to beginning of create_XXXfield declaration (1 for 119695b482a8SLen Brown * Opcode) 119795b482a8SLen Brown * 119895b482a8SLen Brown * body_length is unknown until we parse the body 119995b482a8SLen Brown */ 120095b482a8SLen Brown op->named.length = 120195b482a8SLen Brown (u32) (parser_state->aml - op->named.data); 120295b482a8SLen Brown } 120395b482a8SLen Brown 120495b482a8SLen Brown if (op->common.aml_opcode == AML_BANK_FIELD_OP) { 120595b482a8SLen Brown /* 120695b482a8SLen Brown * Backup to beginning of bank_field declaration 120795b482a8SLen Brown * 120895b482a8SLen Brown * body_length is unknown until we parse the body 120995b482a8SLen Brown */ 121095b482a8SLen Brown op->named.length = 121195b482a8SLen Brown (u32) (parser_state->aml - op->named.data); 121295b482a8SLen Brown } 121395b482a8SLen Brown 121495b482a8SLen Brown /* This op complete, notify the dispatcher */ 121595b482a8SLen Brown 121695b482a8SLen Brown if (walk_state->ascending_callback != NULL) { 121795b482a8SLen Brown walk_state->op = op; 121895b482a8SLen Brown walk_state->opcode = op->common.aml_opcode; 121995b482a8SLen Brown 122095b482a8SLen Brown status = walk_state->ascending_callback(walk_state); 122195b482a8SLen Brown status = 122295b482a8SLen Brown acpi_ps_next_parse_state(walk_state, op, status); 122395b482a8SLen Brown if (status == AE_CTRL_PENDING) { 122495b482a8SLen Brown status = AE_OK; 122595b482a8SLen Brown } 122695b482a8SLen Brown } 122795b482a8SLen Brown 122895b482a8SLen Brown status = acpi_ps_complete_op(walk_state, &op, status); 122995b482a8SLen Brown if (ACPI_FAILURE(status)) { 123095b482a8SLen Brown return_ACPI_STATUS(status); 123195b482a8SLen Brown } 123295b482a8SLen Brown 123395b482a8SLen Brown } /* while parser_state->Aml */ 123495b482a8SLen Brown 123595b482a8SLen Brown status = acpi_ps_complete_final_op(walk_state, op, status); 123695b482a8SLen Brown return_ACPI_STATUS(status); 123795b482a8SLen Brown } 1238