📄 psparse.c
字号:
/******************************************************************************
*
* Module Name: psparse - Parser top level AML parse routines
* $Revision: 1.1 $
*
*****************************************************************************/
/*
* Copyright (C) 2000, 2001 R. Byron Moore
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* 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.h>
#define _COMPONENT ACPI_PARSER
MODULE_NAME ("psparse")
u32 acpi_gbl_depth = 0;
extern u32 acpi_gbl_scope_depth;
/*******************************************************************************
*
* FUNCTION: Acpi_ps_peek_opcode
*
* PARAMETERS: None
*
* RETURN: Status
*
* DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
*
******************************************************************************/
static u32
acpi_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)
*
******************************************************************************/
u16
acpi_ps_peek_opcode (
ACPI_PARSE_STATE *parser_state)
{
u8 *aml;
u16 opcode;
aml = parser_state->aml;
opcode = (u16) GET8 (aml);
aml++;
/*
* Original code special cased LNOTEQUAL, LLESSEQUAL, LGREATEREQUAL.
* These opcodes are no longer recognized. Instead, they are broken into
* two opcodes.
*
*
* if (Opcode == AML_EXTOP
* || (Opcode == AML_LNOT
* && (GET8 (Acpi_aml) == AML_LEQUAL
* || GET8 (Acpi_aml) == AML_LGREATER
* || GET8 (Acpi_aml) == AML_LLESS)))
*
* extended Opcode, !=, <=, or >=
*/
if (opcode == AML_EXTOP) {
/* Extended opcode */
opcode = (u16) ((opcode << 8) | GET8 (aml));
aml++;
}
/* don't convert bare name to a namepath */
return (opcode);
}
/*******************************************************************************
*
* FUNCTION: Acpi_ps_create_state
*
* PARAMETERS: Acpi_aml - Acpi_aml code pointer
* Acpi_aml_size - Length of AML code
*
* RETURN: A new parser state object
*
* DESCRIPTION: Create and initialize a new parser state object
*
******************************************************************************/
ACPI_PARSE_STATE *
acpi_ps_create_state (
u8 *aml,
u32 aml_size)
{
ACPI_PARSE_STATE *parser_state;
parser_state = acpi_cm_callocate (sizeof (ACPI_PARSE_STATE));
if (!parser_state) {
return (NULL);
}
parser_state->aml = aml;
parser_state->aml_end = aml + aml_size;
parser_state->pkg_end = parser_state->aml_end;
parser_state->aml_start = aml;
return (parser_state);
}
/*******************************************************************************
*
* FUNCTION: Acpi_ps_find_object
*
* PARAMETERS: Opcode - Current opcode
* Parser_state - Current state
* Walk_state - Current state
* *Op - Where found/new op is returned
*
* RETURN: Status
*
* DESCRIPTION: Find a named object. Two versions - one to search the parse
* tree (for parser-only applications such as acpidump), another
* to search the ACPI internal namespace (the parse tree may no
* longer exist)
*
******************************************************************************/
#ifdef PARSER_ONLY
ACPI_STATUS
acpi_ps_find_object (
u16 opcode,
ACPI_PARSE_OBJECT *op,
ACPI_WALK_STATE *walk_state,
ACPI_PARSE_OBJECT **out_op)
{
NATIVE_CHAR *path;
/* We are only interested in opcodes that have an associated name */
if (!acpi_ps_is_named_op (opcode)) {
*out_op = op;
return (AE_OK);
}
/* Find the name in the parse tree */
path = acpi_ps_get_next_namestring (walk_state->parser_state);
*out_op = acpi_ps_find (acpi_ps_get_parent_scope (walk_state->parser_state),
path, opcode, 1);
if (!(*out_op)) {
return (AE_NOT_FOUND);
}
return (AE_OK);
}
#endif
/*******************************************************************************
*
* FUNCTION: Acpi_ps_complete_this_op
*
* PARAMETERS: Walk_state - Current State
* Op - Op to complete
*
* RETURN: TRUE if Op and subtree was deleted
*
* DESCRIPTION: Perform any cleanup at the completion of an Op.
*
******************************************************************************/
static u8
acpi_ps_complete_this_op (
ACPI_WALK_STATE *walk_state,
ACPI_PARSE_OBJECT *op)
{
#ifndef PARSER_ONLY
ACPI_PARSE_OBJECT *prev;
ACPI_PARSE_OBJECT *next;
ACPI_OPCODE_INFO *op_info;
ACPI_OPCODE_INFO *parent_info;
u32 opcode_class;
ACPI_PARSE_OBJECT *replacement_op = NULL;
op_info = acpi_ps_get_opcode_info (op->opcode);
opcode_class = ACPI_GET_OP_CLASS (op_info);
/* Delete this op and the subtree below it if asked to */
if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) == ACPI_PARSE_DELETE_TREE) &&
(opcode_class != OPTYPE_CONSTANT) &&
(opcode_class != OPTYPE_LITERAL) &&
(opcode_class != OPTYPE_LOCAL_VARIABLE) &&
(opcode_class != OPTYPE_METHOD_ARGUMENT) &&
(opcode_class != OPTYPE_DATA_TERM) &&
(op->opcode != AML_NAMEPATH_OP)) {
/* Make sure that we only delete this subtree */
if (op->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->parent->opcode);
switch (ACPI_GET_OP_CLASS (parent_info)) {
case OPTYPE_CONTROL: /* IF, ELSE, WHILE only */
break;
case OPTYPE_NAMED_OBJECT: /* Scope, method, etc. */
/*
* These opcodes contain Term_arg operands. The current
* op must be replace by a placeholder return op
*/
if ((op->parent->opcode == AML_REGION_OP) ||
(op->parent->opcode == AML_CREATE_FIELD_OP) ||
(op->parent->opcode == AML_BIT_FIELD_OP) ||
(op->parent->opcode == AML_BYTE_FIELD_OP) ||
(op->parent->opcode == AML_WORD_FIELD_OP) ||
(op->parent->opcode == AML_DWORD_FIELD_OP) ||
(op->parent->opcode == AML_QWORD_FIELD_OP)) {
replacement_op = acpi_ps_alloc_op (AML_RETURN_VALUE_OP);
if (!replacement_op) {
return (FALSE);
}
}
break;
default:
replacement_op = acpi_ps_alloc_op (AML_RETURN_VALUE_OP);
if (!replacement_op) {
return (FALSE);
}
}
/* We must unlink this op from the parent tree */
prev = op->parent->value.arg;
if (prev == op) {
/* This op is the first in the list */
if (replacement_op) {
replacement_op->parent = op->parent;
replacement_op->value.arg = NULL;
op->parent->value.arg = replacement_op;
replacement_op->next = op->next;
}
else {
op->parent->value.arg = op->next;
}
}
/* Search the parent list */
else while (prev) {
/* Traverse all siblings in the parent's argument list */
next = prev->next;
if (next == op) {
if (replacement_op) {
replacement_op->parent = op->parent;
replacement_op->value.arg = NULL;
prev->next = replacement_op;
replacement_op->next = op->next;
next = NULL;
}
else {
prev->next = op->next;
next = NULL;
}
}
prev = next;
}
}
/* Now we can actually delete the subtree rooted at op */
acpi_ps_delete_parse_tree (op);
return (TRUE);
}
return (FALSE);
#else
return (FALSE);
#endif
}
/*******************************************************************************
*
* FUNCTION: Acpi_ps_next_parse_state
*
* PARAMETERS: Parser_state - Current parser state object
*
* RETURN:
*
* DESCRIPTION:
*
******************************************************************************/
static ACPI_STATUS
acpi_ps_next_parse_state (
ACPI_WALK_STATE *walk_state,
ACPI_PARSE_OBJECT *op,
ACPI_STATUS callback_status)
{
ACPI_PARSE_STATE *parser_state = walk_state->parser_state;
ACPI_STATUS status = AE_CTRL_PENDING;
u8 *start;
u32 package_length;
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_PENDING:
/*
* Predicate of a WHILE was true and the loop just completed an
* execution. Go back to the start of the loop and reevaluate the
* predicate.
*/
/* Walk_state->Control_state->Common.State =
CONTROL_PREDICATE_EXECUTING;*/
/* TBD: How to handle a break within a while. */
/* This code attempts it */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -