psloop.c
来自「linux 内核源代码」· C语言 代码 · 共 1,057 行 · 第 1/2 页
C
1,057 行
/****************************************************************************** * * Module Name: psloop - Main AML parse loop * *****************************************************************************//* * Copyright (C) 2000 - 2007, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * substantially similar to the "NO WARRANTY" disclaimer below * ("Disclaimer") and any redistribution must be conditioned upon * including a substantially similar Disclaimer requirement for further * binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. *//* * Parse the AML and build an operation tree as most interpreters, (such as * Perl) do. Parsing is done by hand rather than with a YACC generated parser * to tightly constrain stack and dynamic memory usage. Parsing is kept * flexible and the code fairly compact by parsing based on a list of AML * opcode templates in aml_op_info[]. */#include <acpi/acpi.h>#include <acpi/acparser.h>#include <acpi/acdispat.h>#include <acpi/amlcode.h>#define _COMPONENT ACPI_PARSERACPI_MODULE_NAME("psloop")static u32 acpi_gbl_depth = 0;/* Local prototypes */static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);static acpi_statusacpi_ps_build_named_op(struct acpi_walk_state *walk_state, u8 * aml_op_start, union acpi_parse_object *unnamed_op, union acpi_parse_object **op);static acpi_statusacpi_ps_create_op(struct acpi_walk_state *walk_state, u8 * aml_op_start, union acpi_parse_object **new_op);static acpi_statusacpi_ps_get_arguments(struct acpi_walk_state *walk_state, u8 * aml_op_start, union acpi_parse_object *op);static acpi_statusacpi_ps_complete_op(struct acpi_walk_state *walk_state, union acpi_parse_object **op, acpi_status status);static acpi_statusacpi_ps_complete_final_op(struct acpi_walk_state *walk_state, union acpi_parse_object *op, acpi_status status);/******************************************************************************* * * FUNCTION: acpi_ps_get_aml_opcode * * PARAMETERS: walk_state - Current state * * RETURN: Status * * DESCRIPTION: Extract the next AML opcode from the input stream. * ******************************************************************************/static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state){ ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state); walk_state->aml_offset = (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, walk_state->parser_state.aml_start); walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state)); /* * First cut to determine what we have found: * 1) A valid AML opcode * 2) A name string * 3) An unknown/invalid opcode */ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); switch (walk_state->op_info->class) { case AML_CLASS_ASCII: case AML_CLASS_PREFIX: /* * Starts with a valid prefix or ASCII char, this is a name * string. Convert the bare name string to a namepath. */ walk_state->opcode = AML_INT_NAMEPATH_OP; walk_state->arg_types = ARGP_NAMESTRING; break; case AML_CLASS_UNKNOWN: /* The opcode is unrecognized. Just skip unknown opcodes */ ACPI_ERROR((AE_INFO, "Found unknown opcode %X at AML address %p offset %X, ignoring", walk_state->opcode, walk_state->parser_state.aml, walk_state->aml_offset)); ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); /* Assume one-byte bad opcode */ walk_state->parser_state.aml++; return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); default: /* Found opcode info, this is a normal opcode */ walk_state->parser_state.aml += acpi_ps_get_opcode_size(walk_state->opcode); walk_state->arg_types = walk_state->op_info->parse_args; break; } return_ACPI_STATUS(AE_OK);}/******************************************************************************* * * FUNCTION: acpi_ps_build_named_op * * PARAMETERS: walk_state - Current state * aml_op_start - Begin of named Op in AML * unnamed_op - Early Op (not a named Op) * Op - Returned Op * * RETURN: Status * * DESCRIPTION: Parse a named Op * ******************************************************************************/static acpi_statusacpi_ps_build_named_op(struct acpi_walk_state *walk_state, u8 * aml_op_start, union acpi_parse_object *unnamed_op, union acpi_parse_object **op){ acpi_status status = AE_OK; union acpi_parse_object *arg = NULL; ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); unnamed_op->common.value.arg = NULL; unnamed_op->common.aml_opcode = walk_state->opcode; /* * Get and append arguments until we find the node that contains * the name (the type ARGP_NAME). */ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) { status = acpi_ps_get_next_arg(walk_state, &(walk_state->parser_state), GET_CURRENT_ARG_TYPE(walk_state-> arg_types), &arg); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } acpi_ps_append_arg(unnamed_op, arg); INCREMENT_ARG_LIST(walk_state->arg_types); } /* * Make sure that we found a NAME and didn't run out of arguments */ if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) { return_ACPI_STATUS(AE_AML_NO_OPERAND); } /* We know that this arg is a name, move to next arg */ INCREMENT_ARG_LIST(walk_state->arg_types); /* * Find the object. This will either insert the object into * the namespace or simply look it up */ walk_state->op = NULL; status = walk_state->descending_callback(walk_state, op); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog")); return_ACPI_STATUS(status); } if (!*op) { return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); } status = acpi_ps_next_parse_state(walk_state, *op, status); if (ACPI_FAILURE(status)) { if (status == AE_CTRL_PENDING) { return_ACPI_STATUS(AE_CTRL_PARSE_PENDING); } return_ACPI_STATUS(status); } acpi_ps_append_arg(*op, unnamed_op->common.value.arg); acpi_gbl_depth++; if ((*op)->common.aml_opcode == AML_REGION_OP) { /* * Defer final parsing of an operation_region body, because we don't * have enough info in the first pass to parse it correctly (i.e., * there may be method calls within the term_arg elements of the body.) * * However, we must continue parsing because the opregion is not a * standalone package -- we don't know where the end is at this point. * * (Length is unknown until parse of the body complete) */ (*op)->named.data = aml_op_start; (*op)->named.length = 0; } return_ACPI_STATUS(AE_OK);}/******************************************************************************* * * FUNCTION: acpi_ps_create_op * * PARAMETERS: walk_state - Current state * aml_op_start - Op start in AML * new_op - Returned Op * * RETURN: Status * * DESCRIPTION: Get Op from AML * ******************************************************************************/static acpi_statusacpi_ps_create_op(struct acpi_walk_state *walk_state, u8 * aml_op_start, union acpi_parse_object **new_op){ acpi_status status = AE_OK; union acpi_parse_object *op; union acpi_parse_object *named_op = NULL; ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); status = acpi_ps_get_aml_opcode(walk_state); if (status == AE_CTRL_PARSE_CONTINUE) { return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); } /* Create Op structure and append to parent's argument list */ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); op = acpi_ps_alloc_op(walk_state->opcode); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } if (walk_state->op_info->flags & AML_NAMED) { status = acpi_ps_build_named_op(walk_state, aml_op_start, op, &named_op); acpi_ps_free_op(op); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } *new_op = named_op; return_ACPI_STATUS(AE_OK); } /* Not a named opcode, just allocate Op and append to parent */ if (walk_state->op_info->flags & AML_CREATE) { /* * Backup to beginning of create_xXXfield declaration * body_length is unknown until we parse the body */ op->named.data = aml_op_start; op->named.length = 0; } acpi_ps_append_arg(acpi_ps_get_parent_scope (&(walk_state->parser_state)), op); if (walk_state->descending_callback != NULL) { /* * Find the object. This will either insert the object into * the namespace or simply look it up */ walk_state->op = *new_op = op; status = walk_state->descending_callback(walk_state, &op); status = acpi_ps_next_parse_state(walk_state, op, status); if (status == AE_CTRL_PENDING) { status = AE_CTRL_PARSE_PENDING; } } return_ACPI_STATUS(status);}/******************************************************************************* * * FUNCTION: acpi_ps_get_arguments * * PARAMETERS: walk_state - Current state * aml_op_start - Op start in AML * Op - Current Op * * RETURN: Status * * DESCRIPTION: Get arguments for passed Op. * ******************************************************************************/static acpi_statusacpi_ps_get_arguments(struct acpi_walk_state *walk_state, u8 * aml_op_start, union acpi_parse_object *op){ acpi_status status = AE_OK; union acpi_parse_object *arg = NULL; ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); switch (op->common.aml_opcode) { case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ case AML_WORD_OP: /* AML_WORDDATA_ARG */ case AML_DWORD_OP: /* AML_DWORDATA_ARG */ case AML_QWORD_OP: /* AML_QWORDATA_ARG */ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ /* Fill in constant or string argument directly */ acpi_ps_get_next_simple_arg(&(walk_state->parser_state), GET_CURRENT_ARG_TYPE(walk_state-> arg_types), op); break; case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ status = acpi_ps_get_next_namepath(walk_state, &(walk_state->parser_state), op, 1); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } walk_state->arg_types = 0; break; default: /* * Op is not a constant or string, append each argument to the Op */ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && !walk_state->arg_count) { walk_state->aml_offset = (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, walk_state->parser_state. aml_start); status = acpi_ps_get_next_arg(walk_state, &(walk_state->parser_state), GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } if (arg) { arg->common.aml_offset = walk_state->aml_offset; acpi_ps_append_arg(op, arg); } INCREMENT_ARG_LIST(walk_state->arg_types); } /* Special processing for certain opcodes */ /* TBD (remove): Temporary mechanism to disable this code if needed */#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) && ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) { /* * We want to skip If/Else/While constructs during Pass1 because we * want to actually conditionally execute the code during Pass2. * * Except for disassembly, where we always want to walk the * If/Else/While packages */ switch (op->common.aml_opcode) { case AML_IF_OP: case AML_ELSE_OP: case AML_WHILE_OP: ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Pass1: Skipping an If/Else/While body\n")); /* Skip body of if/else/while in pass 1 */ walk_state->parser_state.aml = walk_state->parser_state.pkg_end; walk_state->arg_count = 0; break; default: break; } }#endif switch (op->common.aml_opcode) { case AML_METHOD_OP: /* * Skip parsing of control method because we don't have enough * info in the first pass to parse it correctly. * * Save the length and address of the body */ op->named.data = walk_state->parser_state.aml; op->named.length = (u32) (walk_state->parser_state.pkg_end - walk_state->parser_state.aml); /* Skip body of method */ walk_state->parser_state.aml = walk_state->parser_state.pkg_end; walk_state->arg_count = 0; break; case AML_BUFFER_OP: case AML_PACKAGE_OP: case AML_VAR_PACKAGE_OP: if ((op->common.parent) && (op->common.parent->common.aml_opcode == AML_NAME_OP) && (walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2)) { /* * Skip parsing of Buffers and Packages because we don't have * enough info in the first pass to parse them correctly. */ op->named.data = aml_op_start; op->named.length = (u32) (walk_state->parser_state.pkg_end - aml_op_start); /* Skip body */ walk_state->parser_state.aml = walk_state->parser_state.pkg_end; walk_state->arg_count = 0; } break; case AML_WHILE_OP: if (walk_state->control_state) { walk_state->control_state->control.package_end = walk_state->parser_state.pkg_end; } break; default: /* No action for all other opcodes */ break; } break; } return_ACPI_STATUS(AE_OK);}/******************************************************************************* * * FUNCTION: acpi_ps_complete_op * * PARAMETERS: walk_state - Current state * Op - Returned Op
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?