forked from Minki/linux
ACPICA: changed order of interpretation of operand objects
The interpreter now evaluates operands in the order that they appear (both in the AML and ASL), instead of in reverse order. This previously caused subtle incompatibilities with the MS interpreter as well as being non-intuitive. Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
ba886cd4ac
commit
4e3156b183
@ -472,7 +472,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
|
||||
/* A valid name must be looked up in the namespace */
|
||||
|
||||
if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
|
||||
(arg->common.value.string)) {
|
||||
(arg->common.value.string) &&
|
||||
!(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n",
|
||||
arg));
|
||||
|
||||
@ -595,7 +596,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
|
||||
} else {
|
||||
/* Check for null name case */
|
||||
|
||||
if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) {
|
||||
if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
|
||||
!(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
|
||||
/*
|
||||
* If the name is null, this means that this is an
|
||||
* optional result parameter that was not specified
|
||||
@ -617,7 +619,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state,
|
||||
return_ACPI_STATUS(AE_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
if (op_info->flags & AML_HAS_RETVAL) {
|
||||
if ((op_info->flags & AML_HAS_RETVAL)
|
||||
|| (arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
|
||||
"Argument previously created, already stacked\n"));
|
||||
|
||||
@ -759,3 +762,107 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
|
||||
ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", index));
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ds_evaluate_name_path
|
||||
*
|
||||
* PARAMETERS: walk_state - Current state of the parse tree walk,
|
||||
* the opcode of current operation should be
|
||||
* AML_INT_NAMEPATH_OP
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Translate the -name_path- parse tree object to the equivalent
|
||||
* interpreter object, convert it to value, if needed, duplicate
|
||||
* it, if needed, and push it onto the current result stack.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
union acpi_parse_object *op = walk_state->op;
|
||||
union acpi_operand_object **operand = &walk_state->operands[0];
|
||||
union acpi_operand_object *new_obj_desc;
|
||||
u8 type;
|
||||
|
||||
ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state);
|
||||
|
||||
if (!op->common.parent) {
|
||||
|
||||
/* This happens after certain exception processing */
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
|
||||
(op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) ||
|
||||
(op->common.parent->common.aml_opcode == AML_REF_OF_OP)) {
|
||||
|
||||
/* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */
|
||||
|
||||
goto exit;
|
||||
}
|
||||
|
||||
status = acpi_ds_create_operand(walk_state, op, 0);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (op->common.flags & ACPI_PARSEOP_TARGET) {
|
||||
new_obj_desc = *operand;
|
||||
goto push_result;
|
||||
}
|
||||
|
||||
type = ACPI_GET_OBJECT_TYPE(*operand);
|
||||
|
||||
status = acpi_ex_resolve_to_value(operand, walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (type == ACPI_TYPE_INTEGER) {
|
||||
|
||||
/* It was incremented by acpi_ex_resolve_to_value */
|
||||
|
||||
acpi_ut_remove_reference(*operand);
|
||||
|
||||
status =
|
||||
acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc,
|
||||
walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The object either was anew created or is
|
||||
* a Namespace node - don't decrement it.
|
||||
*/
|
||||
new_obj_desc = *operand;
|
||||
}
|
||||
|
||||
/* Cleanup for name-path operand */
|
||||
|
||||
status = acpi_ds_obj_stack_pop(1, walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
walk_state->result_obj = new_obj_desc;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
push_result:
|
||||
|
||||
walk_state->result_obj = new_obj_desc;
|
||||
|
||||
status = acpi_ds_result_push(walk_state->result_obj, walk_state);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
|
||||
/* Force to take it from stack */
|
||||
|
||||
op->common.flags |= ACPI_PARSEOP_IN_STACK;
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
@ -375,10 +375,17 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
|
||||
/* Decode the Opcode Class */
|
||||
|
||||
switch (op_class) {
|
||||
case AML_CLASS_ARGUMENT: /* constants, literals, etc. - do nothing */
|
||||
case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */
|
||||
|
||||
if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
|
||||
status = acpi_ds_evaluate_name_path(walk_state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case AML_CLASS_EXECUTE: /* most operators with arguments */
|
||||
case AML_CLASS_EXECUTE: /* Most operators with arguments */
|
||||
|
||||
/* Build resolved operand stack */
|
||||
|
||||
|
@ -217,9 +217,10 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc)
|
||||
|
||||
/*
|
||||
* Object must be a valid number and we must be executing
|
||||
* a control method
|
||||
* a control method. NS node could be there for AML_INT_NAMEPATH_OP.
|
||||
*/
|
||||
if ((!obj_desc) ||
|
||||
(ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) ||
|
||||
(ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER)) {
|
||||
return;
|
||||
}
|
||||
|
@ -182,6 +182,7 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
|
||||
ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
|
||||
|
||||
unnamed_op->common.value.arg = NULL;
|
||||
unnamed_op->common.arg_list_length = 0;
|
||||
unnamed_op->common.aml_opcode = walk_state->opcode;
|
||||
|
||||
/*
|
||||
@ -280,6 +281,9 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state,
|
||||
acpi_status status = AE_OK;
|
||||
union acpi_parse_object *op;
|
||||
union acpi_parse_object *named_op = NULL;
|
||||
union acpi_parse_object *parent_scope;
|
||||
u8 argument_count;
|
||||
const struct acpi_opcode_info *op_info;
|
||||
|
||||
ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
|
||||
|
||||
@ -320,8 +324,23 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state,
|
||||
op->named.length = 0;
|
||||
}
|
||||
|
||||
acpi_ps_append_arg(acpi_ps_get_parent_scope
|
||||
(&(walk_state->parser_state)), op);
|
||||
parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
|
||||
acpi_ps_append_arg(parent_scope, op);
|
||||
|
||||
if (parent_scope) {
|
||||
op_info =
|
||||
acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
|
||||
if (op_info->flags & AML_HAS_TARGET) {
|
||||
argument_count =
|
||||
acpi_ps_get_argument_count(op_info->type);
|
||||
if (parent_scope->common.arg_list_length >
|
||||
argument_count) {
|
||||
op->common.flags |= ACPI_PARSEOP_TARGET;
|
||||
}
|
||||
} else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
|
||||
op->common.flags |= ACPI_PARSEOP_TARGET;
|
||||
}
|
||||
}
|
||||
|
||||
if (walk_state->descending_callback != NULL) {
|
||||
/*
|
||||
|
@ -49,6 +49,8 @@
|
||||
#define _COMPONENT ACPI_PARSER
|
||||
ACPI_MODULE_NAME("psopcode")
|
||||
|
||||
const u8 acpi_gbl_argument_count[] = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* NAME: acpi_gbl_aml_op_info
|
||||
@ -59,6 +61,7 @@ ACPI_MODULE_NAME("psopcode")
|
||||
* the operand type.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Summary of opcode types/flags
|
||||
*
|
||||
@ -176,6 +179,7 @@ ACPI_MODULE_NAME("psopcode")
|
||||
AML_CREATE_QWORD_FIELD_OP
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Master Opcode information table. A summary of everything we know about each
|
||||
* opcode, all in one place.
|
||||
@ -779,3 +783,25 @@ char *acpi_ps_get_opcode_name(u16 opcode)
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ps_get_argument_count
|
||||
*
|
||||
* PARAMETERS: op_type - Type associated with the AML opcode
|
||||
*
|
||||
* RETURN: Argument count
|
||||
*
|
||||
* DESCRIPTION: Obtain the number of expected arguments for an AML opcode
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
u8 acpi_ps_get_argument_count(u32 op_type)
|
||||
{
|
||||
|
||||
if (op_type <= AML_TYPE_EXEC_6A_0T_1R) {
|
||||
return (acpi_gbl_argument_count[op_type]);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
@ -171,6 +171,8 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
|
||||
while (arg) {
|
||||
arg->common.parent = op;
|
||||
arg = arg->common.next;
|
||||
|
||||
op->common.arg_list_length++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,6 +269,8 @@ acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state);
|
||||
|
||||
void acpi_ds_clear_operands(struct acpi_walk_state *walk_state);
|
||||
|
||||
acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state);
|
||||
|
||||
/*
|
||||
* dswscope - Scope Stack manipulation
|
||||
*/
|
||||
|
@ -603,6 +603,7 @@ union acpi_parse_value {
|
||||
union acpi_parse_object *next; /* Next op */\
|
||||
struct acpi_namespace_node *node; /* For use by interpreter */\
|
||||
union acpi_parse_value value; /* Value or args associated with the opcode */\
|
||||
u8 arg_list_length; /* Number of elements in the arg list */\
|
||||
ACPI_DISASM_ONLY_MEMBERS (\
|
||||
u8 disasm_flags; /* Used during AML disassembly */\
|
||||
u8 disasm_opcode; /* Subtype used for disassembly */\
|
||||
@ -695,6 +696,8 @@ struct acpi_parse_state {
|
||||
#define ACPI_PARSEOP_NAMED 0x02
|
||||
#define ACPI_PARSEOP_DEFERRED 0x04
|
||||
#define ACPI_PARSEOP_BYTELIST 0x08
|
||||
#define ACPI_PARSEOP_IN_STACK 0x10
|
||||
#define ACPI_PARSEOP_TARGET 0x20
|
||||
#define ACPI_PARSEOP_IN_CACHE 0x80
|
||||
|
||||
/* Parse object disasm_flags */
|
||||
|
@ -109,6 +109,8 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode);
|
||||
|
||||
char *acpi_ps_get_opcode_name(u16 opcode);
|
||||
|
||||
u8 acpi_ps_get_argument_count(u32 op_type);
|
||||
|
||||
/*
|
||||
* psparse - top level parsing routines
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user