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 + -
显示快捷键?