diff options
Diffstat (limited to 'drivers/acpi/dispatcher')
-rw-r--r-- | drivers/acpi/dispatcher/Makefile | 9 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsfield.c | 601 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsinit.c | 235 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsmethod.c | 597 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsmthdat.c | 715 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsobject.c | 618 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsopcode.c | 1151 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dsutils.c | 744 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dswexec.c | 751 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dswload.c | 976 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dswscope.c | 229 | ||||
-rw-r--r-- | drivers/acpi/dispatcher/dswstate.c | 1100 |
12 files changed, 7726 insertions, 0 deletions
diff --git a/drivers/acpi/dispatcher/Makefile b/drivers/acpi/dispatcher/Makefile new file mode 100644 index 00000000000..eb7e602a83c --- /dev/null +++ b/drivers/acpi/dispatcher/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ + dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \ + dsinit.o + +EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c new file mode 100644 index 00000000000..2779211be75 --- /dev/null +++ b/drivers/acpi/dispatcher/dsfield.c @@ -0,0 +1,601 @@ +/****************************************************************************** + * + * Module Name: dsfield - Dispatcher field 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/amlcode.h> +#include <acpi/acdispat.h> +#include <acpi/acinterp.h> +#include <acpi/acnamesp.h> +#include <acpi/acparser.h> + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsfield") + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_create_buffer_field + * + * PARAMETERS: Opcode - The opcode to be executed + * Operands - List of operands for the opcode + * walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Execute the create_field operators: + * create_bit_field_op, + * create_byte_field_op, + * create_word_field_op, + * create_dword_field_op, + * create_qword_field_op, + * create_field_op (all of which define fields in buffers) + * + ******************************************************************************/ + +acpi_status +acpi_ds_create_buffer_field ( + union acpi_parse_object *op, + struct acpi_walk_state *walk_state) +{ + union acpi_parse_object *arg; + struct acpi_namespace_node *node; + acpi_status status; + union acpi_operand_object *obj_desc; + union acpi_operand_object *second_desc = NULL; + u32 flags; + + + ACPI_FUNCTION_TRACE ("ds_create_buffer_field"); + + + /* Get the name_string argument */ + + if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { + arg = acpi_ps_get_arg (op, 3); + } + else { + /* Create Bit/Byte/Word/Dword field */ + + arg = acpi_ps_get_arg (op, 2); + } + + if (!arg) { + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + if (walk_state->deferred_node) { + node = walk_state->deferred_node; + status = AE_OK; + } + else { + /* + * During the load phase, we want to enter the name of the field into + * the namespace. During the execute phase (when we evaluate the size + * operand), we want to lookup the name + */ + if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) { + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE; + } + else { + flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND; + } + + /* + * Enter the name_string into the namespace + */ + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS1, + flags, walk_state, &(node)); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (arg->common.value.string, status); + return_ACPI_STATUS (status); + } + } + + /* We could put the returned object (Node) on the object stack for later, but + * for now, we will put it in the "op" object that the parser uses, so we + * can get it again at the end of this scope + */ + op->common.node = node; + + /* + * If there is no object attached to the node, this node was just created and + * we need to create the field object. Otherwise, this was a lookup of an + * existing node and we don't want to create the field object again. + */ + obj_desc = acpi_ns_get_attached_object (node); + if (obj_desc) { + return_ACPI_STATUS (AE_OK); + } + + /* + * The Field definition is not fully parsed at this time. + * (We must save the address of the AML for the buffer and index operands) + */ + + /* Create the buffer field object */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER_FIELD); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* + * Remember location in AML stream of the field unit + * opcode and operands -- since the buffer and index + * operands must be evaluated. + */ + second_desc = obj_desc->common.next_object; + second_desc->extra.aml_start = op->named.data; + second_desc->extra.aml_length = op->named.length; + obj_desc->buffer_field.node = node; + + /* Attach constructed field descriptors to parent node */ + + status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_BUFFER_FIELD); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + +cleanup: + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_get_field_names + * + * PARAMETERS: Info - create_field info structure + * ` walk_state - Current method state + * Arg - First parser arg for the field name list + * + * RETURN: Status + * + * DESCRIPTION: Process all named fields in a field declaration. Names are + * entered into the namespace. + * + ******************************************************************************/ + +acpi_status +acpi_ds_get_field_names ( + struct acpi_create_field_info *info, + struct acpi_walk_state *walk_state, + union acpi_parse_object *arg) +{ + acpi_status status; + acpi_integer position; + + + ACPI_FUNCTION_TRACE_PTR ("ds_get_field_names", info); + + + /* First field starts at bit zero */ + + info->field_bit_position = 0; + + /* Process all elements in the field list (of parse nodes) */ + + while (arg) { + /* + * Three types of field elements are handled: + * 1) Offset - specifies a bit offset + * 2) access_as - changes the access mode + * 3) Name - Enters a new named field into the namespace + */ + switch (arg->common.aml_opcode) { + case AML_INT_RESERVEDFIELD_OP: + + position = (acpi_integer) info->field_bit_position + + (acpi_integer) arg->common.value.size; + + if (position > ACPI_UINT32_MAX) { + ACPI_REPORT_ERROR (("Bit offset within field too large (> 0xFFFFFFFF)\n")); + return_ACPI_STATUS (AE_SUPPORT); + } + + info->field_bit_position = (u32) position; + break; + + + case AML_INT_ACCESSFIELD_OP: + + /* + * Get a new access_type and access_attribute -- to be used for all + * field units that follow, until field end or another access_as keyword. + * + * In field_flags, preserve the flag bits other than the ACCESS_TYPE bits + */ + info->field_flags = (u8) ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | + ((u8) ((u32) arg->common.value.integer >> 8))); + + info->attribute = (u8) (arg->common.value.integer); + break; + + + case AML_INT_NAMEDFIELD_OP: + + /* Lookup the name */ + + status = acpi_ns_lookup (walk_state->scope_info, + (char *) &arg->named.name, + info->field_type, ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE, + walk_state, &info->field_node); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR ((char *) &arg->named.name, status); + if (status != AE_ALREADY_EXISTS) { + return_ACPI_STATUS (status); + } + + /* Already exists, ignore error */ + } + else { + arg->common.node = info->field_node; + info->field_bit_length = arg->common.value.size; + + /* Create and initialize an object for the new Field Node */ + + status = acpi_ex_prep_field_value (info); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Keep track of bit position for the next field */ + + position = (acpi_integer) info->field_bit_position + + (acpi_integer) arg->common.value.size; + + if (position > ACPI_UINT32_MAX) { + ACPI_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n", + (char *) &info->field_node->name)); + return_ACPI_STATUS (AE_SUPPORT); + } + + info->field_bit_position += info->field_bit_length; + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid opcode in field list: %X\n", + arg->common.aml_opcode)); + return_ACPI_STATUS (AE_AML_BAD_OPCODE); + } + + arg = arg->common.next; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_create_field + * + * PARAMETERS: Op - Op containing the Field definition and args + * region_node - Object for the containing Operation Region + * ` walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Create a new field in the specified operation region + * + ******************************************************************************/ + +acpi_status +acpi_ds_create_field ( + union acpi_parse_object *op, + struct acpi_namespace_node *region_node, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_parse_object *arg; + struct acpi_create_field_info info; + + + ACPI_FUNCTION_TRACE_PTR ("ds_create_field", op); + + + /* First arg is the name of the parent op_region (must already exist) */ + + arg = op->common.value.arg; + if (!region_node) { + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.name, + ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, ®ion_node); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (arg->common.value.name, status); + return_ACPI_STATUS (status); + } + } + + /* Second arg is the field flags */ + + arg = arg->common.next; + info.field_flags = (u8) arg->common.value.integer; + info.attribute = 0; + + /* Each remaining arg is a Named Field */ + + info.field_type = ACPI_TYPE_LOCAL_REGION_FIELD; + info.region_node = region_node; + + status = acpi_ds_get_field_names (&info, walk_state, arg->common.next); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_init_field_objects + * + * PARAMETERS: Op - Op containing the Field definition and args + * ` walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: For each "Field Unit" name in the argument list that is + * part of the field declaration, enter the name into the + * namespace. + * + ******************************************************************************/ + +acpi_status +acpi_ds_init_field_objects ( + union acpi_parse_object *op, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_parse_object *arg = NULL; + struct acpi_namespace_node *node; + u8 type = 0; + + + ACPI_FUNCTION_TRACE_PTR ("ds_init_field_objects", op); + + + switch (walk_state->opcode) { + case AML_FIELD_OP: + arg = acpi_ps_get_arg (op, 2); + type = ACPI_TYPE_LOCAL_REGION_FIELD; + break; + + case AML_BANK_FIELD_OP: + arg = acpi_ps_get_arg (op, 4); + type = ACPI_TYPE_LOCAL_BANK_FIELD; + break; + + case AML_INDEX_FIELD_OP: + arg = acpi_ps_get_arg (op, 3); + type = ACPI_TYPE_LOCAL_INDEX_FIELD; + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Walk the list of entries in the field_list + */ + while (arg) { + /* Ignore OFFSET and ACCESSAS terms here */ + + if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { + status = acpi_ns_lookup (walk_state->scope_info, + (char *) &arg->named.name, + type, ACPI_IMODE_LOAD_PASS1, + ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, + walk_state, &node); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR ((char *) &arg->named.name, status); + if (status != AE_ALREADY_EXISTS) { + return_ACPI_STATUS (status); + } + + /* Name already exists, just ignore this error */ + + status = AE_OK; + } + + arg->common.node = node; + } + + /* Move to next field in the list */ + + arg = arg->common.next; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_create_bank_field + * + * PARAMETERS: Op - Op containing the Field definition and args + * region_node - Object for the containing Operation Region + * ` walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Create a new bank field in the specified operation region + * + ******************************************************************************/ + +acpi_status +acpi_ds_create_bank_field ( + union acpi_parse_object *op, + struct acpi_namespace_node *region_node, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_parse_object *arg; + struct acpi_create_field_info info; + + + ACPI_FUNCTION_TRACE_PTR ("ds_create_bank_field", op); + + + /* First arg is the name of the parent op_region (must already exist) */ + + arg = op->common.value.arg; + if (!region_node) { + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.name, + ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, ®ion_node); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (arg->common.value.name, status); + return_ACPI_STATUS (status); + } + } + + /* Second arg is the Bank Register (Field) (must already exist) */ + + arg = arg->common.next; + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (arg->common.value.string, status); + return_ACPI_STATUS (status); + } + + /* Third arg is the bank_value */ + + arg = arg->common.next; + info.bank_value = (u32) arg->common.value.integer; + + /* Fourth arg is the field flags */ + + arg = arg->common.next; + info.field_flags = (u8) arg->common.value.integer; + + /* Each remaining arg is a Named Field */ + + info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD; + info.region_node = region_node; + + status = acpi_ds_get_field_names (&info, walk_state, arg->common.next); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_create_index_field + * + * PARAMETERS: Op - Op containing the Field definition and args + * region_node - Object for the containing Operation Region + * ` walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Create a new index field in the specified operation region + * + ******************************************************************************/ + +acpi_status +acpi_ds_create_index_field ( + union acpi_parse_object *op, + struct acpi_namespace_node *region_node, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_parse_object *arg; + struct acpi_create_field_info info; + + + ACPI_FUNCTION_TRACE_PTR ("ds_create_index_field", op); + + + /* First arg is the name of the Index register (must already exist) */ + + arg = op->common.value.arg; + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (arg->common.value.string, status); + return_ACPI_STATUS (status); + } + + /* Second arg is the data register (must already exist) */ + + arg = arg->common.next; + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT, walk_state, &info.data_register_node); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (arg->common.value.string, status); + return_ACPI_STATUS (status); + } + + /* Next arg is the field flags */ + + arg = arg->common.next; + info.field_flags = (u8) arg->common.value.integer; + + /* Each remaining arg is a Named Field */ + + info.field_type = ACPI_TYPE_LOCAL_INDEX_FIELD; + info.region_node = region_node; + + status = acpi_ds_get_field_names (&info, walk_state, arg->common.next); + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c new file mode 100644 index 00000000000..b4d264dbbf6 --- /dev/null +++ b/drivers/acpi/dispatcher/dsinit.c @@ -0,0 +1,235 @@ +/****************************************************************************** + * + * Module Name: dsinit - Object initialization namespace walk + * + *****************************************************************************/ + +/* + * 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acdispat.h> +#include <acpi/acnamesp.h> + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsinit") + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_init_one_object + * + * PARAMETERS: obj_handle - Node + * Level - Current nesting level + * Context - Points to a init info struct + * return_value - Not used + * + * RETURN: Status + * + * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object + * within the namespace. + * + * Currently, the only objects that require initialization are: + * 1) Methods + * 2) Operation Regions + * + ******************************************************************************/ + +acpi_status +acpi_ds_init_one_object ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value) +{ + acpi_object_type type; + acpi_status status; + struct acpi_init_walk_info *info = (struct acpi_init_walk_info *) context; + + + ACPI_FUNCTION_NAME ("ds_init_one_object"); + + + /* + * We are only interested in objects owned by the table that + * was just loaded + */ + if (((struct acpi_namespace_node *) obj_handle)->owner_id != + info->table_desc->table_id) { + return (AE_OK); + } + + info->object_count++; + + /* And even then, we are only interested in a few object types */ + + type = acpi_ns_get_type (obj_handle); + + switch (type) { + case ACPI_TYPE_REGION: + + status = acpi_ds_initialize_region (obj_handle); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n", + obj_handle, acpi_ut_get_node_name (obj_handle), + acpi_format_exception (status))); + } + + info->op_region_count++; + break; + + + case ACPI_TYPE_METHOD: + + info->method_count++; + + /* Print a dot for each method unless we are going to print the entire pathname */ + + if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); + } + + /* + * Set the execution data width (32 or 64) based upon the + * revision number of the parent ACPI table. + * TBD: This is really for possible future support of integer width + * on a per-table basis. Currently, we just use a global for the width. + */ + if (info->table_desc->pointer->revision == 1) { + ((struct acpi_namespace_node *) obj_handle)->flags |= ANOBJ_DATA_WIDTH_32; + } + + /* + * Always parse methods to detect errors, we will delete + * the parse tree below + */ + status = acpi_ds_parse_method (obj_handle); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n", + obj_handle, acpi_ut_get_node_name (obj_handle), + acpi_format_exception (status))); + + /* This parse failed, but we will continue parsing more methods */ + + break; + } + + /* + * Delete the parse tree. We simply re-parse the method + * for every execution since there isn't much overhead + */ + acpi_ns_delete_namespace_subtree (obj_handle); + acpi_ns_delete_namespace_by_owner (((struct acpi_namespace_node *) obj_handle)->object->method.owning_id); + break; + + + case ACPI_TYPE_DEVICE: + + info->device_count++; + break; + + + default: + break; + } + + /* + * We ignore errors from above, and always return OK, since + * we don't want to abort the walk on a single error. + */ + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_initialize_objects + * + * PARAMETERS: table_desc - Descriptor for parent ACPI table + * start_node - Root of subtree to be initialized. + * + * RETURN: Status + * + * DESCRIPTION: Walk the namespace starting at "start_node" and perform any + * necessary initialization on the objects found therein + * + ******************************************************************************/ + +acpi_status +acpi_ds_initialize_objects ( + struct acpi_table_desc *table_desc, + struct acpi_namespace_node *start_node) +{ + acpi_status status; + struct acpi_init_walk_info info; + + + ACPI_FUNCTION_TRACE ("ds_initialize_objects"); + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "**** Starting initialization of namespace objects ****\n")); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "Parsing all Control Methods:")); + + info.method_count = 0; + info.op_region_count = 0; + info.object_count = 0; + info.device_count = 0; + info.table_desc = table_desc; + + /* Walk entire namespace from the supplied root */ + + status = acpi_walk_namespace (ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX, + acpi_ds_init_one_object, &info, NULL); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed, %s\n", + acpi_format_exception (status))); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n", + table_desc->pointer->signature, table_desc->table_id, info.object_count, + info.device_count, info.method_count, info.op_region_count)); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "%hd Methods, %hd Regions\n", info.method_count, info.op_region_count)); + + return_ACPI_STATUS (AE_OK); +} + + diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c new file mode 100644 index 00000000000..9f0456cb9bb --- /dev/null +++ b/drivers/acpi/dispatcher/dsmethod.c @@ -0,0 +1,597 @@ +/****************************************************************************** + * + * Module Name: dsmethod - Parser/Interpreter interface - control method parsing + * + *****************************************************************************/ + +/* + * 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acparser.h> +#include <acpi/amlcode.h> +#include <acpi/acdispat.h> +#include <acpi/acinterp.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsmethod") + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_parse_method + * + * PARAMETERS: obj_handle - Method node + * + * RETURN: Status + * + * DESCRIPTION: Call the parser and parse the AML that is associated with the + * method. + * + * MUTEX: Assumes parser is locked + * + ******************************************************************************/ + +acpi_status +acpi_ds_parse_method ( + acpi_handle obj_handle) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + union acpi_parse_object *op; + struct acpi_namespace_node *node; + acpi_owner_id owner_id; + struct acpi_walk_state *walk_state; + + + ACPI_FUNCTION_TRACE_PTR ("ds_parse_method", obj_handle); + + + /* Parameter Validation */ + + if (!obj_handle) { + return_ACPI_STATUS (AE_NULL_ENTRY); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** named_obj=%p\n", + acpi_ut_get_node_name (obj_handle), obj_handle)); + + /* Extract the method object from the method Node */ + + node = (struct acpi_namespace_node *) obj_handle; + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + /* Create a mutex for the method if there is a concurrency limit */ + + if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) && + (!obj_desc->method.semaphore)) { + status = acpi_os_create_semaphore (obj_desc->method.concurrency, + obj_desc->method.concurrency, + &obj_desc->method.semaphore); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * Allocate a new parser op to be the root of the parsed + * method tree + */ + op = acpi_ps_alloc_op (AML_METHOD_OP); + if (!op) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Init new op with the method name and pointer back to the Node */ + + acpi_ps_set_name (op, node->name.integer); + op->common.node = node; + + /* + * Get a new owner_id for objects created by this method. Namespace + * objects (such as Operation Regions) can be created during the + * first pass parse. + */ + owner_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD); + obj_desc->method.owning_id = owner_id; + + /* Create and initialize a new walk state */ + + walk_state = acpi_ds_create_walk_state (owner_id, NULL, NULL, NULL); + if (!walk_state) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + status = acpi_ds_init_aml_walk (walk_state, op, node, + obj_desc->method.aml_start, + obj_desc->method.aml_length, NULL, 1); + if (ACPI_FAILURE (status)) { + acpi_ds_delete_walk_state (walk_state); + return_ACPI_STATUS (status); + } + + /* + * Parse the method, first pass + * + * The first pass load is where newly declared named objects are + * added into the namespace. Actual evaluation of + * the named objects (what would be called a "second + * pass") happens during the actual execution of the + * method so that operands to the named objects can + * take on dynamic run-time values. + */ + status = acpi_ps_parse_aml (walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, + "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n", + acpi_ut_get_node_name (obj_handle), obj_handle, op)); + + acpi_ps_delete_parse_tree (op); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_begin_method_execution + * + * PARAMETERS: method_node - Node of the method + * obj_desc - The method object + * calling_method_node - Caller of this method (if non-null) + * + * RETURN: Status + * + * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, + * increments the thread count, and waits at the method semaphore + * for clearance to execute. + * + ******************************************************************************/ + +acpi_status +acpi_ds_begin_method_execution ( + struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_namespace_node *calling_method_node) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR ("ds_begin_method_execution", method_node); + + + if (!method_node) { + return_ACPI_STATUS (AE_NULL_ENTRY); + } + + /* + * If there is a concurrency limit on this method, we need to + * obtain a unit from the method semaphore. + */ + if (obj_desc->method.semaphore) { + /* + * Allow recursive method calls, up to the reentrancy/concurrency + * limit imposed by the SERIALIZED rule and the sync_level method + * parameter. + * + * The point of this code is to avoid permanently blocking a + * thread that is making recursive method calls. + */ + if (method_node == calling_method_node) { + if (obj_desc->method.thread_count >= obj_desc->method.concurrency) { + return_ACPI_STATUS (AE_AML_METHOD_LIMIT); + } + } + + /* + * Get a unit from the method semaphore. This releases the + * interpreter if we block + */ + status = acpi_ex_system_wait_semaphore (obj_desc->method.semaphore, + ACPI_WAIT_FOREVER); + } + + /* + * Increment the method parse tree thread count since it has been + * reentered one more time (even if it is the same thread) + */ + obj_desc->method.thread_count++; + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_call_control_method + * + * PARAMETERS: Thread - Info for this thread + * this_walk_state - Current walk state + * Op - Current Op to be walked + * + * RETURN: Status + * + * DESCRIPTION: Transfer execution to a called control method + * + ******************************************************************************/ + +acpi_status +acpi_ds_call_control_method ( + struct acpi_thread_state *thread, + struct acpi_walk_state *this_walk_state, + union acpi_parse_object *op) +{ + acpi_status status; + struct acpi_namespace_node *method_node; + struct acpi_walk_state *next_walk_state; + union acpi_operand_object *obj_desc; + struct acpi_parameter_info info; + u32 i; + + + ACPI_FUNCTION_TRACE_PTR ("ds_call_control_method", this_walk_state); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n", + this_walk_state->prev_op, this_walk_state)); + + /* + * Get the namespace entry for the control method we are about to call + */ + method_node = this_walk_state->method_call_node; + if (!method_node) { + return_ACPI_STATUS (AE_NULL_ENTRY); + } + + obj_desc = acpi_ns_get_attached_object (method_node); + if (!obj_desc) { + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + obj_desc->method.owning_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD); + + /* Init for new method, wait on concurrency semaphore */ + + status = acpi_ds_begin_method_execution (method_node, obj_desc, + this_walk_state->method_node); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { + /* 1) Parse: Create a new walk state for the preempting walk */ + + next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, + op, obj_desc, NULL); + if (!next_walk_state) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Create and init a Root Node */ + + op = acpi_ps_create_scope_op (); + if (!op) { + status = AE_NO_MEMORY; + goto cleanup; + } + + status = acpi_ds_init_aml_walk (next_walk_state, op, method_node, + obj_desc->method.aml_start, obj_desc->method.aml_length, + NULL, 1); + if (ACPI_FAILURE (status)) { + acpi_ds_delete_walk_state (next_walk_state); + goto cleanup; + } + + /* Begin AML parse */ + + status = acpi_ps_parse_aml (next_walk_state); + acpi_ps_delete_parse_tree (op); + } + + /* 2) Execute: Create a new state for the preempting walk */ + + next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, + NULL, obj_desc, thread); + if (!next_walk_state) { + status = AE_NO_MEMORY; + goto cleanup; + } + /* + * The resolved arguments were put on the previous walk state's operand + * stack. Operands on the previous walk state stack always + * start at index 0. + * Null terminate the list of arguments + */ + this_walk_state->operands [this_walk_state->num_operands] = NULL; + + info.parameters = &this_walk_state->operands[0]; + info.parameter_type = ACPI_PARAM_ARGS; + + status = acpi_ds_init_aml_walk (next_walk_state, NULL, method_node, + obj_desc->method.aml_start, obj_desc->method.aml_length, + &info, 3); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* + * Delete the operands on the previous walkstate operand stack + * (they were copied to new objects) + */ + for (i = 0; i < obj_desc->method.param_count; i++) { + acpi_ut_remove_reference (this_walk_state->operands [i]); + this_walk_state->operands [i] = NULL; + } + + /* Clear the operand stack */ + + this_walk_state->num_operands = 0; + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Starting nested execution, newstate=%p\n", next_walk_state)); + + if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { + status = obj_desc->method.implementation (next_walk_state); + return_ACPI_STATUS (status); + } + + return_ACPI_STATUS (AE_OK); + + + /* On error, we must delete the new walk state */ + +cleanup: + if (next_walk_state && (next_walk_state->method_desc)) { + /* Decrement the thread count on the method parse tree */ + + next_walk_state->method_desc->method.thread_count--; + } + (void) acpi_ds_terminate_control_method (next_walk_state); + acpi_ds_delete_walk_state (next_walk_state); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_restart_control_method + * + * PARAMETERS: walk_state - State for preempted method (caller) + * return_desc - Return value from the called method + * + * RETURN: Status + * + * DESCRIPTION: Restart a method that was preempted by another (nested) method + * invocation. Handle the return value (if any) from the callee. + * + ******************************************************************************/ + +acpi_status +acpi_ds_restart_control_method ( + struct acpi_walk_state *walk_state, + union acpi_operand_object *return_desc) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ds_restart_control_method", walk_state); + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "****Restart [%4.4s] Op %p return_value_from_callee %p\n", + (char *) &walk_state->method_node->name, walk_state->method_call_op, + return_desc)); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + " return_from_this_method_used?=%X res_stack %p Walk %p\n", + walk_state->return_used, + walk_state->results, walk_state)); + + /* Did the called method return a value? */ + + if (return_desc) { + /* Are we actually going to use the return value? */ + + if (walk_state->return_used) { + /* Save the return value from the previous method */ + + status = acpi_ds_result_push (return_desc, walk_state); + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (return_desc); + return_ACPI_STATUS (status); + } + + /* + * Save as THIS method's return value in case it is returned + * immediately to yet another method + */ + walk_state->return_desc = return_desc; + } + + /* + * The following code is the + * optional support for a so-called "implicit return". Some AML code + * assumes that the last value of the method is "implicitly" returned + * to the caller. Just save the last result as the return value. + * NOTE: this is optional because the ASL language does not actually + * support this behavior. + */ + else if (!acpi_ds_do_implicit_return (return_desc, walk_state, FALSE)) { + /* + * Delete the return value if it will not be used by the + * calling method + */ + acpi_ut_remove_reference (return_desc); + } + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_terminate_control_method + * + * PARAMETERS: walk_state - State of the method + * + * RETURN: Status + * + * DESCRIPTION: Terminate a control method. Delete everything that the method + * created, delete all locals and arguments, and delete the parse + * tree if requested. + * + ******************************************************************************/ + +acpi_status +acpi_ds_terminate_control_method ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *obj_desc; + struct acpi_namespace_node *method_node; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ds_terminate_control_method", walk_state); + + + if (!walk_state) { + return (AE_BAD_PARAMETER); + } + + /* The current method object was saved in the walk state */ + + obj_desc = walk_state->method_desc; + if (!obj_desc) { + return_ACPI_STATUS (AE_OK); + } + + /* Delete all arguments and locals */ + + acpi_ds_method_data_delete_all (walk_state); + + /* + * Lock the parser while we terminate this method. + * If this is the last thread executing the method, + * we have additional cleanup to perform + */ + status = acpi_ut_acquire_mutex (ACPI_MTX_PARSER); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Signal completion of the execution of this method if necessary */ + + if (walk_state->method_desc->method.semaphore) { + status = acpi_os_signal_semaphore ( + walk_state->method_desc->method.semaphore, 1); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not signal method semaphore\n")); + status = AE_OK; + + /* Ignore error and continue cleanup */ + } + } + + if (walk_state->method_desc->method.thread_count) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "*** Not deleting method namespace, there are still %d threads\n", + walk_state->method_desc->method.thread_count)); + } + + if (!walk_state->method_desc->method.thread_count) { + /* + * Support to dynamically change a method from not_serialized to + * Serialized if it appears that the method is written foolishly and + * does not support multiple thread execution. The best example of this + * is if such a method creates namespace objects and blocks. A second + * thread will fail with an AE_ALREADY_EXISTS exception + * + * This code is here because we must wait until the last thread exits + * before creating the synchronization semaphore. + */ + if ((walk_state->method_desc->method.concurrency == 1) && + (!walk_state->method_desc->method.semaphore)) { + status = acpi_os_create_semaphore (1, + 1, + &walk_state->method_desc->method.semaphore); + } + + /* + * There are no more threads executing this method. Perform + * additional cleanup. + * + * The method Node is stored in the walk state + */ + method_node = walk_state->method_node; + + /* + * Delete any namespace entries created immediately underneath + * the method + */ + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (method_node->child) { + acpi_ns_delete_namespace_subtree (method_node); + } + + /* + * Delete any namespace entries created anywhere else within + * the namespace + */ + acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owning_id); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + status = acpi_ut_release_mutex (ACPI_MTX_PARSER); + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c new file mode 100644 index 00000000000..f31d095f983 --- /dev/null +++ b/drivers/acpi/dispatcher/dsmthdat.c @@ -0,0 +1,715 @@ +/******************************************************************************* + * + * Module Name: dsmthdat - control method arguments and local variables + * + ******************************************************************************/ + +/* + * 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acdispat.h> +#include <acpi/amlcode.h> +#include <acpi/acnamesp.h> +#include <acpi/acinterp.h> + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsmthdat") + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_init + * + * PARAMETERS: walk_state - Current walk state object + * + * RETURN: Status + * + * DESCRIPTION: Initialize the data structures that hold the method's arguments + * and locals. The data struct is an array of NTEs for each. + * This allows ref_of and de_ref_of to work properly for these + * special data types. + * + * NOTES: walk_state fields are initialized to zero by the + * ACPI_MEM_CALLOCATE(). + * + * A pseudo-Namespace Node is assigned to each argument and local + * so that ref_of() can return a pointer to the Node. + * + ******************************************************************************/ + +void +acpi_ds_method_data_init ( + struct acpi_walk_state *walk_state) +{ + u32 i; + + + ACPI_FUNCTION_TRACE ("ds_method_data_init"); + + + /* Init the method arguments */ + + for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) { + ACPI_MOVE_32_TO_32 (&walk_state->arguments[i].name, + NAMEOF_ARG_NTE); + walk_state->arguments[i].name.integer |= (i << 24); + walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED; + walk_state->arguments[i].type = ACPI_TYPE_ANY; + walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG; + } + + /* Init the method locals */ + + for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) { + ACPI_MOVE_32_TO_32 (&walk_state->local_variables[i].name, + NAMEOF_LOCAL_NTE); + + walk_state->local_variables[i].name.integer |= (i << 24); + walk_state->local_variables[i].descriptor = ACPI_DESC_TYPE_NAMED; + walk_state->local_variables[i].type = ACPI_TYPE_ANY; + walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL; + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_delete_all + * + * PARAMETERS: walk_state - Current walk state object + * + * RETURN: None + * + * DESCRIPTION: Delete method locals and arguments. Arguments are only + * deleted if this method was called from another method. + * + ******************************************************************************/ + +void +acpi_ds_method_data_delete_all ( + struct acpi_walk_state *walk_state) +{ + u32 index; + + + ACPI_FUNCTION_TRACE ("ds_method_data_delete_all"); + + + /* Detach the locals */ + + for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) { + if (walk_state->local_variables[index].object) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Local%d=%p\n", + index, walk_state->local_variables[index].object)); + + /* Detach object (if present) and remove a reference */ + + acpi_ns_detach_object (&walk_state->local_variables[index]); + } + } + + /* Detach the arguments */ + + for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) { + if (walk_state->arguments[index].object) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Arg%d=%p\n", + index, walk_state->arguments[index].object)); + + /* Detach object (if present) and remove a reference */ + + acpi_ns_detach_object (&walk_state->arguments[index]); + } + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_init_args + * + * PARAMETERS: *Params - Pointer to a parameter list for the method + * max_param_count - The arg count for this method + * walk_state - Current walk state object + * + * RETURN: Status + * + * DESCRIPTION: Initialize arguments for a method. The parameter list is a list + * of ACPI operand objects, either null terminated or whose length + * is defined by max_param_count. + * + ******************************************************************************/ + +acpi_status +acpi_ds_method_data_init_args ( + union acpi_operand_object **params, + u32 max_param_count, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + u32 index = 0; + + + ACPI_FUNCTION_TRACE_PTR ("ds_method_data_init_args", params); + + + if (!params) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "No param list passed to method\n")); + return_ACPI_STATUS (AE_OK); + } + + /* Copy passed parameters into the new method stack frame */ + + while ((index < ACPI_METHOD_NUM_ARGS) && (index < max_param_count) && params[index]) { + /* + * A valid parameter. + * Store the argument in the method/walk descriptor. + * Do not copy the arg in order to implement call by reference + */ + status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index], walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + index++; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%d args passed to method\n", index)); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_get_node + * + * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - which local_var or argument whose type + * to get + * walk_state - Current walk state object + * + * RETURN: Get the Node associated with a local or arg. + * + ******************************************************************************/ + +acpi_status +acpi_ds_method_data_get_node ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state, + struct acpi_namespace_node **node) +{ + ACPI_FUNCTION_TRACE ("ds_method_data_get_node"); + + + /* + * Method Locals and Arguments are supported + */ + switch (opcode) { + case AML_LOCAL_OP: + + if (index > ACPI_METHOD_MAX_LOCAL) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n", + index, ACPI_METHOD_MAX_LOCAL)); + return_ACPI_STATUS (AE_AML_INVALID_INDEX); + } + + /* Return a pointer to the pseudo-node */ + + *node = &walk_state->local_variables[index]; + break; + + case AML_ARG_OP: + + if (index > ACPI_METHOD_MAX_ARG) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n", + index, ACPI_METHOD_MAX_ARG)); + return_ACPI_STATUS (AE_AML_INVALID_INDEX); + } + + /* Return a pointer to the pseudo-node */ + + *node = &walk_state->arguments[index]; + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Opcode %d is invalid\n", opcode)); + return_ACPI_STATUS (AE_AML_BAD_OPCODE); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_set_value + * + * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - which local_var or argument to get + * Object - Object to be inserted into the stack entry + * walk_state - Current walk state object + * + * RETURN: Status + * + * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index. + * Note: There is no "implicit conversion" for locals. + * + ******************************************************************************/ + +acpi_status +acpi_ds_method_data_set_value ( + u16 opcode, + u32 index, + union acpi_operand_object *object, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + struct acpi_namespace_node *node; + + + ACPI_FUNCTION_TRACE ("ds_method_data_set_value"); + + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "new_obj %p Opcode %X, Refs=%d [%s]\n", object, + opcode, object->common.reference_count, + acpi_ut_get_type_name (object->common.type))); + + /* Get the namespace node for the arg/local */ + + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Increment ref count so object can't be deleted while installed. + * NOTE: We do not copy the object in order to preserve the call by + * reference semantics of ACPI Control Method invocation. + * (See ACPI specification 2.0_c) + */ + acpi_ut_add_reference (object); + + /* Install the object */ + + node->object = object; + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_get_type + * + * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - which local_var or argument whose type + * to get + * walk_state - Current walk state object + * + * RETURN: Data type of current value of the selected Arg or Local + * + ******************************************************************************/ +#ifdef ACPI_FUTURE_USAGE +acpi_object_type +acpi_ds_method_data_get_type ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + struct acpi_namespace_node *node; + union acpi_operand_object *object; + + + ACPI_FUNCTION_TRACE ("ds_method_data_get_type"); + + + /* Get the namespace node for the arg/local */ + + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); + if (ACPI_FAILURE (status)) { + return_VALUE ((ACPI_TYPE_NOT_FOUND)); + } + + /* Get the object */ + + object = acpi_ns_get_attached_object (node); + if (!object) { + /* Uninitialized local/arg, return TYPE_ANY */ + + return_VALUE (ACPI_TYPE_ANY); + } + + /* Get the object type */ + + return_VALUE (ACPI_GET_OBJECT_TYPE (object)); +} +#endif /* ACPI_FUTURE_USAGE */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_get_value + * + * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - which local_var or argument to get + * walk_state - Current walk state object + * *dest_desc - Ptr to Descriptor into which selected Arg + * or Local value should be copied + * + * RETURN: Status + * + * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame + * at the current top of the method stack. + * Used only in acpi_ex_resolve_to_value(). + * + ******************************************************************************/ + +acpi_status +acpi_ds_method_data_get_value ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state, + union acpi_operand_object **dest_desc) +{ + acpi_status status; + struct acpi_namespace_node *node; + union acpi_operand_object *object; + + + ACPI_FUNCTION_TRACE ("ds_method_data_get_value"); + + + /* Validate the object descriptor */ + + if (!dest_desc) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null object descriptor pointer\n")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Get the namespace node for the arg/local */ + + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Get the object from the node */ + + object = node->object; + + /* Examine the returned object, it must be valid. */ + + if (!object) { + /* + * Index points to uninitialized object. + * This means that either 1) The expected argument was + * not passed to the method, or 2) A local variable + * was referenced by the method (via the ASL) + * before it was initialized. Either case is an error. + */ + + /* If slack enabled, init the local_x/arg_x to an Integer of value zero */ + + if (acpi_gbl_enable_interpreter_slack) { + object = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!object) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + object->integer.value = 0; + node->object = object; + } + + /* Otherwise, return the error */ + + else switch (opcode) { + case AML_ARG_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at node %p\n", + index, node)); + + return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG); + + case AML_LOCAL_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at node %p\n", + index, node)); + + return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL); + + default: + ACPI_REPORT_ERROR (("Not Arg/Local opcode: %X\n", opcode)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + } + + /* + * The Index points to an initialized and valid object. + * Return an additional reference to the object + */ + *dest_desc = object; + acpi_ut_add_reference (object); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_method_data_delete_value + * + * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - which local_var or argument to delete + * walk_state - Current walk state object + * + * RETURN: None + * + * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts + * a null into the stack slot after the object is deleted. + * + ******************************************************************************/ + +void +acpi_ds_method_data_delete_value ( + u16 opcode, + u32 index, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + struct acpi_namespace_node *node; + union acpi_operand_object *object; + + + ACPI_FUNCTION_TRACE ("ds_method_data_delete_value"); + + + /* Get the namespace node for the arg/local */ + + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); + if (ACPI_FAILURE (status)) { + return_VOID; + } + + /* Get the associated object */ + + object = acpi_ns_get_attached_object (node); + + /* + * Undefine the Arg or Local by setting its descriptor + * pointer to NULL. Locals/Args can contain both + * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs + */ + node->object = NULL; + + if ((object) && + (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_OPERAND)) { + /* + * There is a valid object. + * Decrement the reference count by one to balance the + * increment when the object was stored. + */ + acpi_ut_remove_reference (object); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_store_object_to_local + * + * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP + * Index - which local_var or argument to set + * obj_desc - Value to be stored + * walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed + * as the new value for the Arg or Local and the reference count + * for obj_desc is incremented. + * + ******************************************************************************/ + +acpi_status +acpi_ds_store_object_to_local ( + u16 opcode, + u32 index, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + struct acpi_namespace_node *node; + union acpi_operand_object *current_obj_desc; + union acpi_operand_object *new_obj_desc; + + + ACPI_FUNCTION_TRACE ("ds_store_object_to_local"); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n", + opcode, index, obj_desc)); + + /* Parameter validation */ + + if (!obj_desc) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Get the namespace node for the arg/local */ + + status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + current_obj_desc = acpi_ns_get_attached_object (node); + if (current_obj_desc == obj_desc) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p already installed!\n", + obj_desc)); + return_ACPI_STATUS (status); + } + + /* + * If the reference count on the object is more than one, we must + * take a copy of the object before we store. A reference count + * of exactly 1 means that the object was just created during the + * evaluation of an expression, and we can safely use it since it + * is not used anywhere else. + */ + new_obj_desc = obj_desc; + if (obj_desc->common.reference_count > 1) { + status = acpi_ut_copy_iobject_to_iobject (obj_desc, &new_obj_desc, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * If there is an object already in this slot, we either + * have to delete it, or if this is an argument and there + * is an object reference stored there, we have to do + * an indirect store! + */ + if (current_obj_desc) { + /* + * Check for an indirect store if an argument + * contains an object reference (stored as an Node). + * We don't allow this automatic dereferencing for + * locals, since a store to a local should overwrite + * anything there, including an object reference. + * + * If both Arg0 and Local0 contain ref_of (Local4): + * + * Store (1, Arg0) - Causes indirect store to local4 + * Store (1, Local0) - Stores 1 in local0, overwriting + * the reference to local4 + * Store (1, de_refof (Local0)) - Causes indirect store to local4 + * + * Weird, but true. + */ + if (opcode == AML_ARG_OP) { + /* + * Make sure that the object is the correct type. This may be overkill, but + * it is here because references were NS nodes in the past. Now they are + * operand objects of type Reference. + */ + if (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) != ACPI_DESC_TYPE_OPERAND) { + ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: [%s]\n", + acpi_ut_get_descriptor_name (current_obj_desc))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* + * If we have a valid reference object that came from ref_of(), do the + * indirect store + */ + if ((current_obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) && + (current_obj_desc->reference.opcode == AML_REF_OF_OP)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Arg (%p) is an obj_ref(Node), storing in node %p\n", + new_obj_desc, current_obj_desc)); + + /* + * Store this object to the Node (perform the indirect store) + * NOTE: No implicit conversion is performed, as per the ACPI + * specification rules on storing to Locals/Args. + */ + status = acpi_ex_store_object_to_node (new_obj_desc, + current_obj_desc->reference.object, walk_state, + ACPI_NO_IMPLICIT_CONVERSION); + + /* Remove local reference if we copied the object above */ + + if (new_obj_desc != obj_desc) { + acpi_ut_remove_reference (new_obj_desc); + } + return_ACPI_STATUS (status); + } + } + + /* + * Delete the existing object + * before storing the new one + */ + acpi_ds_method_data_delete_value (opcode, index, walk_state); + } + + /* + * Install the Obj descriptor (*new_obj_desc) into + * the descriptor for the Arg or Local. + * (increments the object reference count by one) + */ + status = acpi_ds_method_data_set_value (opcode, index, new_obj_desc, walk_state); + + /* Remove local reference if we copied the object above */ + + if (new_obj_desc != obj_desc) { + acpi_ut_remove_reference (new_obj_desc); + } + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c new file mode 100644 index 00000000000..eb8af4785bc --- /dev/null +++ b/drivers/acpi/dispatcher/dsobject.c @@ -0,0 +1,618 @@ +/****************************************************************************** + * + * Module Name: dsobject - Dispatcher object management 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acparser.h> +#include <acpi/amlcode.h> +#include <acpi/acdispat.h> +#include <acpi/acnamesp.h> +#include <acpi/acinterp.h> + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsobject") + + +#ifndef ACPI_NO_METHOD_EXECUTION +/***************************************************************************** + * + * FUNCTION: acpi_ds_build_internal_object + * + * PARAMETERS: walk_state - Current walk state + * Op - Parser object to be translated + * obj_desc_ptr - Where the ACPI internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: Translate a parser Op object to the equivalent namespace object + * Simple objects are any objects other than a package object! + * + ****************************************************************************/ + +acpi_status +acpi_ds_build_internal_object ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + union acpi_operand_object **obj_desc_ptr) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ds_build_internal_object"); + + + *obj_desc_ptr = NULL; + if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { + /* + * This is an named object reference. If this name was + * previously looked up in the namespace, it was stored in this op. + * Otherwise, go ahead and look it up now + */ + if (!op->common.node) { + status = acpi_ns_lookup (walk_state->scope_info, op->common.value.string, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, + (struct acpi_namespace_node **) &(op->common.node)); + + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (op->common.value.string, status); + return_ACPI_STATUS (status); + } + } + } + + /* Create and init the internal ACPI object */ + + obj_desc = acpi_ut_create_internal_object ((acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode, &obj_desc); + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); + } + + *obj_desc_ptr = obj_desc; + return_ACPI_STATUS (AE_OK); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_build_internal_buffer_obj + * + * PARAMETERS: walk_state - Current walk state + * Op - Parser object to be translated + * buffer_length - Length of the buffer + * obj_desc_ptr - Where the ACPI internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: Translate a parser Op package object to the equivalent + * namespace object + * + ****************************************************************************/ + +acpi_status +acpi_ds_build_internal_buffer_obj ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + u32 buffer_length, + union acpi_operand_object **obj_desc_ptr) +{ + union acpi_parse_object *arg; + union acpi_operand_object *obj_desc; + union acpi_parse_object *byte_list; + u32 byte_list_length = 0; + + + ACPI_FUNCTION_TRACE ("ds_build_internal_buffer_obj"); + + + obj_desc = *obj_desc_ptr; + if (obj_desc) { + /* + * We are evaluating a Named buffer object "Name (xxxx, Buffer)". + * The buffer object already exists (from the NS node) + */ + } + else { + /* Create a new buffer object */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); + *obj_desc_ptr = obj_desc; + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + } + + /* + * Second arg is the buffer data (optional) byte_list can be either + * individual bytes or a string initializer. In either case, a + * byte_list appears in the AML. + */ + arg = op->common.value.arg; /* skip first arg */ + + byte_list = arg->named.next; + if (byte_list) { + if (byte_list->common.aml_opcode != AML_INT_BYTELIST_OP) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Expecting bytelist, got AML opcode %X in op %p\n", + byte_list->common.aml_opcode, byte_list)); + + acpi_ut_remove_reference (obj_desc); + return (AE_TYPE); + } + + byte_list_length = (u32) byte_list->common.value.integer; + } + + /* + * The buffer length (number of bytes) will be the larger of: + * 1) The specified buffer length and + * 2) The length of the initializer byte list + */ + obj_desc->buffer.length = buffer_length; + if (byte_list_length > buffer_length) { + obj_desc->buffer.length = byte_list_length; + } + + /* Allocate the buffer */ + + if (obj_desc->buffer.length == 0) { + obj_desc->buffer.pointer = NULL; + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Buffer defined with zero length in AML, creating\n")); + } + else { + obj_desc->buffer.pointer = ACPI_MEM_CALLOCATE ( + obj_desc->buffer.length); + if (!obj_desc->buffer.pointer) { + acpi_ut_delete_object_desc (obj_desc); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize buffer from the byte_list (if present) */ + + if (byte_list) { + ACPI_MEMCPY (obj_desc->buffer.pointer, byte_list->named.data, + byte_list_length); + } + } + + obj_desc->buffer.flags |= AOPOBJ_DATA_VALID; + op->common.node = (struct acpi_namespace_node *) obj_desc; + return_ACPI_STATUS (AE_OK); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_build_internal_package_obj + * + * PARAMETERS: walk_state - Current walk state + * Op - Parser object to be translated + * package_length - Number of elements in the package + * obj_desc_ptr - Where the ACPI internal object is returned + * + * RETURN: Status + * + * DESCRIPTION: Translate a parser Op package object to the equivalent + * namespace object + * + ****************************************************************************/ + +acpi_status +acpi_ds_build_internal_package_obj ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + u32 package_length, + union acpi_operand_object **obj_desc_ptr) +{ + union acpi_parse_object *arg; + union acpi_parse_object *parent; + union acpi_operand_object *obj_desc = NULL; + u32 package_list_length; + acpi_status status = AE_OK; + u32 i; + + + ACPI_FUNCTION_TRACE ("ds_build_internal_package_obj"); + + + /* Find the parent of a possibly nested package */ + + parent = op->common.parent; + while ((parent->common.aml_opcode == AML_PACKAGE_OP) || + (parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { + parent = parent->common.parent; + } + + obj_desc = *obj_desc_ptr; + if (obj_desc) { + /* + * We are evaluating a Named package object "Name (xxxx, Package)". + * Get the existing package object from the NS node + */ + } + else { + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE); + *obj_desc_ptr = obj_desc; + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + obj_desc->package.node = parent->common.node; + } + + obj_desc->package.count = package_length; + + /* Count the number of items in the package list */ + + package_list_length = 0; + arg = op->common.value.arg; + arg = arg->common.next; + while (arg) { + package_list_length++; + arg = arg->common.next; + } + + /* + * The package length (number of elements) will be the greater + * of the specified length and the length of the initializer list + */ + if (package_list_length > package_length) { + obj_desc->package.count = package_list_length; + } + + /* + * Allocate the pointer array (array of pointers to the + * individual objects). Add an extra pointer slot so + * that the list is always null terminated. + */ + obj_desc->package.elements = ACPI_MEM_CALLOCATE ( + ((acpi_size) obj_desc->package.count + 1) * sizeof (void *)); + + if (!obj_desc->package.elements) { + acpi_ut_delete_object_desc (obj_desc); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Now init the elements of the package + */ + i = 0; + arg = op->common.value.arg; + arg = arg->common.next; + while (arg) { + if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { + /* Object (package or buffer) is already built */ + + obj_desc->package.elements[i] = ACPI_CAST_PTR (union acpi_operand_object, arg->common.node); + } + else { + status = acpi_ds_build_internal_object (walk_state, arg, + &obj_desc->package.elements[i]); + } + + i++; + arg = arg->common.next; + } + + obj_desc->package.flags |= AOPOBJ_DATA_VALID; + op->common.node = (struct acpi_namespace_node *) obj_desc; + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_create_node + * + * PARAMETERS: walk_state - Current walk state + * Node - NS Node to be initialized + * Op - Parser object to be translated + * + * RETURN: Status + * + * DESCRIPTION: Create the object to be associated with a namespace node + * + ****************************************************************************/ + +acpi_status +acpi_ds_create_node ( + struct acpi_walk_state *walk_state, + struct acpi_namespace_node *node, + union acpi_parse_object *op) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_TRACE_PTR ("ds_create_node", op); + + + /* + * Because of the execution pass through the non-control-method + * parts of the table, we can arrive here twice. Only init + * the named object node the first time through + */ + if (acpi_ns_get_attached_object (node)) { + return_ACPI_STATUS (AE_OK); + } + + if (!op->common.value.arg) { + /* No arguments, there is nothing to do */ + + return_ACPI_STATUS (AE_OK); + } + + /* Build an internal object for the argument(s) */ + + status = acpi_ds_build_internal_object (walk_state, op->common.value.arg, &obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Re-type the object according to its argument */ + + node->type = ACPI_GET_OBJECT_TYPE (obj_desc); + + /* Attach obj to node */ + + status = acpi_ns_attach_object (node, obj_desc, node->type); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + +#endif /* ACPI_NO_METHOD_EXECUTION */ + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_init_object_from_op + * + * PARAMETERS: walk_state - Current walk state + * Op - Parser op used to init the internal object + * Opcode - AML opcode associated with the object + * ret_obj_desc - Namespace object to be initialized + * + * RETURN: Status + * + * DESCRIPTION: Initialize a namespace object from a parser Op and its + * associated arguments. The namespace object is a more compact + * representation of the Op and its arguments. + * + ****************************************************************************/ + +acpi_status +acpi_ds_init_object_from_op ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + u16 opcode, + union acpi_operand_object **ret_obj_desc) +{ + const struct acpi_opcode_info *op_info; + union acpi_operand_object *obj_desc; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ds_init_object_from_op"); + + + obj_desc = *ret_obj_desc; + op_info = acpi_ps_get_opcode_info (opcode); + if (op_info->class == AML_CLASS_UNKNOWN) { + /* Unknown opcode */ + + return_ACPI_STATUS (AE_TYPE); + } + + /* Perform per-object initialization */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_BUFFER: + + /* + * Defer evaluation of Buffer term_arg operand + */ + obj_desc->buffer.node = (struct acpi_namespace_node *) walk_state->operands[0]; + obj_desc->buffer.aml_start = op->named.data; + obj_desc->buffer.aml_length = op->named.length; + break; + + + case ACPI_TYPE_PACKAGE: + + /* + * Defer evaluation of Package term_arg operand + */ + obj_desc->package.node = (struct acpi_namespace_node *) walk_state->operands[0]; + obj_desc->package.aml_start = op->named.data; + obj_desc->package.aml_length = op->named.length; + break; + + + case ACPI_TYPE_INTEGER: + + switch (op_info->type) { + case AML_TYPE_CONSTANT: + /* + * Resolve AML Constants here - AND ONLY HERE! + * All constants are integers. + * We mark the integer with a flag that indicates that it started life + * as a constant -- so that stores to constants will perform as expected (noop). + * (zero_op is used as a placeholder for optional target operands.) + */ + obj_desc->common.flags = AOPOBJ_AML_CONSTANT; + + switch (opcode) { + case AML_ZERO_OP: + + obj_desc->integer.value = 0; + break; + + case AML_ONE_OP: + + obj_desc->integer.value = 1; + break; + + case AML_ONES_OP: + + obj_desc->integer.value = ACPI_INTEGER_MAX; + + /* Truncate value if we are executing from a 32-bit ACPI table */ + +#ifndef ACPI_NO_METHOD_EXECUTION + acpi_ex_truncate_for32bit_table (obj_desc); +#endif + break; + + case AML_REVISION_OP: + + obj_desc->integer.value = ACPI_CA_VERSION; + break; + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown constant opcode %X\n", opcode)); + status = AE_AML_OPERAND_TYPE; + break; + } + break; + + + case AML_TYPE_LITERAL: + + obj_desc->integer.value = op->common.value.integer; + break; + + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", op_info->type)); + status = AE_AML_OPERAND_TYPE; + break; + } + break; + + + case ACPI_TYPE_STRING: + + obj_desc->string.pointer = op->common.value.string; + obj_desc->string.length = (u32) ACPI_STRLEN (op->common.value.string); + + /* + * The string is contained in the ACPI table, don't ever try + * to delete it + */ + obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; + break; + + + case ACPI_TYPE_METHOD: + break; + + + case ACPI_TYPE_LOCAL_REFERENCE: + + switch (op_info->type) { + case AML_TYPE_LOCAL_VARIABLE: + + /* Split the opcode into a base opcode + offset */ + + obj_desc->reference.opcode = AML_LOCAL_OP; + obj_desc->reference.offset = opcode - AML_LOCAL_OP; + +#ifndef ACPI_NO_METHOD_EXECUTION + status = acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset, + walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object); +#endif + break; + + + case AML_TYPE_METHOD_ARGUMENT: + + /* Split the opcode into a base opcode + offset */ + + obj_desc->reference.opcode = AML_ARG_OP; + obj_desc->reference.offset = opcode - AML_ARG_OP; + +#ifndef ACPI_NO_METHOD_EXECUTION + status = acpi_ds_method_data_get_node (AML_ARG_OP, obj_desc->reference.offset, + walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object); +#endif + break; + + default: /* Other literals, etc.. */ + + if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { + /* Node was saved in Op */ + + obj_desc->reference.node = op->common.node; + } + + obj_desc->reference.opcode = opcode; + break; + } + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unimplemented data type: %X\n", + ACPI_GET_OBJECT_TYPE (obj_desc))); + + status = AE_AML_OPERAND_TYPE; + break; + } + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c new file mode 100644 index 00000000000..5c987a0e7b7 --- /dev/null +++ b/drivers/acpi/dispatcher/dsopcode.c @@ -0,0 +1,1151 @@ +/****************************************************************************** + * + * Module Name: dsopcode - Dispatcher Op Region support and handling of + * "control" opcodes + * + *****************************************************************************/ + +/* + * 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acparser.h> +#include <acpi/amlcode.h> +#include <acpi/acdispat.h> +#include <acpi/acinterp.h> +#include <acpi/acnamesp.h> +#include <acpi/acevents.h> + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsopcode") + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_execute_arguments + * + * PARAMETERS: Node - Parent NS node + * aml_length - Length of executable AML + * aml_start - Pointer to the AML + * + * RETURN: Status. + * + * DESCRIPTION: Late (deferred) execution of region or field arguments + * + ****************************************************************************/ + +acpi_status +acpi_ds_execute_arguments ( + struct acpi_namespace_node *node, + struct acpi_namespace_node *scope_node, + u32 aml_length, + u8 *aml_start) +{ + acpi_status status; + union acpi_parse_object *op; + struct acpi_walk_state *walk_state; + + + ACPI_FUNCTION_TRACE ("ds_execute_arguments"); + + + /* + * Allocate a new parser op to be the root of the parsed tree + */ + op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP); + if (!op) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Save the Node for use in acpi_ps_parse_aml */ + + op->common.node = scope_node; + + /* Create and initialize a new parser state */ + + walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL); + if (!walk_state) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, + aml_length, NULL, 1); + if (ACPI_FAILURE (status)) { + acpi_ds_delete_walk_state (walk_state); + return_ACPI_STATUS (status); + } + + /* Mark this parse as a deferred opcode */ + + walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP; + walk_state->deferred_node = node; + + /* Pass1: Parse the entire declaration */ + + status = acpi_ps_parse_aml (walk_state); + if (ACPI_FAILURE (status)) { + acpi_ps_delete_parse_tree (op); + return_ACPI_STATUS (status); + } + + /* Get and init the Op created above */ + + op->common.node = node; + acpi_ps_delete_parse_tree (op); + + /* Evaluate the deferred arguments */ + + op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP); + if (!op) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + op->common.node = scope_node; + + /* Create and initialize a new parser state */ + + walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL); + if (!walk_state) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Execute the opcode and arguments */ + + status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start, + aml_length, NULL, 3); + if (ACPI_FAILURE (status)) { + acpi_ds_delete_walk_state (walk_state); + return_ACPI_STATUS (status); + } + + /* Mark this execution as a deferred opcode */ + + walk_state->deferred_node = node; + status = acpi_ps_parse_aml (walk_state); + acpi_ps_delete_parse_tree (op); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_get_buffer_field_arguments + * + * PARAMETERS: obj_desc - A valid buffer_field object + * + * RETURN: Status. + * + * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late + * evaluation of these field attributes. + * + ****************************************************************************/ + +acpi_status +acpi_ds_get_buffer_field_arguments ( + union acpi_operand_object *obj_desc) +{ + union acpi_operand_object *extra_desc; + struct acpi_namespace_node *node; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ds_get_buffer_field_arguments", obj_desc); + + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS (AE_OK); + } + + /* Get the AML pointer (method object) and buffer_field node */ + + extra_desc = acpi_ns_get_secondary_object (obj_desc); + node = obj_desc->buffer_field.node; + + ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_BUFFER_FIELD, node, NULL)); + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] buffer_field Arg Init\n", + acpi_ut_get_node_name (node))); + + /* Execute the AML code for the term_arg arguments */ + + status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node), + extra_desc->extra.aml_length, extra_desc->extra.aml_start); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_get_buffer_arguments + * + * PARAMETERS: obj_desc - A valid Buffer object + * + * RETURN: Status. + * + * DESCRIPTION: Get Buffer length and initializer byte list. This implements + * the late evaluation of these attributes. + * + ****************************************************************************/ + +acpi_status +acpi_ds_get_buffer_arguments ( + union acpi_operand_object *obj_desc) +{ + struct acpi_namespace_node *node; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ds_get_buffer_arguments", obj_desc); + + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS (AE_OK); + } + + /* Get the Buffer node */ + + node = obj_desc->buffer.node; + if (!node) { + ACPI_REPORT_ERROR (( + "No pointer back to NS node in buffer obj %p\n", obj_desc)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Buffer Arg Init\n")); + + /* Execute the AML code for the term_arg arguments */ + + status = acpi_ds_execute_arguments (node, node, + obj_desc->buffer.aml_length, obj_desc->buffer.aml_start); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_get_package_arguments + * + * PARAMETERS: obj_desc - A valid Package object + * + * RETURN: Status. + * + * DESCRIPTION: Get Package length and initializer byte list. This implements + * the late evaluation of these attributes. + * + ****************************************************************************/ + +acpi_status +acpi_ds_get_package_arguments ( + union acpi_operand_object *obj_desc) +{ + struct acpi_namespace_node *node; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ds_get_package_arguments", obj_desc); + + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS (AE_OK); + } + + /* Get the Package node */ + + node = obj_desc->package.node; + if (!node) { + ACPI_REPORT_ERROR (( + "No pointer back to NS node in package %p\n", obj_desc)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Package Arg Init\n")); + + /* Execute the AML code for the term_arg arguments */ + + status = acpi_ds_execute_arguments (node, node, + obj_desc->package.aml_length, obj_desc->package.aml_start); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_get_region_arguments + * + * PARAMETERS: obj_desc - A valid region object + * + * RETURN: Status. + * + * DESCRIPTION: Get region address and length. This implements the late + * evaluation of these region attributes. + * + ****************************************************************************/ + +acpi_status +acpi_ds_get_region_arguments ( + union acpi_operand_object *obj_desc) +{ + struct acpi_namespace_node *node; + acpi_status status; + union acpi_operand_object *extra_desc; + + + ACPI_FUNCTION_TRACE_PTR ("ds_get_region_arguments", obj_desc); + + + if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { + return_ACPI_STATUS (AE_OK); + } + + extra_desc = acpi_ns_get_secondary_object (obj_desc); + if (!extra_desc) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Get the Region node */ + + node = obj_desc->region.node; + + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_REGION, node, NULL)); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] op_region Arg Init at AML %p\n", + acpi_ut_get_node_name (node), extra_desc->extra.aml_start)); + + /* Execute the argument AML */ + + status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node), + extra_desc->extra.aml_length, extra_desc->extra.aml_start); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_initialize_region + * + * PARAMETERS: Op - A valid region Op object + * + * RETURN: Status + * + * DESCRIPTION: Front end to ev_initialize_region + * + ****************************************************************************/ + +acpi_status +acpi_ds_initialize_region ( + acpi_handle obj_handle) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + + obj_desc = acpi_ns_get_attached_object (obj_handle); + + /* Namespace is NOT locked */ + + status = acpi_ev_initialize_region (obj_desc, FALSE); + return (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_init_buffer_field + * + * PARAMETERS: aml_opcode - create_xxx_field + * obj_desc - buffer_field object + * buffer_desc - Host Buffer + * offset_desc - Offset into buffer + * Length - Length of field (CREATE_FIELD_OP only) + * Result - Where to store the result + * + * RETURN: Status + * + * DESCRIPTION: Perform actual initialization of a buffer field + * + ****************************************************************************/ + +acpi_status +acpi_ds_init_buffer_field ( + u16 aml_opcode, + union acpi_operand_object *obj_desc, + union acpi_operand_object *buffer_desc, + union acpi_operand_object *offset_desc, + union acpi_operand_object *length_desc, + union acpi_operand_object *result_desc) +{ + u32 offset; + u32 bit_offset; + u32 bit_count; + u8 field_flags; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ds_init_buffer_field", obj_desc); + + + /* Host object must be a Buffer */ + + if (ACPI_GET_OBJECT_TYPE (buffer_desc) != ACPI_TYPE_BUFFER) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Target of Create Field is not a Buffer object - %s\n", + acpi_ut_get_object_type_name (buffer_desc))); + + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + + /* + * The last parameter to all of these opcodes (result_desc) started + * out as a name_string, and should therefore now be a NS node + * after resolution in acpi_ex_resolve_operands(). + */ + if (ACPI_GET_DESCRIPTOR_TYPE (result_desc) != ACPI_DESC_TYPE_NAMED) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination not a NS Node [%s]\n", + acpi_ps_get_opcode_name (aml_opcode), acpi_ut_get_descriptor_name (result_desc))); + + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + + offset = (u32) offset_desc->integer.value; + + /* + * Setup the Bit offsets and counts, according to the opcode + */ + switch (aml_opcode) { + case AML_CREATE_FIELD_OP: + + /* Offset is in bits, count is in bits */ + + bit_offset = offset; + bit_count = (u32) length_desc->integer.value; + field_flags = AML_FIELD_ACCESS_BYTE; + break; + + case AML_CREATE_BIT_FIELD_OP: + + /* Offset is in bits, Field is one bit */ + + bit_offset = offset; + bit_count = 1; + field_flags = AML_FIELD_ACCESS_BYTE; + break; + + case AML_CREATE_BYTE_FIELD_OP: + + /* Offset is in bytes, field is one byte */ + + bit_offset = 8 * offset; + bit_count = 8; + field_flags = AML_FIELD_ACCESS_BYTE; + break; + + case AML_CREATE_WORD_FIELD_OP: + + /* Offset is in bytes, field is one word */ + + bit_offset = 8 * offset; + bit_count = 16; + field_flags = AML_FIELD_ACCESS_WORD; + break; + + case AML_CREATE_DWORD_FIELD_OP: + + /* Offset is in bytes, field is one dword */ + + bit_offset = 8 * offset; + bit_count = 32; + field_flags = AML_FIELD_ACCESS_DWORD; + break; + + case AML_CREATE_QWORD_FIELD_OP: + + /* Offset is in bytes, field is one qword */ + + bit_offset = 8 * offset; + bit_count = 64; + field_flags = AML_FIELD_ACCESS_QWORD; + break; + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown field creation opcode %02x\n", + aml_opcode)); + status = AE_AML_BAD_OPCODE; + goto cleanup; + } + + /* Entire field must fit within the current length of the buffer */ + + if ((bit_offset + bit_count) > + (8 * (u32) buffer_desc->buffer.length)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Field [%4.4s] size %d exceeds Buffer [%4.4s] size %d (bits)\n", + acpi_ut_get_node_name (result_desc), + bit_offset + bit_count, + acpi_ut_get_node_name (buffer_desc->buffer.node), + 8 * (u32) buffer_desc->buffer.length)); + status = AE_AML_BUFFER_LIMIT; + goto cleanup; + } + + /* + * Initialize areas of the field object that are common to all fields + * For field_flags, use LOCK_RULE = 0 (NO_LOCK), UPDATE_RULE = 0 (UPDATE_PRESERVE) + */ + status = acpi_ex_prep_common_field_object (obj_desc, field_flags, 0, + bit_offset, bit_count); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + obj_desc->buffer_field.buffer_obj = buffer_desc; + + /* Reference count for buffer_desc inherits obj_desc count */ + + buffer_desc->common.reference_count = (u16) (buffer_desc->common.reference_count + + obj_desc->common.reference_count); + + +cleanup: + + /* Always delete the operands */ + + acpi_ut_remove_reference (offset_desc); + acpi_ut_remove_reference (buffer_desc); + + if (aml_opcode == AML_CREATE_FIELD_OP) { + acpi_ut_remove_reference (length_desc); + } + + /* On failure, delete the result descriptor */ + + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (result_desc); /* Result descriptor */ + } + else { + /* Now the address and length are valid for this buffer_field */ + + obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID; + } + + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_eval_buffer_field_operands + * + * PARAMETERS: walk_state - Current walk + * Op - A valid buffer_field Op object + * + * RETURN: Status + * + * DESCRIPTION: Get buffer_field Buffer and Index + * Called from acpi_ds_exec_end_op during buffer_field parse tree walk + * + ****************************************************************************/ + +acpi_status +acpi_ds_eval_buffer_field_operands ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + struct acpi_namespace_node *node; + union acpi_parse_object *next_op; + + + ACPI_FUNCTION_TRACE_PTR ("ds_eval_buffer_field_operands", op); + + + /* + * This is where we evaluate the address and length fields of the + * create_xxx_field declaration + */ + node = op->common.node; + + /* next_op points to the op that holds the Buffer */ + + next_op = op->common.value.arg; + + /* Evaluate/create the address and length operands */ + + status = acpi_ds_create_operands (walk_state, next_op); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* Resolve the operands */ + + status = acpi_ex_resolve_operands (op->common.aml_opcode, + ACPI_WALK_OPERANDS, walk_state); + + ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, + acpi_ps_get_opcode_name (op->common.aml_opcode), + walk_state->num_operands, "after acpi_ex_resolve_operands"); + + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) bad operand(s) (%X)\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), status)); + + return_ACPI_STATUS (status); + } + + /* Initialize the Buffer Field */ + + if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { + /* NOTE: Slightly different operands for this opcode */ + + status = acpi_ds_init_buffer_field (op->common.aml_opcode, obj_desc, + walk_state->operands[0], walk_state->operands[1], + walk_state->operands[2], walk_state->operands[3]); + } + else { + /* All other, create_xxx_field opcodes */ + + status = acpi_ds_init_buffer_field (op->common.aml_opcode, obj_desc, + walk_state->operands[0], walk_state->operands[1], + NULL, walk_state->operands[2]); + } + + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_eval_region_operands + * + * PARAMETERS: walk_state - Current walk + * Op - A valid region Op object + * + * RETURN: Status + * + * DESCRIPTION: Get region address and length + * Called from acpi_ds_exec_end_op during op_region parse tree walk + * + ****************************************************************************/ + +acpi_status +acpi_ds_eval_region_operands ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + union acpi_operand_object *operand_desc; + struct acpi_namespace_node *node; + union acpi_parse_object *next_op; + + + ACPI_FUNCTION_TRACE_PTR ("ds_eval_region_operands", op); + + + /* + * This is where we evaluate the address and length fields of the op_region declaration + */ + node = op->common.node; + + /* next_op points to the op that holds the space_iD */ + + next_op = op->common.value.arg; + + /* next_op points to address op */ + + next_op = next_op->common.next; + + /* Evaluate/create the address and length operands */ + + status = acpi_ds_create_operands (walk_state, next_op); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Resolve the length and address operands to numbers */ + + status = acpi_ex_resolve_operands (op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, + acpi_ps_get_opcode_name (op->common.aml_opcode), + 1, "after acpi_ex_resolve_operands"); + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + return_ACPI_STATUS (AE_NOT_EXIST); + } + + /* + * Get the length operand and save it + * (at Top of stack) + */ + operand_desc = walk_state->operands[walk_state->num_operands - 1]; + + obj_desc->region.length = (u32) operand_desc->integer.value; + acpi_ut_remove_reference (operand_desc); + + /* + * Get the address and save it + * (at top of stack - 1) + */ + operand_desc = walk_state->operands[walk_state->num_operands - 2]; + + obj_desc->region.address = (acpi_physical_address) operand_desc->integer.value; + acpi_ut_remove_reference (operand_desc); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "rgn_obj %p Addr %8.8X%8.8X Len %X\n", + obj_desc, + ACPI_FORMAT_UINT64 (obj_desc->region.address), + obj_desc->region.length)); + + /* Now the address and length are valid for this opregion */ + + obj_desc->region.flags |= AOPOBJ_DATA_VALID; + + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_eval_data_object_operands + * + * PARAMETERS: walk_state - Current walk + * Op - A valid data_object Op object + * obj_desc - data_object + * + * RETURN: Status + * + * DESCRIPTION: Get the operands and complete the following data object types: + * Buffer, Package. + * + ****************************************************************************/ + +acpi_status +acpi_ds_eval_data_object_operands ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + union acpi_operand_object *obj_desc) +{ + acpi_status status; + union acpi_operand_object *arg_desc; + u32 length; + + + ACPI_FUNCTION_TRACE ("ds_eval_data_object_operands"); + + + /* The first operand (for all of these data objects) is the length */ + + status = acpi_ds_create_operand (walk_state, op->common.value.arg, 1); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ex_resolve_operands (walk_state->opcode, + &(walk_state->operands [walk_state->num_operands -1]), + walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Extract length operand */ + + arg_desc = walk_state->operands [walk_state->num_operands - 1]; + length = (u32) arg_desc->integer.value; + + /* Cleanup for length operand */ + + status = acpi_ds_obj_stack_pop (1, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + acpi_ut_remove_reference (arg_desc); + + /* + * Create the actual data object + */ + switch (op->common.aml_opcode) { + case AML_BUFFER_OP: + + status = acpi_ds_build_internal_buffer_obj (walk_state, op, length, &obj_desc); + break; + + case AML_PACKAGE_OP: + case AML_VAR_PACKAGE_OP: + + status = acpi_ds_build_internal_package_obj (walk_state, op, length, &obj_desc); + break; + + default: + return_ACPI_STATUS (AE_AML_BAD_OPCODE); + } + + if (ACPI_SUCCESS (status)) { + /* + * Return the object in the walk_state, unless the parent is a package -- + * in this case, the return object will be stored in the parse tree + * for the package. + */ + if ((!op->common.parent) || + ((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_NAME_OP))) { + walk_state->result_obj = obj_desc; + } + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_exec_begin_control_op + * + * PARAMETERS: walk_list - The list that owns the walk stack + * Op - The control Op + * + * RETURN: Status + * + * DESCRIPTION: Handles all control ops encountered during control method + * execution. + * + ******************************************************************************/ + +acpi_status +acpi_ds_exec_begin_control_op ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + acpi_status status = AE_OK; + union acpi_generic_state *control_state; + + + ACPI_FUNCTION_NAME ("ds_exec_begin_control_op"); + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", op, + op->common.aml_opcode, walk_state)); + + switch (op->common.aml_opcode) { + case AML_IF_OP: + case AML_WHILE_OP: + + /* + * IF/WHILE: Create a new control state to manage these + * constructs. We need to manage these as a stack, in order + * to handle nesting. + */ + control_state = acpi_ut_create_control_state (); + if (!control_state) { + status = AE_NO_MEMORY; + break; + } + /* + * Save a pointer to the predicate for multiple executions + * of a loop + */ + control_state->control.aml_predicate_start = walk_state->parser_state.aml - 1; + control_state->control.package_end = walk_state->parser_state.pkg_end; + control_state->control.opcode = op->common.aml_opcode; + + + /* Push the control state on this walk's control stack */ + + acpi_ut_push_generic_state (&walk_state->control_state, control_state); + break; + + case AML_ELSE_OP: + + /* Predicate is in the state object */ + /* If predicate is true, the IF was executed, ignore ELSE part */ + + if (walk_state->last_predicate) { + status = AE_CTRL_TRUE; + } + + break; + + case AML_RETURN_OP: + + break; + + default: + break; + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_exec_end_control_op + * + * PARAMETERS: walk_list - The list that owns the walk stack + * Op - The control Op + * + * RETURN: Status + * + * DESCRIPTION: Handles all control ops encountered during control method + * execution. + * + ******************************************************************************/ + +acpi_status +acpi_ds_exec_end_control_op ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + acpi_status status = AE_OK; + union acpi_generic_state *control_state; + + + ACPI_FUNCTION_NAME ("ds_exec_end_control_op"); + + + switch (op->common.aml_opcode) { + case AML_IF_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op)); + + /* + * Save the result of the predicate in case there is an + * ELSE to come + */ + walk_state->last_predicate = + (u8) walk_state->control_state->common.value; + + /* + * Pop the control state that was created at the start + * of the IF and free it + */ + control_state = acpi_ut_pop_generic_state (&walk_state->control_state); + acpi_ut_delete_generic_state (control_state); + break; + + + case AML_ELSE_OP: + + break; + + + case AML_WHILE_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); + + if (walk_state->control_state->common.value) { + /* Predicate was true, go back and evaluate it again! */ + + status = AE_CTRL_PENDING; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] termination! Op=%p\n", op)); + + /* Pop this control state and free it */ + + control_state = acpi_ut_pop_generic_state (&walk_state->control_state); + + walk_state->aml_last_while = control_state->control.aml_predicate_start; + acpi_ut_delete_generic_state (control_state); + break; + + + case AML_RETURN_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "[RETURN_OP] Op=%p Arg=%p\n",op, op->common.value.arg)); + + /* + * One optional operand -- the return value + * It can be either an immediate operand or a result that + * has been bubbled up the tree + */ + if (op->common.value.arg) { + /* Since we have a real Return(), delete any implicit return */ + + acpi_ds_clear_implicit_return (walk_state); + + /* Return statement has an immediate operand */ + + status = acpi_ds_create_operands (walk_state, op->common.value.arg); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* + * If value being returned is a Reference (such as + * an arg or local), resolve it now because it may + * cease to exist at the end of the method. + */ + status = acpi_ex_resolve_to_value (&walk_state->operands [0], walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* + * Get the return value and save as the last result + * value. This is the only place where walk_state->return_desc + * is set to anything other than zero! + */ + walk_state->return_desc = walk_state->operands[0]; + } + else if ((walk_state->results) && + (walk_state->results->results.num_results > 0)) { + /* Since we have a real Return(), delete any implicit return */ + + acpi_ds_clear_implicit_return (walk_state); + + /* + * The return value has come from a previous calculation. + * + * If value being returned is a Reference (such as + * an arg or local), resolve it now because it may + * cease to exist at the end of the method. + * + * Allow references created by the Index operator to return unchanged. + */ + if ((ACPI_GET_DESCRIPTOR_TYPE (walk_state->results->results.obj_desc[0]) == ACPI_DESC_TYPE_OPERAND) && + (ACPI_GET_OBJECT_TYPE (walk_state->results->results.obj_desc [0]) == ACPI_TYPE_LOCAL_REFERENCE) && + ((walk_state->results->results.obj_desc [0])->reference.opcode != AML_INDEX_OP)) { + status = acpi_ex_resolve_to_value (&walk_state->results->results.obj_desc [0], walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } + } + + walk_state->return_desc = walk_state->results->results.obj_desc [0]; + } + else { + /* No return operand */ + + if (walk_state->num_operands) { + acpi_ut_remove_reference (walk_state->operands [0]); + } + + walk_state->operands [0] = NULL; + walk_state->num_operands = 0; + walk_state->return_desc = NULL; + } + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Completed RETURN_OP State=%p, ret_val=%p\n", + walk_state, walk_state->return_desc)); + + /* End the control method execution right now */ + + status = AE_CTRL_TERMINATE; + break; + + + case AML_NOOP_OP: + + /* Just do nothing! */ + break; + + + case AML_BREAK_POINT_OP: + + /* Call up to the OS service layer to handle this */ + + status = acpi_os_signal (ACPI_SIGNAL_BREAKPOINT, "Executed AML Breakpoint opcode"); + + /* If and when it returns, all done. */ + + break; + + + case AML_BREAK_OP: + case AML_CONTINUE_OP: /* ACPI 2.0 */ + + + /* Pop and delete control states until we find a while */ + + while (walk_state->control_state && + (walk_state->control_state->control.opcode != AML_WHILE_OP)) { + control_state = acpi_ut_pop_generic_state (&walk_state->control_state); + acpi_ut_delete_generic_state (control_state); + } + + /* No while found? */ + + if (!walk_state->control_state) { + return (AE_AML_NO_WHILE); + } + + /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */ + + walk_state->aml_last_while = walk_state->control_state->control.package_end; + + /* Return status depending on opcode */ + + if (op->common.aml_opcode == AML_BREAK_OP) { + status = AE_CTRL_BREAK; + } + else { + status = AE_CTRL_CONTINUE; + } + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown control opcode=%X Op=%p\n", + op->common.aml_opcode, op)); + + status = AE_AML_BAD_OPCODE; + break; + } + + return (status); +} + diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c new file mode 100644 index 00000000000..462c5d83e74 --- /dev/null +++ b/drivers/acpi/dispatcher/dsutils.c @@ -0,0 +1,744 @@ +/******************************************************************************* + * + * Module Name: dsutils - Dispatcher utilities + * + ******************************************************************************/ + +/* + * 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acparser.h> +#include <acpi/amlcode.h> +#include <acpi/acdispat.h> +#include <acpi/acinterp.h> +#include <acpi/acnamesp.h> +#include <acpi/acdebug.h> + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dsutils") + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_clear_implicit_return + * + * PARAMETERS: walk_state - Current State + * + * RETURN: None. + * + * DESCRIPTION: Clear and remove a reference on an implicit return value. Used + * to delete "stale" return values (if enabled, the return value + * from every operator is saved at least momentarily, in case the + * parent method exits.) + * + ******************************************************************************/ + +void +acpi_ds_clear_implicit_return ( + struct acpi_walk_state *walk_state) +{ + ACPI_FUNCTION_NAME ("ds_clear_implicit_return"); + + + /* + * Slack must be enabled for this feature + */ + if (!acpi_gbl_enable_interpreter_slack) { + return; + } + + if (walk_state->implicit_return_obj) { + /* + * Delete any "stale" implicit return. However, in + * complex statements, the implicit return value can be + * bubbled up several levels. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Removing reference on stale implicit return obj %p\n", + walk_state->implicit_return_obj)); + + acpi_ut_remove_reference (walk_state->implicit_return_obj); + walk_state->implicit_return_obj = NULL; + } +} + + +#ifndef ACPI_NO_METHOD_EXECUTION + +/******************************************************************************* + * + * FUNCTION: acpi_ds_do_implicit_return + * + * PARAMETERS: return_desc - The return value + * walk_state - Current State + * add_reference - True if a reference should be added to the + * return object + * + * RETURN: TRUE if implicit return enabled, FALSE otherwise + * + * DESCRIPTION: Implements the optional "implicit return". We save the result + * of every ASL operator and control method invocation in case the + * parent method exit. Before storing a new return value, we + * delete the previous return value. + * + ******************************************************************************/ + +u8 +acpi_ds_do_implicit_return ( + union acpi_operand_object *return_desc, + struct acpi_walk_state *walk_state, + u8 add_reference) +{ + ACPI_FUNCTION_NAME ("ds_do_implicit_return"); + + + /* + * Slack must be enabled for this feature, and we must + * have a valid return object + */ + if ((!acpi_gbl_enable_interpreter_slack) || + (!return_desc)) { + return (FALSE); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Result %p will be implicitly returned; Prev=%p\n", + return_desc, + walk_state->implicit_return_obj)); + + /* + * Delete any "stale" implicit return value first. However, in + * complex statements, the implicit return value can be + * bubbled up several levels, so we don't clear the value if it + * is the same as the return_desc. + */ + if (walk_state->implicit_return_obj) { + if (walk_state->implicit_return_obj == return_desc) { + return (TRUE); + } + acpi_ds_clear_implicit_return (walk_state); + } + + /* Save the implicit return value, add a reference if requested */ + + walk_state->implicit_return_obj = return_desc; + if (add_reference) { + acpi_ut_add_reference (return_desc); + } + + return (TRUE); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_is_result_used + * + * PARAMETERS: Op - Current Op + * walk_state - Current State + * + * RETURN: TRUE if result is used, FALSE otherwise + * + * DESCRIPTION: Check if a result object will be used by the parent + * + ******************************************************************************/ + +u8 +acpi_ds_is_result_used ( + union acpi_parse_object *op, + struct acpi_walk_state *walk_state) +{ + const struct acpi_opcode_info *parent_info; + + ACPI_FUNCTION_TRACE_PTR ("ds_is_result_used", op); + + + /* Must have both an Op and a Result Object */ + + if (!op) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Op\n")); + return_VALUE (TRUE); + } + + /* + * We know that this operator is not a + * Return() operator (would not come here.) The following code is the + * optional support for a so-called "implicit return". Some AML code + * assumes that the last value of the method is "implicitly" returned + * to the caller. Just save the last result as the return value. + * NOTE: this is optional because the ASL language does not actually + * support this behavior. + */ + acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE); + + /* + * Now determine if the parent will use the result + * + * If there is no parent, or the parent is a scope_op, we are executing + * at the method level. An executing method typically has no parent, + * since each method is parsed separately. A method invoked externally + * via execute_control_method has a scope_op as the parent. + */ + if ((!op->common.parent) || + (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) { + /* No parent, the return value cannot possibly be used */ + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "At Method level, result of [%s] not used\n", + acpi_ps_get_opcode_name (op->common.aml_opcode))); + return_VALUE (FALSE); + } + + /* Get info on the parent. The root_op is AML_SCOPE */ + + parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode); + if (parent_info->class == AML_CLASS_UNKNOWN) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown parent opcode. Op=%p\n", op)); + return_VALUE (FALSE); + } + + /* + * Decide what to do with the result based on the parent. If + * the parent opcode will not use the result, delete the object. + * Otherwise leave it as is, it will be deleted when it is used + * as an operand later. + */ + switch (parent_info->class) { + case AML_CLASS_CONTROL: + + switch (op->common.parent->common.aml_opcode) { + case AML_RETURN_OP: + + /* Never delete the return value associated with a return opcode */ + + goto result_used; + + case AML_IF_OP: + case AML_WHILE_OP: + + /* + * If we are executing the predicate AND this is the predicate op, + * we will use the return value + */ + if ((walk_state->control_state->common.state == ACPI_CONTROL_PREDICATE_EXECUTING) && + (walk_state->control_state->control.predicate_op == op)) { + goto result_used; + } + break; + + default: + /* Ignore other control opcodes */ + break; + } + + /* The general control opcode returns no result */ + + goto result_not_used; + + + case AML_CLASS_CREATE: + + /* + * These opcodes allow term_arg(s) as operands and therefore + * the operands can be method calls. The result is used. + */ + goto result_used; + + + case AML_CLASS_NAMED_OBJECT: + + 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_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_BUFFER_OP) || + (op->common.parent->common.aml_opcode == AML_INT_EVAL_SUBTREE_OP)) { + /* + * These opcodes allow term_arg(s) as operands and therefore + * the operands can be method calls. The result is used. + */ + goto result_used; + } + + goto result_not_used; + + + default: + + /* + * In all other cases. the parent will actually use the return + * object, so keep it. + */ + goto result_used; + } + + +result_used: + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] used by Parent [%s] Op=%p\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), + acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); + + return_VALUE (TRUE); + + +result_not_used: + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] not used by Parent [%s] Op=%p\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), + acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op)); + + return_VALUE (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_delete_result_if_not_used + * + * PARAMETERS: Op - Current parse Op + * result_obj - Result of the operation + * walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Used after interpretation of an opcode. If there is an internal + * result descriptor, check if the parent opcode will actually use + * this result. If not, delete the result now so that it will + * not become orphaned. + * + ******************************************************************************/ + +void +acpi_ds_delete_result_if_not_used ( + union acpi_parse_object *op, + union acpi_operand_object *result_obj, + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ds_delete_result_if_not_used", result_obj); + + + if (!op) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Op\n")); + return_VOID; + } + + if (!result_obj) { + return_VOID; + } + + if (!acpi_ds_is_result_used (op, walk_state)) { + /* Must pop the result stack (obj_desc should be equal to result_obj) */ + + status = acpi_ds_result_pop (&obj_desc, walk_state); + if (ACPI_SUCCESS (status)) { + acpi_ut_remove_reference (result_obj); + } + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_resolve_operands + * + * PARAMETERS: walk_state - Current walk state with operands on stack + * + * RETURN: Status + * + * DESCRIPTION: Resolve all operands to their values. Used to prepare + * arguments to a control method invocation (a call from one + * method to another.) + * + ******************************************************************************/ + +acpi_status +acpi_ds_resolve_operands ( + struct acpi_walk_state *walk_state) +{ + u32 i; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR ("ds_resolve_operands", walk_state); + + + /* + * Attempt to resolve each of the valid operands + * Method arguments are passed by reference, not by value. This means + * that the actual objects are passed, not copies of the objects. + */ + for (i = 0; i < walk_state->num_operands; i++) { + status = acpi_ex_resolve_to_value (&walk_state->operands[i], walk_state); + if (ACPI_FAILURE (status)) { + break; + } + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_clear_operands + * + * PARAMETERS: walk_state - Current walk state with operands on stack + * + * RETURN: None + * + * DESCRIPTION: Clear all operands on the current walk state operand stack. + * + ******************************************************************************/ + +void +acpi_ds_clear_operands ( + struct acpi_walk_state *walk_state) +{ + u32 i; + + + ACPI_FUNCTION_TRACE_PTR ("ds_clear_operands", walk_state); + + + /* Remove a reference on each operand on the stack */ + + for (i = 0; i < walk_state->num_operands; i++) { + /* + * Remove a reference to all operands, including both + * "Arguments" and "Targets". + */ + acpi_ut_remove_reference (walk_state->operands[i]); + walk_state->operands[i] = NULL; + } + + walk_state->num_operands = 0; + return_VOID; +} +#endif + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_create_operand + * + * PARAMETERS: walk_state - Current walk state + * Arg - Parse object for the argument + * arg_index - Which argument (zero based) + * + * RETURN: Status + * + * DESCRIPTION: Translate a parse tree object that is an argument to an AML + * opcode to the equivalent interpreter object. This may include + * looking up a name or entering a new name into the internal + * namespace. + * + ******************************************************************************/ + +acpi_status +acpi_ds_create_operand ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *arg, + u32 arg_index) +{ + acpi_status status = AE_OK; + char *name_string; + u32 name_length; + union acpi_operand_object *obj_desc; + union acpi_parse_object *parent_op; + u16 opcode; + acpi_interpreter_mode interpreter_mode; + const struct acpi_opcode_info *op_info; + + + ACPI_FUNCTION_TRACE_PTR ("ds_create_operand", arg); + + + /* A valid name must be looked up in the namespace */ + + if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) && + (arg->common.value.string)) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", arg)); + + /* Get the entire name string from the AML stream */ + + status = acpi_ex_get_name_string (ACPI_TYPE_ANY, arg->common.value.buffer, + &name_string, &name_length); + + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* All prefixes have been handled, and the name is in name_string */ + + /* + * Special handling for buffer_field declarations. This is a deferred + * opcode that unfortunately defines the field name as the last + * parameter instead of the first. We get here when we are performing + * the deferred execution, so the actual name of the field is already + * in the namespace. We don't want to attempt to look it up again + * because we may be executing in a different scope than where the + * actual opcode exists. + */ + if ((walk_state->deferred_node) && + (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) && + (arg_index != 0)) { + obj_desc = ACPI_CAST_PTR (union acpi_operand_object, walk_state->deferred_node); + status = AE_OK; + } + else /* All other opcodes */ { + /* + * Differentiate between a namespace "create" operation + * versus a "lookup" operation (IMODE_LOAD_PASS2 vs. + * IMODE_EXECUTE) in order to support the creation of + * namespace objects during the execution of control methods. + */ + parent_op = arg->common.parent; + op_info = acpi_ps_get_opcode_info (parent_op->common.aml_opcode); + if ((op_info->flags & AML_NSNODE) && + (parent_op->common.aml_opcode != AML_INT_METHODCALL_OP) && + (parent_op->common.aml_opcode != AML_REGION_OP) && + (parent_op->common.aml_opcode != AML_INT_NAMEPATH_OP)) { + /* Enter name into namespace if not found */ + + interpreter_mode = ACPI_IMODE_LOAD_PASS2; + } + else { + /* Return a failure if name not found */ + + interpreter_mode = ACPI_IMODE_EXECUTE; + } + + status = acpi_ns_lookup (walk_state->scope_info, name_string, + ACPI_TYPE_ANY, interpreter_mode, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + walk_state, + ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &obj_desc)); + /* + * The only case where we pass through (ignore) a NOT_FOUND + * error is for the cond_ref_of opcode. + */ + if (status == AE_NOT_FOUND) { + if (parent_op->common.aml_opcode == AML_COND_REF_OF_OP) { + /* + * For the Conditional Reference op, it's OK if + * the name is not found; We just need a way to + * indicate this to the interpreter, set the + * object to the root + */ + obj_desc = ACPI_CAST_PTR (union acpi_operand_object, acpi_gbl_root_node); + status = AE_OK; + } + else { + /* + * We just plain didn't find it -- which is a + * very serious error at this point + */ + status = AE_AML_NAME_NOT_FOUND; + } + } + + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (name_string, status); + } + } + + /* Free the namestring created above */ + + ACPI_MEM_FREE (name_string); + + /* Check status from the lookup */ + + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Put the resulting object onto the current object stack */ + + status = acpi_ds_obj_stack_push (obj_desc, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); + } + else { + /* Check for null name case */ + + if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) { + /* + * If the name is null, this means that this is an + * optional result parameter that was not specified + * in the original ASL. Create a Zero Constant for a + * placeholder. (Store to a constant is a Noop.) + */ + opcode = AML_ZERO_OP; /* Has no arguments! */ + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Null namepath: Arg=%p\n", arg)); + } + else { + opcode = arg->common.aml_opcode; + } + + /* Get the object type of the argument */ + + op_info = acpi_ps_get_opcode_info (opcode); + if (op_info->object_type == ACPI_TYPE_INVALID) { + return_ACPI_STATUS (AE_NOT_IMPLEMENTED); + } + + if (op_info->flags & AML_HAS_RETVAL) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Argument previously created, already stacked \n")); + + ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object ( + walk_state->operands [walk_state->num_operands - 1], walk_state)); + + /* + * Use value that was already previously returned + * by the evaluation of this argument + */ + status = acpi_ds_result_pop_from_bottom (&obj_desc, walk_state); + if (ACPI_FAILURE (status)) { + /* + * Only error is underflow, and this indicates + * a missing or null operand! + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Missing or null operand, %s\n", + acpi_format_exception (status))); + return_ACPI_STATUS (status); + } + } + else { + /* Create an ACPI_INTERNAL_OBJECT for the argument */ + + obj_desc = acpi_ut_create_internal_object (op_info->object_type); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize the new object */ + + status = acpi_ds_init_object_from_op (walk_state, arg, + opcode, &obj_desc); + if (ACPI_FAILURE (status)) { + acpi_ut_delete_object_desc (obj_desc); + return_ACPI_STATUS (status); + } + } + + /* Put the operand object on the object stack */ + + status = acpi_ds_obj_stack_push (obj_desc, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state)); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_create_operands + * + * PARAMETERS: walk_state - Current state + * first_arg - First argument of a parser argument tree + * + * RETURN: Status + * + * DESCRIPTION: Convert an operator's arguments from a parse tree format to + * namespace objects and place those argument object on the object + * stack in preparation for evaluation by the interpreter. + * + ******************************************************************************/ + +acpi_status +acpi_ds_create_operands ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *first_arg) +{ + acpi_status status = AE_OK; + union acpi_parse_object *arg; + u32 arg_count = 0; + + + ACPI_FUNCTION_TRACE_PTR ("ds_create_operands", first_arg); + + + /* For all arguments in the list... */ + + arg = first_arg; + while (arg) { + status = acpi_ds_create_operand (walk_state, arg, arg_count); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Arg #%d (%p) done, Arg1=%p\n", + arg_count, arg, first_arg)); + + /* Move on to next argument, if any */ + + arg = arg->common.next; + arg_count++; + } + + return_ACPI_STATUS (status); + + +cleanup: + /* + * We must undo everything done above; meaning that we must + * pop everything off of the operand stack and delete those + * objects + */ + (void) acpi_ds_obj_stack_pop_and_delete (arg_count, walk_state); + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While creating Arg %d - %s\n", + (arg_count + 1), acpi_format_exception (status))); + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c new file mode 100644 index 00000000000..2071a0d2bbb --- /dev/null +++ b/drivers/acpi/dispatcher/dswexec.c @@ -0,0 +1,751 @@ +/****************************************************************************** + * + * Module Name: dswexec - Dispatcher method execution callbacks; + * dispatch to interpreter. + * + *****************************************************************************/ + +/* + * 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acparser.h> +#include <acpi/amlcode.h> +#include <acpi/acdispat.h> +#include <acpi/acinterp.h> +#include <acpi/acnamesp.h> +#include <acpi/acdebug.h> +#include <acpi/acdisasm.h> + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dswexec") + +/* + * Dispatch table for opcode classes + */ +static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch [] = { + acpi_ex_opcode_0A_0T_1R, + acpi_ex_opcode_1A_0T_0R, + acpi_ex_opcode_1A_0T_1R, + acpi_ex_opcode_1A_1T_0R, + acpi_ex_opcode_1A_1T_1R, + acpi_ex_opcode_2A_0T_0R, + acpi_ex_opcode_2A_0T_1R, + acpi_ex_opcode_2A_1T_1R, + acpi_ex_opcode_2A_2T_1R, + acpi_ex_opcode_3A_0T_0R, + acpi_ex_opcode_3A_1T_1R, + acpi_ex_opcode_6A_0T_1R}; + +/***************************************************************************** + * + * FUNCTION: acpi_ds_get_predicate_value + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * + * RETURN: Status + * + * DESCRIPTION: Get the result of a predicate evaluation + * + ****************************************************************************/ + +acpi_status +acpi_ds_get_predicate_value ( + struct acpi_walk_state *walk_state, + union acpi_operand_object *result_obj) { + acpi_status status = AE_OK; + union acpi_operand_object *obj_desc; + union acpi_operand_object *local_obj_desc = NULL; + + + ACPI_FUNCTION_TRACE_PTR ("ds_get_predicate_value", walk_state); + + + walk_state->control_state->common.state = 0; + + if (result_obj) { + status = acpi_ds_result_pop (&obj_desc, walk_state); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not get result from predicate evaluation, %s\n", + acpi_format_exception (status))); + + return_ACPI_STATUS (status); + } + } + else { + status = acpi_ds_create_operand (walk_state, walk_state->op, 0); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ex_resolve_to_value (&walk_state->operands [0], walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + obj_desc = walk_state->operands [0]; + } + + if (!obj_desc) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No predicate obj_desc=%p State=%p\n", + obj_desc, walk_state)); + + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + /* + * Result of predicate evaluation must be an Integer + * object. Implicitly convert the argument if necessary. + */ + status = acpi_ex_convert_to_integer (obj_desc, &local_obj_desc, 16); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + if (ACPI_GET_OBJECT_TYPE (local_obj_desc) != ACPI_TYPE_INTEGER) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Bad predicate (not an integer) obj_desc=%p State=%p Type=%X\n", + obj_desc, walk_state, ACPI_GET_OBJECT_TYPE (obj_desc))); + + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + + /* Truncate the predicate to 32-bits if necessary */ + + acpi_ex_truncate_for32bit_table (local_obj_desc); + + /* + * Save the result of the predicate evaluation on + * the control stack + */ + if (local_obj_desc->integer.value) { + walk_state->control_state->common.value = TRUE; + } + else { + /* + * Predicate is FALSE, we will just toss the + * rest of the package + */ + walk_state->control_state->common.value = FALSE; + status = AE_CTRL_FALSE; + } + + +cleanup: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n", + walk_state->control_state->common.value, walk_state->op)); + + /* Break to debugger to display result */ + + ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (local_obj_desc, walk_state)); + + /* + * Delete the predicate result object (we know that + * we don't need it anymore) + */ + if (local_obj_desc != obj_desc) { + acpi_ut_remove_reference (local_obj_desc); + } + acpi_ut_remove_reference (obj_desc); + + walk_state->control_state->common.state = ACPI_CONTROL_NORMAL; + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_exec_begin_op + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * out_op - Return op if a new one is created + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the execution of control + * methods. This is where most operators and operands are + * dispatched to the interpreter. + * + ****************************************************************************/ + +acpi_status +acpi_ds_exec_begin_op ( + struct acpi_walk_state *walk_state, + union acpi_parse_object **out_op) +{ + union acpi_parse_object *op; + acpi_status status = AE_OK; + u32 opcode_class; + + + ACPI_FUNCTION_TRACE_PTR ("ds_exec_begin_op", walk_state); + + + op = walk_state->op; + if (!op) { + status = acpi_ds_load2_begin_op (walk_state, out_op); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + op = *out_op; + walk_state->op = op; + walk_state->opcode = op->common.aml_opcode; + walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode); + + if (acpi_ns_opens_scope (walk_state->op_info->object_type)) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", + acpi_ut_get_type_name (walk_state->op_info->object_type), op)); + + status = acpi_ds_scope_stack_pop (walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + } + + if (op == walk_state->origin) { + if (out_op) { + *out_op = op; + } + + return_ACPI_STATUS (AE_OK); + } + + /* + * If the previous opcode was a conditional, this opcode + * must be the beginning of the associated predicate. + * Save this knowledge in the current scope descriptor + */ + if ((walk_state->control_state) && + (walk_state->control_state->common.state == + ACPI_CONTROL_CONDITIONAL_EXECUTING)) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Exec predicate Op=%p State=%p\n", + op, walk_state)); + + walk_state->control_state->common.state = ACPI_CONTROL_PREDICATE_EXECUTING; + + /* Save start of predicate */ + + walk_state->control_state->control.predicate_op = op; + } + + + opcode_class = walk_state->op_info->class; + + /* We want to send namepaths to the load code */ + + if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) { + opcode_class = AML_CLASS_NAMED_OBJECT; + } + + /* + * Handle the opcode based upon the opcode type + */ + switch (opcode_class) { + case AML_CLASS_CONTROL: + + status = acpi_ds_result_stack_push (walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ds_exec_begin_control_op (walk_state, op); + break; + + + case AML_CLASS_NAMED_OBJECT: + + if (walk_state->walk_type == ACPI_WALK_METHOD) { + /* + * Found a named object declaration during method + * execution; we must enter this object into the + * namespace. The created object is temporary and + * will be deleted upon completion of the execution + * of this method. + */ + status = acpi_ds_load2_begin_op (walk_state, NULL); + } + + if (op->common.aml_opcode == AML_REGION_OP) { + status = acpi_ds_result_stack_push (walk_state); + } + break; + + + case AML_CLASS_EXECUTE: + case AML_CLASS_CREATE: + + /* + * Most operators with arguments. + * Start a new result/operand state + */ + status = acpi_ds_result_stack_push (walk_state); + break; + + + default: + break; + } + + /* Nothing to do here during method execution */ + + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ds_exec_end_op + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * Op - Op that has been just been completed in the + * walk; Arguments have now been evaluated. + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback used during the execution of control + * methods. The only thing we really need to do here is to + * notice the beginning of IF, ELSE, and WHILE blocks. + * + ****************************************************************************/ + +acpi_status +acpi_ds_exec_end_op ( + struct acpi_walk_state *walk_state) +{ + union acpi_parse_object *op; + acpi_status status = AE_OK; + u32 op_type; + u32 op_class; + union acpi_parse_object *next_op; + union acpi_parse_object *first_arg; + + + ACPI_FUNCTION_TRACE_PTR ("ds_exec_end_op", walk_state); + + + op = walk_state->op; + op_type = walk_state->op_info->type; + op_class = walk_state->op_info->class; + + if (op_class == AML_CLASS_UNKNOWN) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown opcode %X\n", op->common.aml_opcode)); + return_ACPI_STATUS (AE_NOT_IMPLEMENTED); + } + + first_arg = op->common.value.arg; + + /* Init the walk state */ + + walk_state->num_operands = 0; + walk_state->return_desc = NULL; + walk_state->result_obj = NULL; + + /* Call debugger for single step support (DEBUG build only) */ + + ACPI_DEBUGGER_EXEC (status = acpi_db_single_step (walk_state, op, op_class)); + ACPI_DEBUGGER_EXEC (if (ACPI_FAILURE (status)) {return_ACPI_STATUS (status);}); + + /* Decode the Opcode Class */ + + switch (op_class) { + case AML_CLASS_ARGUMENT: /* constants, literals, etc. -- do nothing */ + break; + + + case AML_CLASS_EXECUTE: /* most operators with arguments */ + + /* Build resolved operand stack */ + + status = acpi_ds_create_operands (walk_state, first_arg); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Done with this result state (Now that operand stack is built) */ + + status = acpi_ds_result_stack_pop (walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* + * All opcodes require operand resolution, with the only exceptions + * being the object_type and size_of operators. + */ + if (!(walk_state->op_info->flags & AML_NO_OPERAND_RESOLVE)) { + /* Resolve all operands */ + + status = acpi_ex_resolve_operands (walk_state->opcode, + &(walk_state->operands [walk_state->num_operands -1]), + walk_state); + if (ACPI_SUCCESS (status)) { + ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE, + acpi_ps_get_opcode_name (walk_state->opcode), + walk_state->num_operands, "after ex_resolve_operands"); + } + } + + if (ACPI_SUCCESS (status)) { + /* + * Dispatch the request to the appropriate interpreter handler + * routine. There is one routine per opcode "type" based upon the + * number of opcode arguments and return type. + */ + status = acpi_gbl_op_type_dispatch[op_type] (walk_state); + } + else { + /* + * Treat constructs of the form "Store(local_x,local_x)" as noops when the + * Local is uninitialized. + */ + if ((status == AE_AML_UNINITIALIZED_LOCAL) && + (walk_state->opcode == AML_STORE_OP) && + (walk_state->operands[0]->common.type == ACPI_TYPE_LOCAL_REFERENCE) && + (walk_state->operands[1]->common.type == ACPI_TYPE_LOCAL_REFERENCE) && + (walk_state->operands[0]->reference.opcode == + walk_state->operands[1]->reference.opcode) && + (walk_state->operands[0]->reference.offset == + walk_state->operands[1]->reference.offset)) { + status = AE_OK; + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "[%s]: Could not resolve operands, %s\n", + acpi_ps_get_opcode_name (walk_state->opcode), + acpi_format_exception (status))); + } + } + + /* Always delete the argument objects and clear the operand stack */ + + acpi_ds_clear_operands (walk_state); + + /* + * If a result object was returned from above, push it on the + * current result stack + */ + if (ACPI_SUCCESS (status) && + walk_state->result_obj) { + status = acpi_ds_result_push (walk_state->result_obj, walk_state); + } + + break; + + + default: + + switch (op_type) { + case AML_TYPE_CONTROL: /* Type 1 opcode, IF/ELSE/WHILE/NOOP */ + + /* 1 Operand, 0 external_result, 0 internal_result */ + + status = acpi_ds_exec_end_control_op (walk_state, op); + + /* Make sure to properly pop the result stack */ + + if (ACPI_SUCCESS (status)) { + status = acpi_ds_result_stack_pop (walk_state); + } + else if (status == AE_CTRL_PENDING) { + status = acpi_ds_result_stack_pop (walk_state); + if (ACPI_SUCCESS (status)) { + status = AE_CTRL_PENDING; + } + } + break; + + + case AML_TYPE_METHOD_CALL: + + /* + * If the method is referenced from within a package + * declaration, it is not a invocation of the method, just + * a reference to it. + */ + if ((op->asl.parent) && + ((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) || + (op->asl.parent->asl.aml_opcode == AML_VAR_PACKAGE_OP))) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method Reference in a Package, Op=%p\n", op)); + op->common.node = (struct acpi_namespace_node *) op->asl.value.arg->asl.node->object; + acpi_ut_add_reference (op->asl.value.arg->asl.node->object); + return_ACPI_STATUS (AE_OK); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method invocation, Op=%p\n", op)); + + /* + * (AML_METHODCALL) Op->Asl.Value.Arg->Asl.Node contains + * the method Node pointer + */ + /* next_op points to the op that holds the method name */ + + next_op = first_arg; + + /* next_op points to first argument op */ + + next_op = next_op->common.next; + + /* + * Get the method's arguments and put them on the operand stack + */ + status = acpi_ds_create_operands (walk_state, next_op); + if (ACPI_FAILURE (status)) { + break; + } + + /* + * Since the operands will be passed to another control method, + * we must resolve all local references here (Local variables, + * arguments to *this* method, etc.) + */ + status = acpi_ds_resolve_operands (walk_state); + if (ACPI_FAILURE (status)) { + /* On error, clear all resolved operands */ + + acpi_ds_clear_operands (walk_state); + break; + } + + /* + * Tell the walk loop to preempt this running method and + * execute the new method + */ + status = AE_CTRL_TRANSFER; + + /* + * Return now; we don't want to disturb anything, + * especially the operand count! + */ + return_ACPI_STATUS (status); + + + case AML_TYPE_CREATE_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Executing create_field Buffer/Index Op=%p\n", op)); + + status = acpi_ds_load2_end_op (walk_state); + if (ACPI_FAILURE (status)) { + break; + } + + status = acpi_ds_eval_buffer_field_operands (walk_state, op); + break; + + + case AML_TYPE_CREATE_OBJECT: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Executing create_object (Buffer/Package) Op=%p\n", op)); + + switch (op->common.parent->common.aml_opcode) { + case AML_NAME_OP: + + /* + * Put the Node on the object stack (Contains the ACPI Name of + * this object) + */ + walk_state->operands[0] = (void *) op->common.parent->common.node; + walk_state->num_operands = 1; + + status = acpi_ds_create_node (walk_state, op->common.parent->common.node, op->common.parent); + if (ACPI_FAILURE (status)) { + break; + } + + /* Fall through */ + /*lint -fallthrough */ + + case AML_INT_EVAL_SUBTREE_OP: + + status = acpi_ds_eval_data_object_operands (walk_state, op, + acpi_ns_get_attached_object (op->common.parent->common.node)); + break; + + default: + + status = acpi_ds_eval_data_object_operands (walk_state, op, NULL); + break; + } + + /* Done with this result state (Now that operand stack is built) */ + + status = acpi_ds_result_stack_pop (walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* + * If a result object was returned from above, push it on the + * current result stack + */ + if (ACPI_SUCCESS (status) && + walk_state->result_obj) { + status = acpi_ds_result_push (walk_state->result_obj, walk_state); + } + break; + + + case AML_TYPE_NAMED_FIELD: + case AML_TYPE_NAMED_COMPLEX: + case AML_TYPE_NAMED_SIMPLE: + case AML_TYPE_NAMED_NO_OBJ: + + status = acpi_ds_load2_end_op (walk_state); + if (ACPI_FAILURE (status)) { + break; + } + + if (op->common.aml_opcode == AML_REGION_OP) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Executing op_region Address/Length Op=%p\n", op)); + + status = acpi_ds_eval_region_operands (walk_state, op); + if (ACPI_FAILURE (status)) { + break; + } + + status = acpi_ds_result_stack_pop (walk_state); + } + + break; + + + case AML_TYPE_UNDEFINED: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Undefined opcode type Op=%p\n", op)); + return_ACPI_STATUS (AE_NOT_IMPLEMENTED); + + + case AML_TYPE_BOGUS: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Internal opcode=%X type Op=%p\n", + walk_state->opcode, op)); + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unimplemented opcode, class=%X type=%X Opcode=%X Op=%p\n", + op_class, op_type, op->common.aml_opcode, op)); + + status = AE_NOT_IMPLEMENTED; + break; + } + } + + /* + * ACPI 2.0 support for 64-bit integers: Truncate numeric + * result value if we are executing from a 32-bit ACPI table + */ + acpi_ex_truncate_for32bit_table (walk_state->result_obj); + + /* + * Check if we just completed the evaluation of a + * conditional predicate + */ + + if ((ACPI_SUCCESS (status)) && + (walk_state->control_state) && + (walk_state->control_state->common.state == + ACPI_CONTROL_PREDICATE_EXECUTING) && + (walk_state->control_state->control.predicate_op == op)) { + status = acpi_ds_get_predicate_value (walk_state, walk_state->result_obj); + walk_state->result_obj = NULL; + } + + +cleanup: + + /* Invoke exception handler on error */ + + if (ACPI_FAILURE (status) && + acpi_gbl_exception_handler && + !(status & AE_CODE_CONTROL)) { + acpi_ex_exit_interpreter (); + status = acpi_gbl_exception_handler (status, + walk_state->method_node->name.integer, walk_state->opcode, + walk_state->aml_offset, NULL); + acpi_ex_enter_interpreter (); + } + + if (walk_state->result_obj) { + /* Break to debugger to display result */ + + ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, walk_state)); + + /* + * Delete the result op if and only if: + * Parent will not use the result -- such as any + * non-nested type2 op in a method (parent will be method) + */ + acpi_ds_delete_result_if_not_used (op, walk_state->result_obj, walk_state); + } + +#ifdef _UNDER_DEVELOPMENT + + if (walk_state->parser_state.aml == walk_state->parser_state.aml_end) { + acpi_db_method_end (walk_state); + } +#endif + + /* Always clear the object stack */ + + walk_state->num_operands = 0; + +#ifdef ACPI_DISASSEMBLER + + /* On error, display method locals/args */ + + if (ACPI_FAILURE (status)) { + acpi_dm_dump_method_info (status, walk_state, op); + } +#endif + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c new file mode 100644 index 00000000000..06d75867958 --- /dev/null +++ b/drivers/acpi/dispatcher/dswload.c @@ -0,0 +1,976 @@ +/****************************************************************************** + * + * Module Name: dswload - Dispatcher namespace load callbacks + * + *****************************************************************************/ + +/* + * 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acparser.h> +#include <acpi/amlcode.h> +#include <acpi/acdispat.h> +#include <acpi/acinterp.h> +#include <acpi/acnamesp.h> +#include <acpi/acevents.h> + +#ifdef _ACPI_ASL_COMPILER +#include <acpi/acdisasm.h> +#endif + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dswload") + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_init_callbacks + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * pass_number - 1, 2, or 3 + * + * RETURN: Status + * + * DESCRIPTION: Init walk state callbacks + * + ******************************************************************************/ + +acpi_status +acpi_ds_init_callbacks ( + struct acpi_walk_state *walk_state, + u32 pass_number) +{ + + switch (pass_number) { + case 1: + walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; + walk_state->descending_callback = acpi_ds_load1_begin_op; + walk_state->ascending_callback = acpi_ds_load1_end_op; + break; + + case 2: + walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE; + walk_state->descending_callback = acpi_ds_load2_begin_op; + walk_state->ascending_callback = acpi_ds_load2_end_op; + break; + + case 3: +#ifndef ACPI_NO_METHOD_EXECUTION + walk_state->parse_flags |= ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE; + walk_state->descending_callback = acpi_ds_exec_begin_op; + walk_state->ascending_callback = acpi_ds_exec_end_op; +#endif + break; + + default: + return (AE_BAD_PARAMETER); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_load1_begin_op + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * Op - Op that has been just been reached in the + * walk; Arguments have not been evaluated yet. + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the loading of ACPI tables. + * + ******************************************************************************/ + +acpi_status +acpi_ds_load1_begin_op ( + struct acpi_walk_state *walk_state, + union acpi_parse_object **out_op) +{ + union acpi_parse_object *op; + struct acpi_namespace_node *node; + acpi_status status; + acpi_object_type object_type; + char *path; + u32 flags; + + + ACPI_FUNCTION_NAME ("ds_load1_begin_op"); + + + op = walk_state->op; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); + + /* We are only interested in opcodes that have an associated name */ + + if (op) { + if (!(walk_state->op_info->flags & AML_NAMED)) { +#if 0 + if ((walk_state->op_info->class == AML_CLASS_EXECUTE) || + (walk_state->op_info->class == AML_CLASS_CONTROL)) { + acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", walk_state->op_info->name); + *out_op = op; + return (AE_CTRL_SKIP); + } +#endif + *out_op = op; + return (AE_OK); + } + + /* Check if this object has already been installed in the namespace */ + + if (op->common.node) { + *out_op = op; + return (AE_OK); + } + } + + path = acpi_ps_get_next_namestring (&walk_state->parser_state); + + /* Map the raw opcode into an internal object type */ + + object_type = walk_state->op_info->object_type; + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "State=%p Op=%p [%s]\n", walk_state, op, acpi_ut_get_type_name (object_type))); + + switch (walk_state->opcode) { + case AML_SCOPE_OP: + + /* + * The target name of the Scope() operator must exist at this point so + * that we can actually open the scope to enter new names underneath it. + * Allow search-to-root for single namesegs. + */ + status = acpi_ns_lookup (walk_state->scope_info, path, object_type, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); +#ifdef _ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + /* + * Table disassembly: + * Target of Scope() not found. Generate an External for it, and + * insert the name into the namespace. + */ + acpi_dm_add_to_external_list (path); + status = acpi_ns_lookup (walk_state->scope_info, path, object_type, + ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + } +#endif + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (path, status); + return (status); + } + + /* + * Check to make sure that the target is + * one of the opcodes that actually opens a scope + */ + switch (node->type) { + case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* These are acceptable types */ + break; + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* + * These types we will allow, but we will change the type. This + * enables some existing code of the form: + * + * Name (DEB, 0) + * Scope (DEB) { ... } + * + * Note: silently change the type here. On the second pass, we will report a warning + */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", + path, acpi_ut_get_type_name (node->type))); + + node->type = ACPI_TYPE_ANY; + walk_state->scope_info->common.value = ACPI_TYPE_ANY; + break; + + default: + + /* All other types are an error */ + + ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n", + acpi_ut_get_type_name (node->type), path)); + + return (AE_AML_OPERAND_TYPE); + } + break; + + + default: + + /* + * For all other named opcodes, we will enter the name into the namespace. + * + * Setup the search flags. + * Since we are entering a name into the namespace, we do not want to + * enable the search-to-root upsearch. + * + * There are only two conditions where it is acceptable that the name + * already exists: + * 1) the Scope() operator can reopen a scoping object that was + * previously defined (Scope, Method, Device, etc.) + * 2) Whenever we are parsing a deferred opcode (op_region, Buffer, + * buffer_field, or Package), the name of the object is already + * in the namespace. + */ + if (walk_state->deferred_node) { + /* This name is already in the namespace, get the node */ + + node = walk_state->deferred_node; + status = AE_OK; + break; + } + + flags = ACPI_NS_NO_UPSEARCH; + if ((walk_state->opcode != AML_SCOPE_OP) && + (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) { + flags |= ACPI_NS_ERROR_IF_FOUND; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Cannot already exist\n", + acpi_ut_get_type_name (object_type))); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n", + acpi_ut_get_type_name (object_type))); + } + + /* + * Enter the named type into the internal namespace. We enter the name + * as we go downward in the parse tree. Any necessary subobjects that involve + * arguments to the opcode must be created as we go back up the parse tree later. + */ + status = acpi_ns_lookup (walk_state->scope_info, path, object_type, + ACPI_IMODE_LOAD_PASS1, flags, walk_state, &(node)); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (path, status); + return (status); + } + break; + } + + + /* Common exit */ + + if (!op) { + /* Create a new op */ + + op = acpi_ps_alloc_op (walk_state->opcode); + if (!op) { + return (AE_NO_MEMORY); + } + } + + /* Initialize */ + + op->named.name = node->name.integer; + +#if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)) + op->named.path = (u8 *) path; +#endif + + + /* + * Put the Node in the "op" object that the parser uses, so we + * can get it again quickly when this scope is closed + */ + op->common.node = node; + acpi_ps_append_arg (acpi_ps_get_parent_scope (&walk_state->parser_state), op); + + *out_op = op; + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_load1_end_op + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * Op - Op that has been just been completed in the + * walk; Arguments have now been evaluated. + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback used during the loading of the namespace, + * both control methods and everything else. + * + ******************************************************************************/ + +acpi_status +acpi_ds_load1_end_op ( + struct acpi_walk_state *walk_state) +{ + union acpi_parse_object *op; + acpi_object_type object_type; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_NAME ("ds_load1_end_op"); + + + op = walk_state->op; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); + + /* We are only interested in opcodes that have an associated name */ + + if (!(walk_state->op_info->flags & (AML_NAMED | AML_FIELD))) { + return (AE_OK); + } + + /* Get the object type to determine if we should pop the scope */ + + object_type = walk_state->op_info->object_type; + +#ifndef ACPI_NO_METHOD_EXECUTION + if (walk_state->op_info->flags & AML_FIELD) { + if (walk_state->opcode == AML_FIELD_OP || + walk_state->opcode == AML_BANK_FIELD_OP || + walk_state->opcode == AML_INDEX_FIELD_OP) { + status = acpi_ds_init_field_objects (op, walk_state); + } + return (status); + } + + + if (op->common.aml_opcode == AML_REGION_OP) { + status = acpi_ex_create_region (op->named.data, op->named.length, + (acpi_adr_space_type) ((op->common.value.arg)->common.value.integer), walk_state); + if (ACPI_FAILURE (status)) { + return (status); + } + } +#endif + + if (op->common.aml_opcode == AML_NAME_OP) { + /* For Name opcode, get the object type from the argument */ + + if (op->common.value.arg) { + object_type = (acpi_ps_get_opcode_info ((op->common.value.arg)->common.aml_opcode))->object_type; + op->common.node->type = (u8) object_type; + } + } + + if (op->common.aml_opcode == AML_METHOD_OP) { + /* + * method_op pkg_length name_string method_flags term_list + * + * Note: We must create the method node/object pair as soon as we + * see the method declaration. This allows later pass1 parsing + * of invocations of the method (need to know the number of + * arguments.) + */ + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "LOADING-Method: State=%p Op=%p named_obj=%p\n", + walk_state, op, op->named.node)); + + if (!acpi_ns_get_attached_object (op->named.node)) { + walk_state->operands[0] = (void *) op->named.node; + walk_state->num_operands = 1; + + status = acpi_ds_create_operands (walk_state, op->common.value.arg); + if (ACPI_SUCCESS (status)) { + status = acpi_ex_create_method (op->named.data, + op->named.length, walk_state); + } + walk_state->operands[0] = NULL; + walk_state->num_operands = 0; + + if (ACPI_FAILURE (status)) { + return (status); + } + } + } + + /* Pop the scope stack */ + + if (acpi_ns_opens_scope (object_type)) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s): Popping scope for Op %p\n", + acpi_ut_get_type_name (object_type), op)); + + status = acpi_ds_scope_stack_pop (walk_state); + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_load2_begin_op + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * Op - Op that has been just been reached in the + * walk; Arguments have not been evaluated yet. + * + * RETURN: Status + * + * DESCRIPTION: Descending callback used during the loading of ACPI tables. + * + ******************************************************************************/ + +acpi_status +acpi_ds_load2_begin_op ( + struct acpi_walk_state *walk_state, + union acpi_parse_object **out_op) +{ + union acpi_parse_object *op; + struct acpi_namespace_node *node; + acpi_status status; + acpi_object_type object_type; + char *buffer_ptr; + + + ACPI_FUNCTION_TRACE ("ds_load2_begin_op"); + + + op = walk_state->op; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state)); + + if (op) { + /* We only care about Namespace opcodes here */ + + if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) || + (!(walk_state->op_info->flags & AML_NAMED))) { + return_ACPI_STATUS (AE_OK); + } + + /* + * Get the name we are going to enter or lookup in the namespace + */ + if (walk_state->opcode == AML_INT_NAMEPATH_OP) { + /* For Namepath op, get the path string */ + + buffer_ptr = op->common.value.string; + if (!buffer_ptr) { + /* No name, just exit */ + + return_ACPI_STATUS (AE_OK); + } + } + else { + /* Get name from the op */ + + buffer_ptr = (char *) &op->named.name; + } + } + else { + /* Get the namestring from the raw AML */ + + buffer_ptr = acpi_ps_get_next_namestring (&walk_state->parser_state); + } + + /* Map the opcode into an internal object type */ + + object_type = walk_state->op_info->object_type; + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "State=%p Op=%p Type=%X\n", walk_state, op, object_type)); + + + switch (walk_state->opcode) { + case AML_FIELD_OP: + case AML_BANK_FIELD_OP: + case AML_INDEX_FIELD_OP: + + node = NULL; + status = AE_OK; + break; + + case AML_INT_NAMEPATH_OP: + + /* + * The name_path is an object reference to an existing object. Don't enter the + * name into the namespace, but look it up for use later + */ + status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + break; + + case AML_SCOPE_OP: + + /* + * The Path is an object reference to an existing object. Don't enter the + * name into the namespace, but look it up for use later + */ + status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, + ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node)); + if (ACPI_FAILURE (status)) { +#ifdef _ACPI_ASL_COMPILER + if (status == AE_NOT_FOUND) { + status = AE_OK; + } + else { + ACPI_REPORT_NSERROR (buffer_ptr, status); + } +#else + ACPI_REPORT_NSERROR (buffer_ptr, status); +#endif + return_ACPI_STATUS (status); + } + /* + * We must check to make sure that the target is + * one of the opcodes that actually opens a scope + */ + switch (node->type) { + case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ + case ACPI_TYPE_DEVICE: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* These are acceptable types */ + break; + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* + * These types we will allow, but we will change the type. This + * enables some existing code of the form: + * + * Name (DEB, 0) + * Scope (DEB) { ... } + */ + + ACPI_REPORT_WARNING (("Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", + buffer_ptr, acpi_ut_get_type_name (node->type))); + + node->type = ACPI_TYPE_ANY; + walk_state->scope_info->common.value = ACPI_TYPE_ANY; + break; + + default: + + /* All other types are an error */ + + ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n", + acpi_ut_get_type_name (node->type), buffer_ptr)); + + return (AE_AML_OPERAND_TYPE); + } + break; + + default: + + /* All other opcodes */ + + if (op && op->common.node) { + /* This op/node was previously entered into the namespace */ + + node = op->common.node; + + if (acpi_ns_opens_scope (object_type)) { + status = acpi_ds_scope_stack_push (node, object_type, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + } + return_ACPI_STATUS (AE_OK); + } + + /* + * Enter the named type into the internal namespace. We enter the name + * as we go downward in the parse tree. Any necessary subobjects that involve + * arguments to the opcode must be created as we go back up the parse tree later. + * + * Note: Name may already exist if we are executing a deferred opcode. + */ + if (walk_state->deferred_node) { + /* This name is already in the namespace, get the node */ + + node = walk_state->deferred_node; + status = AE_OK; + break; + } + + status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type, + ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node)); + break; + } + + if (ACPI_FAILURE (status)) { + ACPI_REPORT_NSERROR (buffer_ptr, status); + return_ACPI_STATUS (status); + } + + + if (!op) { + /* Create a new op */ + + op = acpi_ps_alloc_op (walk_state->opcode); + if (!op) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize the new op */ + + if (node) { + op->named.name = node->name.integer; + } + if (out_op) { + *out_op = op; + } + } + + /* + * Put the Node in the "op" object that the parser uses, so we + * can get it again quickly when this scope is closed + */ + op->common.node = node; + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_load2_end_op + * + * PARAMETERS: walk_state - Current state of the parse tree walk + * Op - Op that has been just been completed in the + * walk; Arguments have now been evaluated. + * + * RETURN: Status + * + * DESCRIPTION: Ascending callback used during the loading of the namespace, + * both control methods and everything else. + * + ******************************************************************************/ + +acpi_status +acpi_ds_load2_end_op ( + struct acpi_walk_state *walk_state) +{ + union acpi_parse_object *op; + acpi_status status = AE_OK; + acpi_object_type object_type; + struct acpi_namespace_node *node; + union acpi_parse_object *arg; + struct acpi_namespace_node *new_node; +#ifndef ACPI_NO_METHOD_EXECUTION + u32 i; +#endif + + + ACPI_FUNCTION_TRACE ("ds_load2_end_op"); + + op = walk_state->op; + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n", + walk_state->op_info->name, op, walk_state)); + + /* Only interested in opcodes that have namespace objects */ + + if (!(walk_state->op_info->flags & AML_NSOBJECT)) { + return_ACPI_STATUS (AE_OK); + } + + if (op->common.aml_opcode == AML_SCOPE_OP) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Ending scope Op=%p State=%p\n", op, walk_state)); + } + + + object_type = walk_state->op_info->object_type; + + /* + * Get the Node/name from the earlier lookup + * (It was saved in the *op structure) + */ + node = op->common.node; + + /* + * Put the Node on the object stack (Contains the ACPI Name of + * this object) + */ + walk_state->operands[0] = (void *) node; + walk_state->num_operands = 1; + + /* Pop the scope stack */ + + if (acpi_ns_opens_scope (object_type) && (op->common.aml_opcode != AML_INT_METHODCALL_OP)) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n", + acpi_ut_get_type_name (object_type), op)); + + status = acpi_ds_scope_stack_pop (walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + } + + /* + * Named operations are as follows: + * + * AML_ALIAS + * AML_BANKFIELD + * AML_CREATEBITFIELD + * AML_CREATEBYTEFIELD + * AML_CREATEDWORDFIELD + * AML_CREATEFIELD + * AML_CREATEQWORDFIELD + * AML_CREATEWORDFIELD + * AML_DATA_REGION + * AML_DEVICE + * AML_EVENT + * AML_FIELD + * AML_INDEXFIELD + * AML_METHOD + * AML_METHODCALL + * AML_MUTEX + * AML_NAME + * AML_NAMEDFIELD + * AML_OPREGION + * AML_POWERRES + * AML_PROCESSOR + * AML_SCOPE + * AML_THERMALZONE + */ + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "Create-Load [%s] State=%p Op=%p named_obj=%p\n", + acpi_ps_get_opcode_name (op->common.aml_opcode), walk_state, op, node)); + + /* Decode the opcode */ + + arg = op->common.value.arg; + + switch (walk_state->op_info->type) { +#ifndef ACPI_NO_METHOD_EXECUTION + + case AML_TYPE_CREATE_FIELD: + + /* + * Create the field object, but the field buffer and index must + * be evaluated later during the execution phase + */ + status = acpi_ds_create_buffer_field (op, walk_state); + break; + + + case AML_TYPE_NAMED_FIELD: + + switch (op->common.aml_opcode) { + case AML_INDEX_FIELD_OP: + + status = acpi_ds_create_index_field (op, (acpi_handle) arg->common.node, + walk_state); + break; + + case AML_BANK_FIELD_OP: + + status = acpi_ds_create_bank_field (op, arg->common.node, walk_state); + break; + + case AML_FIELD_OP: + + status = acpi_ds_create_field (op, arg->common.node, walk_state); + break; + + default: + /* All NAMED_FIELD opcodes must be handled above */ + break; + } + break; + + + case AML_TYPE_NAMED_SIMPLE: + + status = acpi_ds_create_operands (walk_state, arg); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + switch (op->common.aml_opcode) { + case AML_PROCESSOR_OP: + + status = acpi_ex_create_processor (walk_state); + break; + + case AML_POWER_RES_OP: + + status = acpi_ex_create_power_resource (walk_state); + break; + + case AML_MUTEX_OP: + + status = acpi_ex_create_mutex (walk_state); + break; + + case AML_EVENT_OP: + + status = acpi_ex_create_event (walk_state); + break; + + case AML_DATA_REGION_OP: + + status = acpi_ex_create_table_region (walk_state); + break; + + case AML_ALIAS_OP: + + status = acpi_ex_create_alias (walk_state); + break; + + default: + /* Unknown opcode */ + + status = AE_OK; + goto cleanup; + } + + /* Delete operands */ + + for (i = 1; i < walk_state->num_operands; i++) { + acpi_ut_remove_reference (walk_state->operands[i]); + walk_state->operands[i] = NULL; + } + + break; +#endif /* ACPI_NO_METHOD_EXECUTION */ + + case AML_TYPE_NAMED_COMPLEX: + + switch (op->common.aml_opcode) { +#ifndef ACPI_NO_METHOD_EXECUTION + case AML_REGION_OP: + /* + * The op_region is not fully parsed at this time. Only valid argument is the space_id. + * (We must save the address of the AML of the address and length operands) + */ + /* + * If we have a valid region, initialize it + * Namespace is NOT locked at this point. + */ + status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), FALSE); + if (ACPI_FAILURE (status)) { + /* + * If AE_NOT_EXIST is returned, it is not fatal + * because many regions get created before a handler + * is installed for said region. + */ + if (AE_NOT_EXIST == status) { + status = AE_OK; + } + } + break; + + + case AML_NAME_OP: + + status = acpi_ds_create_node (walk_state, node, op); + break; +#endif /* ACPI_NO_METHOD_EXECUTION */ + + + default: + /* All NAMED_COMPLEX opcodes must be handled above */ + /* Note: Method objects were already created in Pass 1 */ + break; + } + break; + + + case AML_CLASS_INTERNAL: + + /* case AML_INT_NAMEPATH_OP: */ + break; + + + case AML_CLASS_METHOD_CALL: + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "RESOLVING-method_call: State=%p Op=%p named_obj=%p\n", + walk_state, op, node)); + + /* + * Lookup the method name and save the Node + */ + status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string, + ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS2, + ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, + walk_state, &(new_node)); + if (ACPI_SUCCESS (status)) { + /* + * Make sure that what we found is indeed a method + * We didn't search for a method on purpose, to see if the name would resolve + */ + if (new_node->type != ACPI_TYPE_METHOD) { + status = AE_AML_OPERAND_TYPE; + } + + /* We could put the returned object (Node) on the object stack for later, but + * for now, we will put it in the "op" object that the parser uses, so we + * can get it again at the end of this scope + */ + op->common.node = new_node; + } + else { + ACPI_REPORT_NSERROR (arg->common.value.string, status); + } + break; + + + default: + break; + } + +cleanup: + + /* Remove the Node pushed at the very beginning */ + + walk_state->operands[0] = NULL; + walk_state->num_operands = 0; + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c new file mode 100644 index 00000000000..65f456151e2 --- /dev/null +++ b/drivers/acpi/dispatcher/dswscope.c @@ -0,0 +1,229 @@ +/****************************************************************************** + * + * Module Name: dswscope - Scope stack manipulation + * + *****************************************************************************/ + +/* + * 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acdispat.h> + + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dswscope") + + +#define STACK_POP(head) head + + +/**************************************************************************** + * + * FUNCTION: acpi_ds_scope_stack_clear + * + * PARAMETERS: None + * + * DESCRIPTION: Pop (and free) everything on the scope stack except the + * root scope object (which remains at the stack top.) + * + ***************************************************************************/ + +void +acpi_ds_scope_stack_clear ( + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *scope_info; + + ACPI_FUNCTION_NAME ("ds_scope_stack_clear"); + + + while (walk_state->scope_info) { + /* Pop a scope off the stack */ + + scope_info = walk_state->scope_info; + walk_state->scope_info = scope_info->scope.next; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Popped object type (%s)\n", acpi_ut_get_type_name (scope_info->common.value))); + acpi_ut_delete_generic_state (scope_info); + } +} + + +/**************************************************************************** + * + * FUNCTION: acpi_ds_scope_stack_push + * + * PARAMETERS: *Node, - Name to be made current + * Type, - Type of frame being pushed + * + * DESCRIPTION: Push the current scope on the scope stack, and make the + * passed Node current. + * + ***************************************************************************/ + +acpi_status +acpi_ds_scope_stack_push ( + struct acpi_namespace_node *node, + acpi_object_type type, + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *scope_info; + union acpi_generic_state *old_scope_info; + + + ACPI_FUNCTION_TRACE ("ds_scope_stack_push"); + + + if (!node) { + /* Invalid scope */ + + ACPI_REPORT_ERROR (("ds_scope_stack_push: null scope passed\n")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Make sure object type is valid */ + + if (!acpi_ut_valid_object_type (type)) { + ACPI_REPORT_WARNING (("ds_scope_stack_push: Invalid object type: 0x%X\n", type)); + } + + /* Allocate a new scope object */ + + scope_info = acpi_ut_create_generic_state (); + if (!scope_info) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Init new scope object */ + + scope_info->common.data_type = ACPI_DESC_TYPE_STATE_WSCOPE; + scope_info->scope.node = node; + scope_info->common.value = (u16) type; + + walk_state->scope_depth++; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[%.2d] Pushed scope ", (u32) walk_state->scope_depth)); + + old_scope_info = walk_state->scope_info; + if (old_scope_info) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + "[%4.4s] (%s)", + acpi_ut_get_node_name (old_scope_info->scope.node), + acpi_ut_get_type_name (old_scope_info->common.value))); + } + else { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + "[\\___] (%s)", "ROOT")); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + ", New scope -> [%4.4s] (%s)\n", + acpi_ut_get_node_name (scope_info->scope.node), + acpi_ut_get_type_name (scope_info->common.value))); + + /* Push new scope object onto stack */ + + acpi_ut_push_generic_state (&walk_state->scope_info, scope_info); + return_ACPI_STATUS (AE_OK); +} + + +/**************************************************************************** + * + * FUNCTION: acpi_ds_scope_stack_pop + * + * PARAMETERS: Type - The type of frame to be found + * + * DESCRIPTION: Pop the scope stack until a frame of the requested type + * is found. + * + * RETURN: Count of frames popped. If no frame of the requested type + * was found, the count is returned as a negative number and + * the scope stack is emptied (which sets the current scope + * to the root). If the scope stack was empty at entry, the + * function is a no-op and returns 0. + * + ***************************************************************************/ + +acpi_status +acpi_ds_scope_stack_pop ( + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *scope_info; + union acpi_generic_state *new_scope_info; + + + ACPI_FUNCTION_TRACE ("ds_scope_stack_pop"); + + + /* + * Pop scope info object off the stack. + */ + scope_info = acpi_ut_pop_generic_state (&walk_state->scope_info); + if (!scope_info) { + return_ACPI_STATUS (AE_STACK_UNDERFLOW); + } + + walk_state->scope_depth--; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "[%.2d] Popped scope [%4.4s] (%s), New scope -> ", + (u32) walk_state->scope_depth, + acpi_ut_get_node_name (scope_info->scope.node), + acpi_ut_get_type_name (scope_info->common.value))); + + new_scope_info = walk_state->scope_info; + if (new_scope_info) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + "[%4.4s] (%s)\n", + acpi_ut_get_node_name (new_scope_info->scope.node), + acpi_ut_get_type_name (new_scope_info->common.value))); + } + else { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, + "[\\___] (ROOT)\n")); + } + + acpi_ut_delete_generic_state (scope_info); + return_ACPI_STATUS (AE_OK); +} + + diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c new file mode 100644 index 00000000000..e555b3fbd5e --- /dev/null +++ b/drivers/acpi/dispatcher/dswstate.c @@ -0,0 +1,1100 @@ +/****************************************************************************** + * + * Module Name: dswstate - Dispatcher parse tree walk management 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. + */ + + +#include <acpi/acpi.h> +#include <acpi/acparser.h> +#include <acpi/acdispat.h> +#include <acpi/acnamesp.h> + +#define _COMPONENT ACPI_DISPATCHER + ACPI_MODULE_NAME ("dswstate") + + +#ifdef ACPI_FUTURE_USAGE + +/******************************************************************************* + * + * FUNCTION: acpi_ds_result_insert + * + * PARAMETERS: Object - Object to push + * Index - Where to insert the object + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Insert an object onto this walk's result stack + * + ******************************************************************************/ + +acpi_status +acpi_ds_result_insert ( + void *object, + u32 index, + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_NAME ("ds_result_insert"); + + + state = walk_state->results; + if (!state) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n", + walk_state)); + return (AE_NOT_EXIST); + } + + if (index >= ACPI_OBJ_NUM_OPERANDS) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Index out of range: %X Obj=%p State=%p Num=%X\n", + index, object, walk_state, state->results.num_results)); + return (AE_BAD_PARAMETER); + } + + if (!object) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null Object! Index=%X Obj=%p State=%p Num=%X\n", + index, object, walk_state, state->results.num_results)); + return (AE_BAD_PARAMETER); + } + + state->results.obj_desc [index] = object; + state->results.num_results++; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj=%p [%s] State=%p Num=%X Cur=%X\n", + object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL", + walk_state, state->results.num_results, walk_state->current_result)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_result_remove + * + * PARAMETERS: Object - Where to return the popped object + * Index - Where to extract the object + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In + * other words, this is a FIFO. + * + ******************************************************************************/ + +acpi_status +acpi_ds_result_remove ( + union acpi_operand_object **object, + u32 index, + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_NAME ("ds_result_remove"); + + + state = walk_state->results; + if (!state) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n", + walk_state)); + return (AE_NOT_EXIST); + } + + if (index >= ACPI_OBJ_MAX_OPERAND) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Index out of range: %X State=%p Num=%X\n", + index, walk_state, state->results.num_results)); + } + + /* Check for a valid result object */ + + if (!state->results.obj_desc [index]) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null operand! State=%p #Ops=%X, Index=%X\n", + walk_state, state->results.num_results, index)); + return (AE_AML_NO_RETURN_VALUE); + } + + /* Remove the object */ + + state->results.num_results--; + + *object = state->results.obj_desc [index]; + state->results.obj_desc [index] = NULL; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Obj=%p [%s] Index=%X State=%p Num=%X\n", + *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", + index, walk_state, state->results.num_results)); + + return (AE_OK); +} + +#endif /* ACPI_FUTURE_USAGE */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_result_pop + * + * PARAMETERS: Object - Where to return the popped object + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In + * other words, this is a FIFO. + * + ******************************************************************************/ + +acpi_status +acpi_ds_result_pop ( + union acpi_operand_object **object, + struct acpi_walk_state *walk_state) +{ + acpi_native_uint index; + union acpi_generic_state *state; + + + ACPI_FUNCTION_NAME ("ds_result_pop"); + + + state = walk_state->results; + if (!state) { + return (AE_OK); + } + + if (!state->results.num_results) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Result stack is empty! State=%p\n", + walk_state)); + return (AE_AML_NO_RETURN_VALUE); + } + + /* Remove top element */ + + state->results.num_results--; + + for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) { + /* Check for a valid result object */ + + if (state->results.obj_desc [index -1]) { + *object = state->results.obj_desc [index -1]; + state->results.obj_desc [index -1] = NULL; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] Index=%X State=%p Num=%X\n", + *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", + (u32) index -1, walk_state, state->results.num_results)); + + return (AE_OK); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state)); + return (AE_AML_NO_RETURN_VALUE); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_result_pop_from_bottom + * + * PARAMETERS: Object - Where to return the popped object + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In + * other words, this is a FIFO. + * + ******************************************************************************/ + +acpi_status +acpi_ds_result_pop_from_bottom ( + union acpi_operand_object **object, + struct acpi_walk_state *walk_state) +{ + acpi_native_uint index; + union acpi_generic_state *state; + + + ACPI_FUNCTION_NAME ("ds_result_pop_from_bottom"); + + + state = walk_state->results; + if (!state) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Warning: No result object pushed! State=%p\n", walk_state)); + return (AE_NOT_EXIST); + } + + if (!state->results.num_results) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state)); + return (AE_AML_NO_RETURN_VALUE); + } + + /* Remove Bottom element */ + + *object = state->results.obj_desc [0]; + + /* Push entire stack down one element */ + + for (index = 0; index < state->results.num_results; index++) { + state->results.obj_desc [index] = state->results.obj_desc [index + 1]; + } + + state->results.num_results--; + + /* Check for a valid result object */ + + if (!*object) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null operand! State=%p #Ops=%X, Index=%X\n", + walk_state, state->results.num_results, (u32) index)); + return (AE_AML_NO_RETURN_VALUE); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s], Results=%p State=%p\n", + *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL", + state, walk_state)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_result_push + * + * PARAMETERS: Object - Where to return the popped object + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Push an object onto the current result stack + * + ******************************************************************************/ + +acpi_status +acpi_ds_result_push ( + union acpi_operand_object *object, + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_NAME ("ds_result_push"); + + + state = walk_state->results; + if (!state) { + ACPI_REPORT_ERROR (("No result stack frame during push\n")); + return (AE_AML_INTERNAL); + } + + if (state->results.num_results == ACPI_OBJ_NUM_OPERANDS) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Result stack overflow: Obj=%p State=%p Num=%X\n", + object, walk_state, state->results.num_results)); + return (AE_STACK_OVERFLOW); + } + + if (!object) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Object! Obj=%p State=%p Num=%X\n", + object, walk_state, state->results.num_results)); + return (AE_BAD_PARAMETER); + } + + state->results.obj_desc [state->results.num_results] = object; + state->results.num_results++; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n", + object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL", + walk_state, state->results.num_results, walk_state->current_result)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_result_stack_push + * + * PARAMETERS: walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Push an object onto the walk_state result stack. + * + ******************************************************************************/ + +acpi_status +acpi_ds_result_stack_push ( + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *state; + + ACPI_FUNCTION_NAME ("ds_result_stack_push"); + + + state = acpi_ut_create_generic_state (); + if (!state) { + return (AE_NO_MEMORY); + } + + state->common.data_type = ACPI_DESC_TYPE_STATE_RESULT; + acpi_ut_push_generic_state (&walk_state->results, state); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Results=%p State=%p\n", + state, walk_state)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_result_stack_pop + * + * PARAMETERS: walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop an object off of the walk_state result stack. + * + ******************************************************************************/ + +acpi_status +acpi_ds_result_stack_pop ( + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *state; + + ACPI_FUNCTION_NAME ("ds_result_stack_pop"); + + + /* Check for stack underflow */ + + if (walk_state->results == NULL) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Underflow - State=%p\n", + walk_state)); + return (AE_AML_NO_OPERAND); + } + + state = acpi_ut_pop_generic_state (&walk_state->results); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Result=%p remaining_results=%X State=%p\n", + state, state->results.num_results, walk_state)); + + acpi_ut_delete_generic_state (state); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_delete_all + * + * PARAMETERS: walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Clear the object stack by deleting all objects that are on it. + * Should be used with great care, if at all! + * + ******************************************************************************/ +#ifdef ACPI_FUTURE_USAGE +acpi_status +acpi_ds_obj_stack_delete_all ( + struct acpi_walk_state *walk_state) +{ + u32 i; + + + ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_delete_all", walk_state); + + + /* The stack size is configurable, but fixed */ + + for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) { + if (walk_state->operands[i]) { + acpi_ut_remove_reference (walk_state->operands[i]); + walk_state->operands[i] = NULL; + } + } + + return_ACPI_STATUS (AE_OK); +} +#endif /* ACPI_FUTURE_USAGE */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_push + * + * PARAMETERS: Object - Object to push + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Push an object onto this walk's object/operand stack + * + ******************************************************************************/ + +acpi_status +acpi_ds_obj_stack_push ( + void *object, + struct acpi_walk_state *walk_state) +{ + ACPI_FUNCTION_NAME ("ds_obj_stack_push"); + + + /* Check for stack overflow */ + + if (walk_state->num_operands >= ACPI_OBJ_NUM_OPERANDS) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "overflow! Obj=%p State=%p #Ops=%X\n", + object, walk_state, walk_state->num_operands)); + return (AE_STACK_OVERFLOW); + } + + /* Put the object onto the stack */ + + walk_state->operands [walk_state->num_operands] = object; + walk_state->num_operands++; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", + object, acpi_ut_get_object_type_name ((union acpi_operand_object *) object), + walk_state, walk_state->num_operands)); + + return (AE_OK); +} + + +#if 0 +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_pop_object + * + * PARAMETERS: pop_count - Number of objects/entries to pop + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT + * deleted by this routine. + * + ******************************************************************************/ + +acpi_status +acpi_ds_obj_stack_pop_object ( + union acpi_operand_object **object, + struct acpi_walk_state *walk_state) +{ + ACPI_FUNCTION_NAME ("ds_obj_stack_pop_object"); + + + /* Check for stack underflow */ + + if (walk_state->num_operands == 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Missing operand/stack empty! State=%p #Ops=%X\n", + walk_state, walk_state->num_operands)); + *object = NULL; + return (AE_AML_NO_OPERAND); + } + + /* Pop the stack */ + + walk_state->num_operands--; + + /* Check for a valid operand */ + + if (!walk_state->operands [walk_state->num_operands]) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null operand! State=%p #Ops=%X\n", + walk_state, walk_state->num_operands)); + *object = NULL; + return (AE_AML_NO_OPERAND); + } + + /* Get operand and set stack entry to null */ + + *object = walk_state->operands [walk_state->num_operands]; + walk_state->operands [walk_state->num_operands] = NULL; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n", + *object, acpi_ut_get_object_type_name (*object), + walk_state, walk_state->num_operands)); + + return (AE_OK); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_pop + * + * PARAMETERS: pop_count - Number of objects/entries to pop + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT + * deleted by this routine. + * + ******************************************************************************/ + +acpi_status +acpi_ds_obj_stack_pop ( + u32 pop_count, + struct acpi_walk_state *walk_state) +{ + u32 i; + + ACPI_FUNCTION_NAME ("ds_obj_stack_pop"); + + + for (i = 0; i < pop_count; i++) { + /* Check for stack underflow */ + + if (walk_state->num_operands == 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Underflow! Count=%X State=%p #Ops=%X\n", + pop_count, walk_state, walk_state->num_operands)); + return (AE_STACK_UNDERFLOW); + } + + /* Just set the stack entry to null */ + + walk_state->num_operands--; + walk_state->operands [walk_state->num_operands] = NULL; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n", + pop_count, walk_state, walk_state->num_operands)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_pop_and_delete + * + * PARAMETERS: pop_count - Number of objects/entries to pop + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Pop this walk's object stack and delete each object that is + * popped off. + * + ******************************************************************************/ + +acpi_status +acpi_ds_obj_stack_pop_and_delete ( + u32 pop_count, + struct acpi_walk_state *walk_state) +{ + u32 i; + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_NAME ("ds_obj_stack_pop_and_delete"); + + + for (i = 0; i < pop_count; i++) { + /* Check for stack underflow */ + + if (walk_state->num_operands == 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Underflow! Count=%X State=%p #Ops=%X\n", + pop_count, walk_state, walk_state->num_operands)); + return (AE_STACK_UNDERFLOW); + } + + /* Pop the stack and delete an object if present in this stack entry */ + + walk_state->num_operands--; + obj_desc = walk_state->operands [walk_state->num_operands]; + if (obj_desc) { + acpi_ut_remove_reference (walk_state->operands [walk_state->num_operands]); + walk_state->operands [walk_state->num_operands] = NULL; + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n", + pop_count, walk_state, walk_state->num_operands)); + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_obj_stack_get_value + * + * PARAMETERS: Index - Stack index whose value is desired. Based + * on the top of the stack (index=0 == top) + * walk_state - Current Walk state + * + * RETURN: Status + * + * DESCRIPTION: Retrieve an object from this walk's object stack. Index must + * be within the range of the current stack pointer. + * + ******************************************************************************/ +#ifdef ACPI_FUTURE_USAGE +void * +acpi_ds_obj_stack_get_value ( + u32 index, + struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_get_value", walk_state); + + + /* Can't do it if the stack is empty */ + + if (walk_state->num_operands == 0) { + return_PTR (NULL); + } + + /* or if the index is past the top of the stack */ + + if (index > (walk_state->num_operands - (u32) 1)) { + return_PTR (NULL); + } + + return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) - + index]); +} +#endif /* ACPI_FUTURE_USAGE */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_get_current_walk_state + * + * PARAMETERS: Thread - Get current active state for this Thread + * + * RETURN: Pointer to the current walk state + * + * DESCRIPTION: Get the walk state that is at the head of the list (the "current" + * walk state.) + * + ******************************************************************************/ + +struct acpi_walk_state * +acpi_ds_get_current_walk_state ( + struct acpi_thread_state *thread) + +{ + ACPI_FUNCTION_NAME ("ds_get_current_walk_state"); + + + if (!thread) { + return (NULL); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Current walk_state %p\n", + thread->walk_state_list)); + + return (thread->walk_state_list); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_push_walk_state + * + * PARAMETERS: walk_state - State to push + * walk_list - The list that owns the walk stack + * + * RETURN: None + * + * DESCRIPTION: Place the walk_state at the head of the state list. + * + ******************************************************************************/ + +void +acpi_ds_push_walk_state ( + struct acpi_walk_state *walk_state, + struct acpi_thread_state *thread) +{ + ACPI_FUNCTION_TRACE ("ds_push_walk_state"); + + + walk_state->next = thread->walk_state_list; + thread->walk_state_list = walk_state; + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_pop_walk_state + * + * PARAMETERS: walk_list - The list that owns the walk stack + * + * RETURN: A walk_state object popped from the stack + * + * DESCRIPTION: Remove and return the walkstate object that is at the head of + * the walk stack for the given walk list. NULL indicates that + * the list is empty. + * + ******************************************************************************/ + +struct acpi_walk_state * +acpi_ds_pop_walk_state ( + struct acpi_thread_state *thread) +{ + struct acpi_walk_state *walk_state; + + + ACPI_FUNCTION_TRACE ("ds_pop_walk_state"); + + + walk_state = thread->walk_state_list; + + if (walk_state) { + /* Next walk state becomes the current walk state */ + + thread->walk_state_list = walk_state->next; + + /* + * Don't clear the NEXT field, this serves as an indicator + * that there is a parent WALK STATE + * NO: walk_state->Next = NULL; + */ + } + + return_PTR (walk_state); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_create_walk_state + * + * PARAMETERS: Origin - Starting point for this walk + * Thread - Current thread state + * + * RETURN: Pointer to the new walk state. + * + * DESCRIPTION: Allocate and initialize a new walk state. The current walk + * state is set to this new state. + * + ******************************************************************************/ + +struct acpi_walk_state * +acpi_ds_create_walk_state ( + acpi_owner_id owner_id, + union acpi_parse_object *origin, + union acpi_operand_object *mth_desc, + struct acpi_thread_state *thread) +{ + struct acpi_walk_state *walk_state; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ds_create_walk_state"); + + + walk_state = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_WALK); + if (!walk_state) { + return_PTR (NULL); + } + + walk_state->data_type = ACPI_DESC_TYPE_WALK; + walk_state->owner_id = owner_id; + walk_state->origin = origin; + walk_state->method_desc = mth_desc; + walk_state->thread = thread; + + walk_state->parser_state.start_op = origin; + + /* Init the method args/local */ + +#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) + acpi_ds_method_data_init (walk_state); +#endif + + /* Create an initial result stack entry */ + + status = acpi_ds_result_stack_push (walk_state); + if (ACPI_FAILURE (status)) { + acpi_ut_release_to_cache (ACPI_MEM_LIST_WALK, walk_state); + return_PTR (NULL); + } + + /* Put the new state at the head of the walk list */ + + if (thread) { + acpi_ds_push_walk_state (walk_state, thread); + } + + return_PTR (walk_state); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_init_aml_walk + * + * PARAMETERS: walk_state - New state to be initialized + * Op - Current parse op + * method_node - Control method NS node, if any + * aml_start - Start of AML + * aml_length - Length of AML + * Params - Method args, if any + * return_obj_desc - Where to store a return object, if any + * pass_number - 1, 2, or 3 + * + * RETURN: Status + * + * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk + * + ******************************************************************************/ + +acpi_status +acpi_ds_init_aml_walk ( + struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + struct acpi_namespace_node *method_node, + u8 *aml_start, + u32 aml_length, + struct acpi_parameter_info *info, + u32 pass_number) +{ + acpi_status status; + struct acpi_parse_state *parser_state = &walk_state->parser_state; + union acpi_parse_object *extra_op; + + + ACPI_FUNCTION_TRACE ("ds_init_aml_walk"); + + + walk_state->parser_state.aml = + walk_state->parser_state.aml_start = aml_start; + walk_state->parser_state.aml_end = + walk_state->parser_state.pkg_end = aml_start + aml_length; + + /* The next_op of the next_walk will be the beginning of the method */ + + walk_state->next_op = NULL; + + if (info) { + if (info->parameter_type == ACPI_PARAM_GPE) { + walk_state->gpe_event_info = ACPI_CAST_PTR (struct acpi_gpe_event_info, + info->parameters); + } + else { + walk_state->params = info->parameters; + walk_state->caller_return_desc = &info->return_object; + } + } + + status = acpi_ps_init_scope (&walk_state->parser_state, op); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (method_node) { + walk_state->parser_state.start_node = method_node; + walk_state->walk_type = ACPI_WALK_METHOD; + walk_state->method_node = method_node; + walk_state->method_desc = acpi_ns_get_attached_object (method_node); + + /* Push start scope on scope stack and make it current */ + + status = acpi_ds_scope_stack_push (method_node, ACPI_TYPE_METHOD, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Init the method arguments */ + + status = acpi_ds_method_data_init_args (walk_state->params, ACPI_METHOD_NUM_ARGS, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + else { + /* + * Setup the current scope. + * Find a Named Op that has a namespace node associated with it. + * search upwards from this Op. Current scope is the first + * Op with a namespace node. + */ + extra_op = parser_state->start_op; + while (extra_op && !extra_op->common.node) { + extra_op = extra_op->common.parent; + } + + if (!extra_op) { + parser_state->start_node = NULL; + } + else { + parser_state->start_node = extra_op->common.node; + } + + if (parser_state->start_node) { + /* Push start scope on scope stack and make it current */ + + status = acpi_ds_scope_stack_push (parser_state->start_node, + parser_state->start_node->type, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + } + + status = acpi_ds_init_callbacks (walk_state, pass_number); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ds_delete_walk_state + * + * PARAMETERS: walk_state - State to delete + * + * RETURN: Status + * + * DESCRIPTION: Delete a walk state including all internal data structures + * + ******************************************************************************/ + +void +acpi_ds_delete_walk_state ( + struct acpi_walk_state *walk_state) +{ + union acpi_generic_state *state; + + + ACPI_FUNCTION_TRACE_PTR ("ds_delete_walk_state", walk_state); + + + if (!walk_state) { + return; + } + + if (walk_state->data_type != ACPI_DESC_TYPE_WALK) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p is not a valid walk state\n", walk_state)); + return; + } + + if (walk_state->parser_state.scope) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", walk_state)); + } + + /* Always must free any linked control states */ + + while (walk_state->control_state) { + state = walk_state->control_state; + walk_state->control_state = state->common.next; + + acpi_ut_delete_generic_state (state); + } + + /* Always must free any linked parse states */ + + while (walk_state->scope_info) { + state = walk_state->scope_info; + walk_state->scope_info = state->common.next; + + acpi_ut_delete_generic_state (state); + } + + /* Always must free any stacked result states */ + + while (walk_state->results) { + state = walk_state->results; + walk_state->results = state->common.next; + + acpi_ut_delete_generic_state (state); + } + + acpi_ut_release_to_cache (ACPI_MEM_LIST_WALK, walk_state); + return_VOID; +} + + +#ifdef ACPI_ENABLE_OBJECT_CACHE +/****************************************************************************** + * + * FUNCTION: acpi_ds_delete_walk_state_cache + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Purge the global state object cache. Used during subsystem + * termination. + * + ******************************************************************************/ + +void +acpi_ds_delete_walk_state_cache ( + void) +{ + ACPI_FUNCTION_TRACE ("ds_delete_walk_state_cache"); + + + acpi_ut_delete_generic_cache (ACPI_MEM_LIST_WALK); + return_VOID; +} +#endif + + |