📄 psparse.c
字号:
/****************************************************************************** * * Module Name: psparse - Parser top level AML parse routines * *****************************************************************************//* * Copyright (C) 2000 - 2005, 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, * like Perl, do. Parsing is done by hand rather than with a YACC * generated parser to tightly constrain stack and dynamic memory * usage. At the same time, 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>#include <acpi/acnamesp.h>#include <acpi/acinterp.h>#define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME ("psparse")static u32 acpi_gbl_depth = 0;/******************************************************************************* * * FUNCTION: acpi_ps_get_opcode_size * * PARAMETERS: Opcode - An AML opcode * * RETURN: Size of the opcode, in bytes (1 or 2) * * DESCRIPTION: Get the size of the current opcode. * ******************************************************************************/u32acpi_ps_get_opcode_size ( u32 opcode){ /* Extended (2-byte) opcode if > 255 */ if (opcode > 0x00FF) { return (2); } /* Otherwise, just a single byte opcode */ return (1);}/******************************************************************************* * * FUNCTION: acpi_ps_peek_opcode * * PARAMETERS: parser_state - A parser state object * * RETURN: Status * * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) * ******************************************************************************/u16acpi_ps_peek_opcode ( struct acpi_parse_state *parser_state){ u8 *aml; u16 opcode; aml = parser_state->aml; opcode = (u16) ACPI_GET8 (aml); if (opcode == AML_EXTOP) { /* Extended opcode */ aml++; opcode = (u16) ((opcode << 8) | ACPI_GET8 (aml)); } return (opcode);}/******************************************************************************* * * FUNCTION: acpi_ps_complete_this_op * * PARAMETERS: walk_state - Current State * Op - Op to complete * * RETURN: None. * * DESCRIPTION: Perform any cleanup at the completion of an Op. * ******************************************************************************/voidacpi_ps_complete_this_op ( struct acpi_walk_state *walk_state, union acpi_parse_object *op){ union acpi_parse_object *prev; union acpi_parse_object *next; const struct acpi_opcode_info *parent_info; union acpi_parse_object *replacement_op = NULL; ACPI_FUNCTION_TRACE_PTR ("ps_complete_this_op", op); /* Check for null Op, can happen if AML code is corrupt */ if (!op) { return_VOID; } /* Delete this op and the subtree below it if asked to */ if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) || (walk_state->op_info->class == AML_CLASS_ARGUMENT)) { return_VOID; } /* Make sure that we only delete this subtree */ if (op->common.parent) { /* * Check if we need to replace the operator and its subtree * with a return value op (placeholder op) */ parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); switch (parent_info->class) { case AML_CLASS_CONTROL: break; case AML_CLASS_CREATE: /* * These opcodes contain term_arg operands. The current * op must be replaced by a placeholder return op */ replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); if (!replacement_op) { goto cleanup; } break; case AML_CLASS_NAMED_OBJECT: /* * These opcodes contain term_arg operands. The current * op must be replaced by a placeholder return op */ if ((op->common.parent->common.aml_opcode == AML_REGION_OP) || (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) || (op->common.parent->common.aml_opcode == AML_BUFFER_OP) || (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); if (!replacement_op) { goto cleanup; } } if ((op->common.parent->common.aml_opcode == AML_NAME_OP) && (walk_state->descending_callback != acpi_ds_exec_begin_op)) { if ((op->common.aml_opcode == AML_BUFFER_OP) || (op->common.aml_opcode == AML_PACKAGE_OP) || (op->common.aml_opcode == AML_VAR_PACKAGE_OP)) { replacement_op = acpi_ps_alloc_op (op->common.aml_opcode); if (!replacement_op) { goto cleanup; } replacement_op->named.data = op->named.data; replacement_op->named.length = op->named.length; } } break; default: replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); if (!replacement_op) { goto cleanup; } } /* We must unlink this op from the parent tree */ prev = op->common.parent->common.value.arg; if (prev == op) { /* This op is the first in the list */ if (replacement_op) { replacement_op->common.parent = op->common.parent; replacement_op->common.value.arg = NULL; replacement_op->common.node = op->common.node; op->common.parent->common.value.arg = replacement_op; replacement_op->common.next = op->common.next; } else { op->common.parent->common.value.arg = op->common.next; } } /* Search the parent list */ else while (prev) { /* Traverse all siblings in the parent's argument list */ next = prev->common.next; if (next == op) { if (replacement_op) { replacement_op->common.parent = op->common.parent; replacement_op->common.value.arg = NULL; replacement_op->common.node = op->common.node; prev->common.next = replacement_op; replacement_op->common.next = op->common.next; next = NULL; } else { prev->common.next = op->common.next; next = NULL; } } prev = next; } }cleanup: /* Now we can actually delete the subtree rooted at op */ acpi_ps_delete_parse_tree (op); return_VOID;}/******************************************************************************* * * FUNCTION: acpi_ps_next_parse_state * * PARAMETERS: parser_state - Current parser state object * * RETURN: Status * * DESCRIPTION: Update the parser state based upon the return exception from * the parser callback. * ******************************************************************************/acpi_statusacpi_ps_next_parse_state ( struct acpi_walk_state *walk_state, union acpi_parse_object *op, acpi_status callback_status){ struct acpi_parse_state *parser_state = &walk_state->parser_state; acpi_status status = AE_CTRL_PENDING; ACPI_FUNCTION_TRACE_PTR ("ps_next_parse_state", op); switch (callback_status) { case AE_CTRL_TERMINATE: /* * A control method was terminated via a RETURN statement. * The walk of this method is complete. */ parser_state->aml = parser_state->aml_end; status = AE_CTRL_TERMINATE; break; case AE_CTRL_BREAK: parser_state->aml = walk_state->aml_last_while; walk_state->control_state->common.value = FALSE; status = AE_CTRL_BREAK; break; case AE_CTRL_CONTINUE: parser_state->aml = walk_state->aml_last_while; status = AE_CTRL_CONTINUE; break; case AE_CTRL_PENDING: parser_state->aml = walk_state->aml_last_while; break;#if 0 case AE_CTRL_SKIP: parser_state->aml = parser_state->scope->parse_scope.pkg_end; status = AE_OK; break;#endif case AE_CTRL_TRUE: /* * Predicate of an IF was true, and we are at the matching ELSE. * Just close out this package */ parser_state->aml = acpi_ps_get_next_package_end (parser_state); break; case AE_CTRL_FALSE: /* * Either an IF/WHILE Predicate was false or we encountered a BREAK * opcode. In both cases, we do not execute the rest of the * package; We simply close out the parent (finishing the walk of * this branch of the tree) and continue execution at the parent * level. */ parser_state->aml = parser_state->scope->parse_scope.pkg_end; /* In the case of a BREAK, just force a predicate (if any) to FALSE */ walk_state->control_state->common.value = FALSE; status = AE_CTRL_END; break; case AE_CTRL_TRANSFER: /* * A method call (invocation) -- transfer control */ status = AE_CTRL_TRANSFER; walk_state->prev_op = op; walk_state->method_call_op = op; walk_state->method_call_node = (op->common.value.arg)->common.node; /* Will return value (if any) be used by the caller? */ walk_state->return_used = acpi_ds_is_result_used (op, walk_state); break; default: status = callback_status; if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) { status = AE_OK; } break; } return_ACPI_STATUS (status);}/******************************************************************************* * * FUNCTION: acpi_ps_parse_loop *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -