⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psparse.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************** * * Module Name: psparse - Parser top level AML parse routines *              $Revision: 71 $ * *****************************************************************************//* *  Copyright (C) 2000 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"#include "acparser.h"#include "acdispat.h"#include "amlcode.h"#include "acnamesp.h"#include "acdebug.h"#define _COMPONENT          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 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 (	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_ONLYACPI_STATUSacpi_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 u8acpi_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_STATUSacpi_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 */		parser_state->aml = walk_state->aml_last_while;		break;	case AE_CTRL_TRUE:			/*			 * Predicate of an IF was true, and we are at the matching ELSE.			 * Just close out this package			 *			 * Note: Parser_state->Aml is modified by the package length procedure			 * TBD: [Investigate] perhaps it shouldn't, too much trouble			 */		start = parser_state->aml;		package_length = acpi_ps_get_next_package_length (parser_state);		parser_state->aml = start + package_length;		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->value.arg)->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 (status);}/******************************************************************************* * * FUNCTION:    Acpi_ps_parse_loop * * PARAMETERS:  Parser_state        - Current parser state object * * RETURN:      Status * * DESCRIPTION: Parse AML (pointed to by the current parser state) and return *              a tree of ops. * ******************************************************************************/ACPI_STATUSacpi_ps_parse_loop (	ACPI_WALK_STATE         *walk_state){	ACPI_STATUS             status = AE_OK;	ACPI_PARSE_OBJECT       *op = NULL;     /* current op */	ACPI_OPCODE_INFO        *op_info;	ACPI_PARSE_OBJECT       *arg = NULL;	ACPI_PARSE2_OBJECT      *deferred_op;	u32                     arg_count;      /* push for fixed or var args */	u32                     arg_types = 0;	ACPI_PTRDIFF            aml_offset;	u16                     opcode;	ACPI_PARSE_OBJECT       pre_op;	ACPI_PARSE_STATE        *parser_state;	u8                      *aml_op_start;	parser_state = walk_state->parser_state;#ifndef PARSER_ONLY	if (walk_state->walk_type & WALK_METHOD_RESTART) {		/* We are restarting a preempted control method */		if (acpi_ps_has_completed_scope (parser_state)) {			/*			 * We must check if a predicate to an IF or WHILE statement			 * was just completed			 */			if ((parser_state->scope->parse_scope.op) &&				((parser_state->scope->parse_scope.op->opcode == AML_IF_OP) ||				(parser_state->scope->parse_scope.op->opcode == AML_WHILE_OP)) &&				(walk_state->control_state) &&				(walk_state->control_state->common.state ==					CONTROL_PREDICATE_EXECUTING))			{				/*				 * A predicate was just completed, get the value of the				 * predicate and branch based on that value				 */				status = acpi_ds_get_predicate_value (walk_state, NULL, TRUE);				status = acpi_ps_next_parse_state (walk_state, op, status);			}			acpi_ps_pop_scope (parser_state, &op, &arg_types, &arg_count);		}		else if (walk_state->prev_op) {			/* We were in the middle of an op */			op = walk_state->prev_op;			arg_types = walk_state->prev_arg_types;		}	}#endif	/*	 * Iterative parsing loop, while there is more aml to process:	 */	while ((parser_state->aml < parser_state->aml_end) || (op)) {		if (!op) {			/* Get the next opcode from the AML stream */			aml_op_start = parser_state->aml;			aml_offset = parser_state->aml - parser_state->aml_start;			opcode     = acpi_ps_peek_opcode (parser_state);			/*			 * First cut to determine what we have found:			 * 1) A valid AML opcode			 * 2) A name string			 * 3) An unknown/invalid opcode			 */			op_info = acpi_ps_get_opcode_info (opcode);			switch (ACPI_GET_OP_TYPE (op_info))			{			case ACPI_OP_TYPE_OPCODE:				/* Found opcode info, this is a normal opcode */				parser_state->aml += acpi_ps_get_opcode_size (opcode);				arg_types = op_info->parse_args;				break;			case ACPI_OP_TYPE_ASCII:			case ACPI_OP_TYPE_PREFIX:				/*				 * Starts with a valid prefix or ASCII char, this is a name				 * string.  Convert the bare name string to a namepath.				 */				opcode = AML_NAMEPATH_OP;				arg_types = ARGP_NAMESTRING;				break;			case ACPI_OP_TYPE_UNKNOWN:				/* The opcode is unrecognized.  Just skip unknown opcodes */				/* Assume one-byte bad opcode */				parser_state->aml++;				continue;			}			/* Create Op structure and append to parent's argument list */			if (acpi_ps_is_named_op (opcode)) {				pre_op.value.arg = NULL;				pre_op.opcode = opcode;				while (GET_CURRENT_ARG_TYPE (arg_types) != ARGP_NAME) {					arg = acpi_ps_get_next_arg (parser_state,							 GET_CURRENT_ARG_TYPE (arg_types),							 &arg_count);					acpi_ps_append_arg (&pre_op, arg);					INCREMENT_ARG_LIST (arg_types);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -