diff options
Diffstat (limited to 'drivers/acpi/executer')
24 files changed, 11955 insertions, 0 deletions
diff --git a/drivers/acpi/executer/Makefile b/drivers/acpi/executer/Makefile new file mode 100644 index 000000000000..e09998aa012f --- /dev/null +++ b/drivers/acpi/executer/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +obj-y := exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\ + exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\ + excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \ + exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o + +EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c new file mode 100644 index 000000000000..ac3c061967f2 --- /dev/null +++ b/drivers/acpi/executer/exconfig.c @@ -0,0 +1,487 @@ +/****************************************************************************** + * + * Module Name: exconfig - Namespace reconfiguration (Load/Unload 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/acinterp.h> +#include <acpi/amlcode.h> +#include <acpi/acnamesp.h> +#include <acpi/acevents.h> +#include <acpi/actables.h> +#include <acpi/acdispat.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exconfig") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_add_table + * + * PARAMETERS: Table - Pointer to raw table + * parent_node - Where to load the table (scope) + * ddb_handle - Where to return the table handle. + * + * RETURN: Status + * + * DESCRIPTION: Common function to Install and Load an ACPI table with a + * returned table handle. + * + ******************************************************************************/ + +acpi_status +acpi_ex_add_table ( + struct acpi_table_header *table, + struct acpi_namespace_node *parent_node, + union acpi_operand_object **ddb_handle) +{ + acpi_status status; + struct acpi_table_desc table_info; + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_TRACE ("ex_add_table"); + + + /* Create an object to be the table handle */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_REFERENCE); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Install the new table into the local data structures */ + + ACPI_MEMSET (&table_info, 0, sizeof (struct acpi_table_desc)); + + table_info.type = ACPI_TABLE_SSDT; + table_info.pointer = table; + table_info.length = (acpi_size) table->length; + table_info.allocation = ACPI_MEM_ALLOCATED; + + status = acpi_tb_install_table (&table_info); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Add the table to the namespace */ + + status = acpi_ns_load_table (table_info.installed_desc, parent_node); + if (ACPI_FAILURE (status)) { + /* Uninstall table on error */ + + (void) acpi_tb_uninstall_table (table_info.installed_desc); + goto cleanup; + } + + /* Init the table handle */ + + obj_desc->reference.opcode = AML_LOAD_OP; + obj_desc->reference.object = table_info.installed_desc; + *ddb_handle = obj_desc; + return_ACPI_STATUS (AE_OK); + + +cleanup: + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_load_table_op + * + * PARAMETERS: walk_state - Current state with operands + * return_desc - Where to store the return object + * + * RETURN: Status + * + * DESCRIPTION: Load an ACPI table + * + ******************************************************************************/ + +acpi_status +acpi_ex_load_table_op ( + struct acpi_walk_state *walk_state, + union acpi_operand_object **return_desc) +{ + acpi_status status; + union acpi_operand_object **operand = &walk_state->operands[0]; + struct acpi_table_header *table; + struct acpi_namespace_node *parent_node; + struct acpi_namespace_node *start_node; + struct acpi_namespace_node *parameter_node = NULL; + union acpi_operand_object *ddb_handle; + + + ACPI_FUNCTION_TRACE ("ex_load_table_op"); + + +#if 0 + /* + * Make sure that the signature does not match one of the tables that + * is already loaded. + */ + status = acpi_tb_match_signature (operand[0]->string.pointer, NULL); + if (status == AE_OK) { + /* Signature matched -- don't allow override */ + + return_ACPI_STATUS (AE_ALREADY_EXISTS); + } +#endif + + /* Find the ACPI table */ + + status = acpi_tb_find_table (operand[0]->string.pointer, + operand[1]->string.pointer, + operand[2]->string.pointer, &table); + if (ACPI_FAILURE (status)) { + if (status != AE_NOT_FOUND) { + return_ACPI_STATUS (status); + } + + /* Table not found, return an Integer=0 and AE_OK */ + + ddb_handle = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!ddb_handle) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + ddb_handle->integer.value = 0; + *return_desc = ddb_handle; + + return_ACPI_STATUS (AE_OK); + } + + /* Default nodes */ + + start_node = walk_state->scope_info->scope.node; + parent_node = acpi_gbl_root_node; + + /* root_path (optional parameter) */ + + if (operand[3]->string.length > 0) { + /* + * Find the node referenced by the root_path_string. This is the + * location within the namespace where the table will be loaded. + */ + status = acpi_ns_get_node_by_path (operand[3]->string.pointer, start_node, + ACPI_NS_SEARCH_PARENT, &parent_node); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* parameter_path (optional parameter) */ + + if (operand[4]->string.length > 0) { + if ((operand[4]->string.pointer[0] != '\\') && + (operand[4]->string.pointer[0] != '^')) { + /* + * Path is not absolute, so it will be relative to the node + * referenced by the root_path_string (or the NS root if omitted) + */ + start_node = parent_node; + } + + /* + * Find the node referenced by the parameter_path_string + */ + status = acpi_ns_get_node_by_path (operand[4]->string.pointer, start_node, + ACPI_NS_SEARCH_PARENT, ¶meter_node); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Load the table into the namespace */ + + status = acpi_ex_add_table (table, parent_node, &ddb_handle); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Parameter Data (optional) */ + + if (parameter_node) { + /* Store the parameter data into the optional parameter object */ + + status = acpi_ex_store (operand[5], ACPI_CAST_PTR (union acpi_operand_object, parameter_node), + walk_state); + if (ACPI_FAILURE (status)) { + (void) acpi_ex_unload_table (ddb_handle); + return_ACPI_STATUS (status); + } + } + + *return_desc = ddb_handle; + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_load_op + * + * PARAMETERS: obj_desc - Region or Field where the table will be + * obtained + * Target - Where a handle to the table will be stored + * walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Load an ACPI table from a field or operation region + * + ******************************************************************************/ + +acpi_status +acpi_ex_load_op ( + union acpi_operand_object *obj_desc, + union acpi_operand_object *target, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_operand_object *ddb_handle; + union acpi_operand_object *buffer_desc = NULL; + struct acpi_table_header *table_ptr = NULL; + acpi_physical_address address; + struct acpi_table_header table_header; + u32 i; + + ACPI_FUNCTION_TRACE ("ex_load_op"); + + + /* Object can be either an op_region or a Field */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_REGION: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Region %p %s\n", + obj_desc, acpi_ut_get_object_type_name (obj_desc))); + + /* + * If the Region Address and Length have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_region_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Get the base physical address of the region */ + + address = obj_desc->region.address; + + /* Get the table length from the table header */ + + table_header.length = 0; + for (i = 0; i < 8; i++) { + status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, + (acpi_physical_address) (i + address), 8, + ((u8 *) &table_header) + i); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Sanity check the table length */ + + if (table_header.length < sizeof (struct acpi_table_header)) { + return_ACPI_STATUS (AE_BAD_HEADER); + } + + /* Allocate a buffer for the entire table */ + + table_ptr = ACPI_MEM_ALLOCATE (table_header.length); + if (!table_ptr) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Get the entire table from the op region */ + + for (i = 0; i < table_header.length; i++) { + status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ, + (acpi_physical_address) (i + address), 8, + ((u8 *) table_ptr + i)); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + } + break; + + + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Field %p %s\n", + obj_desc, acpi_ut_get_object_type_name (obj_desc))); + + /* + * The length of the field must be at least as large as the table. + * Read the entire field and thus the entire table. Buffer is + * allocated during the read. + */ + status = acpi_ex_read_data_from_field (walk_state, obj_desc, &buffer_desc); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + table_ptr = ACPI_CAST_PTR (struct acpi_table_header, buffer_desc->buffer.pointer); + + /* Sanity check the table length */ + + if (table_ptr->length < sizeof (struct acpi_table_header)) { + return_ACPI_STATUS (AE_BAD_HEADER); + } + break; + + + default: + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* The table must be either an SSDT or a PSDT */ + + if ((!ACPI_STRNCMP (table_ptr->signature, + acpi_gbl_table_data[ACPI_TABLE_PSDT].signature, + acpi_gbl_table_data[ACPI_TABLE_PSDT].sig_length)) && + (!ACPI_STRNCMP (table_ptr->signature, + acpi_gbl_table_data[ACPI_TABLE_SSDT].signature, + acpi_gbl_table_data[ACPI_TABLE_SSDT].sig_length))) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Table has invalid signature [%4.4s], must be SSDT or PSDT\n", + table_ptr->signature)); + status = AE_BAD_SIGNATURE; + goto cleanup; + } + + /* Install the new table into the local data structures */ + + status = acpi_ex_add_table (table_ptr, acpi_gbl_root_node, &ddb_handle); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Store the ddb_handle into the Target operand */ + + status = acpi_ex_store (ddb_handle, target, walk_state); + if (ACPI_FAILURE (status)) { + (void) acpi_ex_unload_table (ddb_handle); + } + + return_ACPI_STATUS (status); + + +cleanup: + + if (buffer_desc) { + acpi_ut_remove_reference (buffer_desc); + } + else { + ACPI_MEM_FREE (table_ptr); + } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_unload_table + * + * PARAMETERS: ddb_handle - Handle to a previously loaded table + * + * RETURN: Status + * + * DESCRIPTION: Unload an ACPI table + * + ******************************************************************************/ + +acpi_status +acpi_ex_unload_table ( + union acpi_operand_object *ddb_handle) +{ + acpi_status status = AE_OK; + union acpi_operand_object *table_desc = ddb_handle; + struct acpi_table_desc *table_info; + + + ACPI_FUNCTION_TRACE ("ex_unload_table"); + + + /* + * Validate the handle + * Although the handle is partially validated in acpi_ex_reconfiguration(), + * when it calls acpi_ex_resolve_operands(), the handle is more completely + * validated here. + */ + if ((!ddb_handle) || + (ACPI_GET_DESCRIPTOR_TYPE (ddb_handle) != ACPI_DESC_TYPE_OPERAND) || + (ACPI_GET_OBJECT_TYPE (ddb_handle) != ACPI_TYPE_LOCAL_REFERENCE)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Get the actual table descriptor from the ddb_handle */ + + table_info = (struct acpi_table_desc *) table_desc->reference.object; + + /* + * Delete the entire namespace under this table Node + * (Offset contains the table_id) + */ + acpi_ns_delete_namespace_by_owner (table_info->table_id); + + /* Delete the table itself */ + + (void) acpi_tb_uninstall_table (table_info->installed_desc); + + /* Delete the table descriptor (ddb_handle) */ + + acpi_ut_remove_reference (table_desc); + return_ACPI_STATUS (status); +} + diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c new file mode 100644 index 000000000000..df7ba1219bf6 --- /dev/null +++ b/drivers/acpi/executer/exconvrt.c @@ -0,0 +1,708 @@ +/****************************************************************************** + * + * Module Name: exconvrt - Object conversion 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/acinterp.h> +#include <acpi/amlcode.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exconvrt") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_convert_to_integer + * + * PARAMETERS: obj_desc - Object to be converted. Must be an + * Integer, Buffer, or String + * result_desc - Where the new Integer object is returned + * Flags - Used for string conversion + * + * RETURN: Status + * + * DESCRIPTION: Convert an ACPI Object to an integer. + * + ******************************************************************************/ + +acpi_status +acpi_ex_convert_to_integer ( + union acpi_operand_object *obj_desc, + union acpi_operand_object **result_desc, + u32 flags) +{ + union acpi_operand_object *return_desc; + u8 *pointer; + acpi_integer result; + u32 i; + u32 count; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_integer", obj_desc); + + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_INTEGER: + + /* No conversion necessary */ + + *result_desc = obj_desc; + return_ACPI_STATUS (AE_OK); + + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_STRING: + + /* Note: Takes advantage of common buffer/string fields */ + + pointer = obj_desc->buffer.pointer; + count = obj_desc->buffer.length; + break; + + default: + return_ACPI_STATUS (AE_TYPE); + } + + /* + * Convert the buffer/string to an integer. Note that both buffers and + * strings are treated as raw data - we don't convert ascii to hex for + * strings. + * + * There are two terminating conditions for the loop: + * 1) The size of an integer has been reached, or + * 2) The end of the buffer or string has been reached + */ + result = 0; + + /* + * String conversion is different than Buffer conversion + */ + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_STRING: + + /* + * Convert string to an integer - for most cases, the string must be + * hexadecimal as per the ACPI specification. The only exception (as + * of ACPI 3.0) is that the to_integer() operator allows both decimal + * and hexadecimal strings (hex prefixed with "0x"). + */ + status = acpi_ut_strtoul64 ((char *) pointer, flags, &result); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + break; + + + case ACPI_TYPE_BUFFER: + + /* Check for zero-length buffer */ + + if (!count) { + return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); + } + + /* Transfer no more than an integer's worth of data */ + + if (count > acpi_gbl_integer_byte_width) { + count = acpi_gbl_integer_byte_width; + } + + /* + * Convert buffer to an integer - we simply grab enough raw data + * from the buffer to fill an integer + */ + for (i = 0; i < count; i++) { + /* + * Get next byte and shift it into the Result. + * Little endian is used, meaning that the first byte of the buffer + * is the LSB of the integer + */ + result |= (((acpi_integer) pointer[i]) << (i * 8)); + } + break; + + + default: + /* No other types can get here */ + break; + } + + /* + * Create a new integer + */ + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Save the Result */ + + return_desc->integer.value = result; + acpi_ex_truncate_for32bit_table (return_desc); + *result_desc = return_desc; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_convert_to_buffer + * + * PARAMETERS: obj_desc - Object to be converted. Must be an + * Integer, Buffer, or String + * result_desc - Where the new buffer object is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert an ACPI Object to a Buffer + * + ******************************************************************************/ + +acpi_status +acpi_ex_convert_to_buffer ( + union acpi_operand_object *obj_desc, + union acpi_operand_object **result_desc) +{ + union acpi_operand_object *return_desc; + u8 *new_buf; + + + ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_buffer", obj_desc); + + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_BUFFER: + + /* No conversion necessary */ + + *result_desc = obj_desc; + return_ACPI_STATUS (AE_OK); + + + case ACPI_TYPE_INTEGER: + + /* + * Create a new Buffer object. + * Need enough space for one integer + */ + return_desc = acpi_ut_create_buffer_object (acpi_gbl_integer_byte_width); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the integer to the buffer, LSB first */ + + new_buf = return_desc->buffer.pointer; + ACPI_MEMCPY (new_buf, + &obj_desc->integer.value, + acpi_gbl_integer_byte_width); + break; + + + case ACPI_TYPE_STRING: + + /* + * Create a new Buffer object + * Size will be the string length + * + * NOTE: Add one to the string length to include the null terminator. + * The ACPI spec is unclear on this subject, but there is existing + * ASL/AML code that depends on the null being transferred to the new + * buffer. + */ + return_desc = acpi_ut_create_buffer_object ((acpi_size) obj_desc->string.length + 1); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the string to the buffer */ + + new_buf = return_desc->buffer.pointer; + ACPI_STRNCPY ((char *) new_buf, (char *) obj_desc->string.pointer, + obj_desc->string.length); + break; + + + default: + return_ACPI_STATUS (AE_TYPE); + } + + /* Mark buffer initialized */ + + return_desc->common.flags |= AOPOBJ_DATA_VALID; + *result_desc = return_desc; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_convert_to_ascii + * + * PARAMETERS: Integer - Value to be converted + * Base - ACPI_STRING_DECIMAL or ACPI_STRING_HEX + * String - Where the string is returned + * data_width - Size of data item to be converted, in bytes + * + * RETURN: Actual string length + * + * DESCRIPTION: Convert an ACPI Integer to a hex or decimal string + * + ******************************************************************************/ + +u32 +acpi_ex_convert_to_ascii ( + acpi_integer integer, + u16 base, + u8 *string, + u8 data_width) +{ + acpi_integer digit; + acpi_native_uint i; + acpi_native_uint j; + acpi_native_uint k = 0; + acpi_native_uint hex_length; + acpi_native_uint decimal_length; + u32 remainder; + u8 supress_zeros; + + + ACPI_FUNCTION_ENTRY (); + + + switch (base) { + case 10: + + /* Setup max length for the decimal number */ + + switch (data_width) { + case 1: + decimal_length = ACPI_MAX8_DECIMAL_DIGITS; + break; + + case 4: + decimal_length = ACPI_MAX32_DECIMAL_DIGITS; + break; + + case 8: + default: + decimal_length = ACPI_MAX64_DECIMAL_DIGITS; + break; + } + + supress_zeros = TRUE; /* No leading zeros */ + remainder = 0; + + for (i = decimal_length; i > 0; i--) { + /* Divide by nth factor of 10 */ + + digit = integer; + for (j = 0; j < i; j++) { + (void) acpi_ut_short_divide (digit, 10, &digit, &remainder); + } + + /* Handle leading zeros */ + + if (remainder != 0) { + supress_zeros = FALSE; + } + + if (!supress_zeros) { + string[k] = (u8) (ACPI_ASCII_ZERO + remainder); + k++; + } + } + break; + + case 16: + + hex_length = ACPI_MUL_2 (data_width); /* 2 ascii hex chars per data byte */ + + for (i = 0, j = (hex_length-1); i < hex_length; i++, j--) { + /* Get one hex digit, most significant digits first */ + + string[k] = (u8) acpi_ut_hex_to_ascii_char (integer, ACPI_MUL_4 (j)); + k++; + } + break; + + default: + return (0); + } + + /* + * Since leading zeros are supressed, we must check for the case where + * the integer equals 0 + * + * Finally, null terminate the string and return the length + */ + if (!k) { + string [0] = ACPI_ASCII_ZERO; + k = 1; + } + + string [k] = 0; + return ((u32) k); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_convert_to_string + * + * PARAMETERS: obj_desc - Object to be converted. Must be an + * Integer, Buffer, or String + * result_desc - Where the string object is returned + * Type - String flags (base and conversion type) + * + * RETURN: Status + * + * DESCRIPTION: Convert an ACPI Object to a string + * + ******************************************************************************/ + +acpi_status +acpi_ex_convert_to_string ( + union acpi_operand_object *obj_desc, + union acpi_operand_object **result_desc, + u32 type) +{ + union acpi_operand_object *return_desc; + u8 *new_buf; + u32 i; + u32 string_length = 0; + u16 base = 16; + u8 separator = ','; + + + ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_string", obj_desc); + + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_STRING: + + /* No conversion necessary */ + + *result_desc = obj_desc; + return_ACPI_STATUS (AE_OK); + + + case ACPI_TYPE_INTEGER: + + switch (type) { + case ACPI_EXPLICIT_CONVERT_DECIMAL: + + /* Make room for maximum decimal number */ + + string_length = ACPI_MAX_DECIMAL_DIGITS; + base = 10; + break; + + default: + + /* Two hex string characters for each integer byte */ + + string_length = ACPI_MUL_2 (acpi_gbl_integer_byte_width); + break; + } + + /* + * Create a new String + * Need enough space for one ASCII integer (plus null terminator) + */ + return_desc = acpi_ut_create_string_object ((acpi_size) string_length); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + new_buf = return_desc->buffer.pointer; + + /* Convert integer to string */ + + string_length = acpi_ex_convert_to_ascii (obj_desc->integer.value, base, + new_buf, acpi_gbl_integer_byte_width); + + /* Null terminate at the correct place */ + + return_desc->string.length = string_length; + new_buf [string_length] = 0; + break; + + + case ACPI_TYPE_BUFFER: + + /* Setup string length, base, and separator */ + + switch (type) { + case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string operator */ + /* + * From ACPI: "If Data is a buffer, it is converted to a string of + * decimal values separated by commas." + */ + base = 10; + + /* + * Calculate the final string length. Individual string values + * are variable length (include separator for each) + */ + for (i = 0; i < obj_desc->buffer.length; i++) { + if (obj_desc->buffer.pointer[i] >= 100) { + string_length += 4; + } + else if (obj_desc->buffer.pointer[i] >= 10) { + string_length += 3; + } + else { + string_length += 2; + } + } + break; + + case ACPI_IMPLICIT_CONVERT_HEX: + /* + * From the ACPI spec: + *"The entire contents of the buffer are converted to a string of + * two-character hexadecimal numbers, each separated by a space." + */ + separator = ' '; + string_length = (obj_desc->buffer.length * 3); + break; + + case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string operator */ + /* + * From ACPI: "If Data is a buffer, it is converted to a string of + * hexadecimal values separated by commas." + */ + string_length = (obj_desc->buffer.length * 3); + break; + + default: + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Perform the conversion. + * (-1 because of extra separator included in string_length from above) + */ + string_length--; + if (string_length > ACPI_MAX_STRING_CONVERSION) /* ACPI limit */ { + return_ACPI_STATUS (AE_AML_STRING_LIMIT); + } + + /* + * Create a new string object and string buffer + */ + return_desc = acpi_ut_create_string_object ((acpi_size) string_length); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + new_buf = return_desc->buffer.pointer; + + /* + * Convert buffer bytes to hex or decimal values + * (separated by commas or spaces) + */ + for (i = 0; i < obj_desc->buffer.length; i++) { + new_buf += acpi_ex_convert_to_ascii ( + (acpi_integer) obj_desc->buffer.pointer[i], base, + new_buf, 1); + *new_buf++ = separator; /* each separated by a comma or space */ + } + + /* Null terminate the string (overwrites final comma/space from above) */ + + new_buf--; + *new_buf = 0; + break; + + default: + return_ACPI_STATUS (AE_TYPE); + } + + *result_desc = return_desc; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_convert_to_target_type + * + * PARAMETERS: destination_type - Current type of the destination + * source_desc - Source object to be converted. + * result_desc - Where the converted object is returned + * walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Implements "implicit conversion" rules for storing an object. + * + ******************************************************************************/ + +acpi_status +acpi_ex_convert_to_target_type ( + acpi_object_type destination_type, + union acpi_operand_object *source_desc, + union acpi_operand_object **result_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ex_convert_to_target_type"); + + + /* Default behavior */ + + *result_desc = source_desc; + + /* + * If required by the target, + * perform implicit conversion on the source before we store it. + */ + switch (GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args)) { + case ARGI_SIMPLE_TARGET: + case ARGI_FIXED_TARGET: + case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ + + switch (destination_type) { + case ACPI_TYPE_LOCAL_REGION_FIELD: + /* + * Named field can always handle conversions + */ + break; + + default: + /* No conversion allowed for these types */ + + if (destination_type != ACPI_GET_OBJECT_TYPE (source_desc)) { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Explicit operator, will store (%s) over existing type (%s)\n", + acpi_ut_get_object_type_name (source_desc), + acpi_ut_get_type_name (destination_type))); + status = AE_TYPE; + } + } + break; + + + case ARGI_TARGETREF: + + switch (destination_type) { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + /* + * These types require an Integer operand. We can convert + * a Buffer or a String to an Integer if necessary. + */ + status = acpi_ex_convert_to_integer (source_desc, result_desc, + 16); + break; + + + case ACPI_TYPE_STRING: + + /* + * The operand must be a String. We can convert an + * Integer or Buffer if necessary + */ + status = acpi_ex_convert_to_string (source_desc, result_desc, + ACPI_IMPLICIT_CONVERT_HEX); + break; + + + case ACPI_TYPE_BUFFER: + + /* + * The operand must be a Buffer. We can convert an + * Integer or String if necessary + */ + status = acpi_ex_convert_to_buffer (source_desc, result_desc); + break; + + + default: + ACPI_REPORT_ERROR (("Bad destination type during conversion: %X\n", + destination_type)); + status = AE_AML_INTERNAL; + break; + } + break; + + + case ARGI_REFERENCE: + /* + * create_xxxx_field cases - we are storing the field object into the name + */ + break; + + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown Target type ID 0x%X Op %s dest_type %s\n", + GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args), + walk_state->op_info->name, acpi_ut_get_type_name (destination_type))); + + ACPI_REPORT_ERROR (("Bad Target Type (ARGI): %X\n", + GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args))) + status = AE_AML_INTERNAL; + } + + /* + * Source-to-Target conversion semantics: + * + * If conversion to the target type cannot be performed, then simply + * overwrite the target with the new object and type. + */ + if (status == AE_TYPE) { + status = AE_OK; + } + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c new file mode 100644 index 000000000000..d94c260dac6d --- /dev/null +++ b/drivers/acpi/executer/excreate.c @@ -0,0 +1,646 @@ +/****************************************************************************** + * + * Module Name: excreate - Named object creation + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/amlcode.h> +#include <acpi/acnamesp.h> +#include <acpi/acevents.h> +#include <acpi/actables.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("excreate") + + +#ifndef ACPI_NO_METHOD_EXECUTION +/***************************************************************************** + * + * FUNCTION: acpi_ex_create_alias + * + * PARAMETERS: walk_state - Current state, contains operands + * + * RETURN: Status + * + * DESCRIPTION: Create a new named alias + * + ****************************************************************************/ + +acpi_status +acpi_ex_create_alias ( + struct acpi_walk_state *walk_state) +{ + struct acpi_namespace_node *target_node; + struct acpi_namespace_node *alias_node; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ex_create_alias"); + + + /* Get the source/alias operands (both namespace nodes) */ + + alias_node = (struct acpi_namespace_node *) walk_state->operands[0]; + target_node = (struct acpi_namespace_node *) walk_state->operands[1]; + + if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) || + (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { + /* + * Dereference an existing alias so that we don't create a chain + * of aliases. With this code, we guarantee that an alias is + * always exactly one level of indirection away from the + * actual aliased name. + */ + target_node = ACPI_CAST_PTR (struct acpi_namespace_node, target_node->object); + } + + /* + * For objects that can never change (i.e., the NS node will + * permanently point to the same object), we can simply attach + * the object to the new NS node. For other objects (such as + * Integers, buffers, etc.), we have to point the Alias node + * to the original Node. + */ + switch (target_node->type) { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_BUFFER_FIELD: + + /* + * The new alias has the type ALIAS and points to the original + * NS node, not the object itself. This is because for these + * types, the object can change dynamically via a Store. + */ + alias_node->type = ACPI_TYPE_LOCAL_ALIAS; + alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node); + break; + + case ACPI_TYPE_METHOD: + + /* + * The new alias has the type ALIAS and points to the original + * NS node, not the object itself. This is because for these + * types, the object can change dynamically via a Store. + */ + alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS; + alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node); + break; + + default: + + /* Attach the original source object to the new Alias Node */ + + /* + * The new alias assumes the type of the target, and it points + * to the same object. The reference count of the object has an + * additional reference to prevent deletion out from under either the + * target node or the alias Node + */ + status = acpi_ns_attach_object (alias_node, + acpi_ns_get_attached_object (target_node), + target_node->type); + break; + } + + /* Since both operands are Nodes, we don't need to delete them */ + + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ex_create_event + * + * PARAMETERS: walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new event object + * + ****************************************************************************/ + +acpi_status +acpi_ex_create_event ( + struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_TRACE ("ex_create_event"); + + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_EVENT); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* + * Create the actual OS semaphore, with zero initial units -- meaning + * that the event is created in an unsignalled state + */ + status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, + &obj_desc->event.semaphore); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Attach object to the Node */ + + status = acpi_ns_attach_object ((struct acpi_namespace_node *) walk_state->operands[0], + obj_desc, ACPI_TYPE_EVENT); + +cleanup: + /* + * Remove local reference to the object (on error, will cause deletion + * of both object and semaphore if present.) + */ + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ex_create_mutex + * + * PARAMETERS: walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new mutex object + * + * Mutex (Name[0], sync_level[1]) + * + ****************************************************************************/ + +acpi_status +acpi_ex_create_mutex ( + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_TRACE_PTR ("ex_create_mutex", ACPI_WALK_OPERANDS); + + + /* Create the new mutex object */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_MUTEX); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* + * Create the actual OS semaphore. + * One unit max to make it a mutex, with one initial unit to allow + * the mutex to be acquired. + */ + status = acpi_os_create_semaphore (1, 1, &obj_desc->mutex.semaphore); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Init object and attach to NS node */ + + obj_desc->mutex.sync_level = (u8) walk_state->operands[1]->integer.value; + obj_desc->mutex.node = (struct acpi_namespace_node *) walk_state->operands[0]; + + status = acpi_ns_attach_object (obj_desc->mutex.node, + obj_desc, ACPI_TYPE_MUTEX); + + +cleanup: + /* + * Remove local reference to the object (on error, will cause deletion + * of both object and semaphore if present.) + */ + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ex_create_region + * + * PARAMETERS: aml_start - Pointer to the region declaration AML + * aml_length - Max length of the declaration AML + * Operands - List of operands for the opcode + * walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new operation region object + * + ****************************************************************************/ + +acpi_status +acpi_ex_create_region ( + u8 *aml_start, + u32 aml_length, + u8 region_space, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + struct acpi_namespace_node *node; + union acpi_operand_object *region_obj2; + + + ACPI_FUNCTION_TRACE ("ex_create_region"); + + + /* Get the Namespace Node */ + + node = walk_state->op->common.node; + + /* + * If the region object is already attached to this node, + * just return + */ + if (acpi_ns_get_attached_object (node)) { + return_ACPI_STATUS (AE_OK); + } + + /* + * Space ID must be one of the predefined IDs, or in the user-defined + * range + */ + if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) && + (region_space < ACPI_USER_REGION_BEGIN)) { + ACPI_REPORT_ERROR (("Invalid address_space type %X\n", region_space)); + return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Region Type - %s (%X)\n", + acpi_ut_get_region_name (region_space), region_space)); + + /* Create the region descriptor */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_REGION); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* + * Remember location in AML stream of address & length + * operands since they need to be evaluated at run time. + */ + region_obj2 = obj_desc->common.next_object; + region_obj2->extra.aml_start = aml_start; + region_obj2->extra.aml_length = aml_length; + + /* Init the region from the operands */ + + obj_desc->region.space_id = region_space; + obj_desc->region.address = 0; + obj_desc->region.length = 0; + obj_desc->region.node = node; + + /* Install the new region object in the parent Node */ + + status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_REGION); + + +cleanup: + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ex_create_table_region + * + * PARAMETERS: walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new data_table_region object + * + ****************************************************************************/ + +acpi_status +acpi_ex_create_table_region ( + struct acpi_walk_state *walk_state) +{ + acpi_status status; + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *obj_desc; + struct acpi_namespace_node *node; + struct acpi_table_header *table; + union acpi_operand_object *region_obj2; + + + ACPI_FUNCTION_TRACE ("ex_create_table_region"); + + + /* Get the Node from the object stack */ + + node = walk_state->op->common.node; + + /* + * If the region object is already attached to this node, + * just return + */ + if (acpi_ns_get_attached_object (node)) { + return_ACPI_STATUS (AE_OK); + } + + /* Find the ACPI table */ + + status = acpi_tb_find_table (operand[1]->string.pointer, + operand[2]->string.pointer, + operand[3]->string.pointer, &table); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Create the region descriptor */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_REGION); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + region_obj2 = obj_desc->common.next_object; + region_obj2->extra.region_context = NULL; + + /* Init the region from the operands */ + + obj_desc->region.space_id = REGION_DATA_TABLE; + obj_desc->region.address = (acpi_physical_address) ACPI_TO_INTEGER (table); + obj_desc->region.length = table->length; + obj_desc->region.node = node; + obj_desc->region.flags = AOPOBJ_DATA_VALID; + + /* Install the new region object in the parent Node */ + + status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_REGION); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + status = acpi_ev_initialize_region (obj_desc, FALSE); + if (ACPI_FAILURE (status)) { + if (status == AE_NOT_EXIST) { + status = AE_OK; + } + else { + goto cleanup; + } + } + + obj_desc->region.flags |= AOPOBJ_SETUP_COMPLETE; + + +cleanup: + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ex_create_processor + * + * PARAMETERS: walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new processor object and populate the fields + * + * Processor (Name[0], cpu_iD[1], pblock_addr[2], pblock_length[3]) + * + ****************************************************************************/ + +acpi_status +acpi_ex_create_processor ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *obj_desc; + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ex_create_processor", walk_state); + + + /* Create the processor object */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PROCESSOR); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Initialize the processor object from the operands + */ + obj_desc->processor.proc_id = (u8) operand[1]->integer.value; + obj_desc->processor.address = (acpi_io_address) operand[2]->integer.value; + obj_desc->processor.length = (u8) operand[3]->integer.value; + + /* Install the processor object in the parent Node */ + + status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0], + obj_desc, ACPI_TYPE_PROCESSOR); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ex_create_power_resource + * + * PARAMETERS: walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new power_resource object and populate the fields + * + * power_resource (Name[0], system_level[1], resource_order[2]) + * + ****************************************************************************/ + +acpi_status +acpi_ex_create_power_resource ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + acpi_status status; + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_TRACE_PTR ("ex_create_power_resource", walk_state); + + + /* Create the power resource object */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_POWER); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize the power object from the operands */ + + obj_desc->power_resource.system_level = (u8) operand[1]->integer.value; + obj_desc->power_resource.resource_order = (u16) operand[2]->integer.value; + + /* Install the power resource object in the parent Node */ + + status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0], + obj_desc, ACPI_TYPE_POWER); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + +#endif + +/***************************************************************************** + * + * FUNCTION: acpi_ex_create_method + * + * PARAMETERS: aml_start - First byte of the method's AML + * aml_length - AML byte count for this method + * walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Create a new method object + * + ****************************************************************************/ + +acpi_status +acpi_ex_create_method ( + u8 *aml_start, + u32 aml_length, + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *obj_desc; + acpi_status status; + u8 method_flags; + + + ACPI_FUNCTION_TRACE_PTR ("ex_create_method", walk_state); + + + /* Create a new method object */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_METHOD); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Save the method's AML pointer and length */ + + obj_desc->method.aml_start = aml_start; + obj_desc->method.aml_length = aml_length; + + /* + * Disassemble the method flags. Split off the Arg Count + * for efficiency + */ + method_flags = (u8) operand[1]->integer.value; + + obj_desc->method.method_flags = (u8) (method_flags & ~AML_METHOD_ARG_COUNT); + obj_desc->method.param_count = (u8) (method_flags & AML_METHOD_ARG_COUNT); + + /* + * Get the concurrency count. If required, a semaphore will be + * created for this method when it is parsed. + */ + if (acpi_gbl_all_methods_serialized) { + obj_desc->method.concurrency = 1; + obj_desc->method.method_flags |= AML_METHOD_SERIALIZED; + } + else if (method_flags & AML_METHOD_SERIALIZED) { + /* + * ACPI 1.0: Concurrency = 1 + * ACPI 2.0: Concurrency = (sync_level (in method declaration) + 1) + */ + obj_desc->method.concurrency = (u8) + (((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4) + 1); + } + else { + obj_desc->method.concurrency = ACPI_INFINITE_CONCURRENCY; + } + + /* Attach the new object to the method Node */ + + status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0], + obj_desc, ACPI_TYPE_METHOD); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + + /* Remove a reference to the operand */ + + acpi_ut_remove_reference (operand[1]); + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c new file mode 100644 index 000000000000..e2f7c32f28de --- /dev/null +++ b/drivers/acpi/executer/exdump.c @@ -0,0 +1,793 @@ +/****************************************************************************** + * + * Module Name: exdump - Interpreter debug output 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/acinterp.h> +#include <acpi/amlcode.h> +#include <acpi/acnamesp.h> +#include <acpi/acparser.h> + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exdump") + + +/* + * The following routines are used for debug output only + */ +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +/***************************************************************************** + * + * FUNCTION: acpi_ex_dump_operand + * + * PARAMETERS: *obj_desc - Pointer to entry to be dumped + * + * RETURN: None + * + * DESCRIPTION: Dump an operand object + * + ****************************************************************************/ + +void +acpi_ex_dump_operand ( + union acpi_operand_object *obj_desc, + u32 depth) +{ + u32 length; + u32 index; + + + ACPI_FUNCTION_NAME ("ex_dump_operand") + + + if (!((ACPI_LV_EXEC & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { + return; + } + + if (!obj_desc) { + /* + * This could be a null element of a package + */ + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Null Object Descriptor\n")); + return; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p is a NS Node: ", obj_desc)); + ACPI_DUMP_ENTRY (obj_desc, ACPI_LV_EXEC); + return; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "%p is not a node or operand object: [%s]\n", + obj_desc, acpi_ut_get_descriptor_name (obj_desc))); + ACPI_DUMP_BUFFER (obj_desc, sizeof (union acpi_operand_object)); + return; + } + + /* obj_desc is a valid object */ + + if (depth > 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%*s[%u] %p ", + depth, " ", depth, obj_desc)); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc)); + } + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_LOCAL_REFERENCE: + + switch (obj_desc->reference.opcode) { + case AML_DEBUG_OP: + + acpi_os_printf ("Reference: Debug\n"); + break; + + + case AML_NAME_OP: + + ACPI_DUMP_PATHNAME (obj_desc->reference.object, + "Reference: Name: ", ACPI_LV_INFO, _COMPONENT); + ACPI_DUMP_ENTRY (obj_desc->reference.object, ACPI_LV_INFO); + break; + + + case AML_INDEX_OP: + + acpi_os_printf ("Reference: Index %p\n", + obj_desc->reference.object); + break; + + + case AML_REF_OF_OP: + + acpi_os_printf ("Reference: (ref_of) %p\n", + obj_desc->reference.object); + break; + + + case AML_ARG_OP: + + acpi_os_printf ("Reference: Arg%d", + obj_desc->reference.offset); + + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { + /* Value is an Integer */ + + acpi_os_printf (" value is [%8.8X%8.8x]", + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); + } + + acpi_os_printf ("\n"); + break; + + + case AML_LOCAL_OP: + + acpi_os_printf ("Reference: Local%d", + obj_desc->reference.offset); + + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) { + + /* Value is an Integer */ + + acpi_os_printf (" value is [%8.8X%8.8x]", + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); + } + + acpi_os_printf ("\n"); + break; + + + case AML_INT_NAMEPATH_OP: + + acpi_os_printf ("Reference.Node->Name %X\n", + obj_desc->reference.node->name.integer); + break; + + + default: + + /* Unknown opcode */ + + acpi_os_printf ("Unknown Reference opcode=%X\n", + obj_desc->reference.opcode); + break; + + } + break; + + + case ACPI_TYPE_BUFFER: + + acpi_os_printf ("Buffer len %X @ %p \n", + obj_desc->buffer.length, obj_desc->buffer.pointer); + + length = obj_desc->buffer.length; + if (length > 64) { + length = 64; + } + + /* Debug only -- dump the buffer contents */ + + if (obj_desc->buffer.pointer) { + acpi_os_printf ("Buffer Contents: "); + + for (index = 0; index < length; index++) { + acpi_os_printf (" %02x", obj_desc->buffer.pointer[index]); + } + acpi_os_printf ("\n"); + } + break; + + + case ACPI_TYPE_INTEGER: + + acpi_os_printf ("Integer %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); + break; + + + case ACPI_TYPE_PACKAGE: + + acpi_os_printf ("Package [Len %X] element_array %p\n", + obj_desc->package.count, obj_desc->package.elements); + + /* + * If elements exist, package element pointer is valid, + * and debug_level exceeds 1, dump package's elements. + */ + if (obj_desc->package.count && + obj_desc->package.elements && + acpi_dbg_level > 1) { + for (index = 0; index < obj_desc->package.count; index++) { + acpi_ex_dump_operand (obj_desc->package.elements[index], depth+1); + } + } + break; + + + case ACPI_TYPE_REGION: + + acpi_os_printf ("Region %s (%X)", + acpi_ut_get_region_name (obj_desc->region.space_id), + obj_desc->region.space_id); + + /* + * If the address and length have not been evaluated, + * don't print them. + */ + if (!(obj_desc->region.flags & AOPOBJ_DATA_VALID)) { + acpi_os_printf ("\n"); + } + else { + acpi_os_printf (" base %8.8X%8.8X Length %X\n", + ACPI_FORMAT_UINT64 (obj_desc->region.address), + obj_desc->region.length); + } + break; + + + case ACPI_TYPE_STRING: + + acpi_os_printf ("String length %X @ %p ", + obj_desc->string.length, obj_desc->string.pointer); + acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX); + acpi_os_printf ("\n"); + break; + + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + acpi_os_printf ("bank_field\n"); + break; + + + case ACPI_TYPE_LOCAL_REGION_FIELD: + + acpi_os_printf ( + "region_field: Bits=%X acc_width=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n", + obj_desc->field.bit_length, obj_desc->field.access_byte_width, + obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK, + obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK, + obj_desc->field.base_byte_offset, obj_desc->field.start_field_bit_offset); + acpi_ex_dump_operand (obj_desc->field.region_obj, depth+1); + break; + + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + acpi_os_printf ("index_field\n"); + break; + + + case ACPI_TYPE_BUFFER_FIELD: + + acpi_os_printf ( + "buffer_field: %X bits at byte %X bit %X of \n", + obj_desc->buffer_field.bit_length, obj_desc->buffer_field.base_byte_offset, + obj_desc->buffer_field.start_field_bit_offset); + + if (!obj_desc->buffer_field.buffer_obj) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*NULL* \n")); + } + else if (ACPI_GET_OBJECT_TYPE (obj_desc->buffer_field.buffer_obj) != ACPI_TYPE_BUFFER) { + acpi_os_printf ("*not a Buffer* \n"); + } + else { + acpi_ex_dump_operand (obj_desc->buffer_field.buffer_obj, depth+1); + } + break; + + + case ACPI_TYPE_EVENT: + + acpi_os_printf ("Event\n"); + break; + + + case ACPI_TYPE_METHOD: + + acpi_os_printf ( + "Method(%X) @ %p:%X\n", + obj_desc->method.param_count, + obj_desc->method.aml_start, obj_desc->method.aml_length); + break; + + + case ACPI_TYPE_MUTEX: + + acpi_os_printf ("Mutex\n"); + break; + + + case ACPI_TYPE_DEVICE: + + acpi_os_printf ("Device\n"); + break; + + + case ACPI_TYPE_POWER: + + acpi_os_printf ("Power\n"); + break; + + + case ACPI_TYPE_PROCESSOR: + + acpi_os_printf ("Processor\n"); + break; + + + case ACPI_TYPE_THERMAL: + + acpi_os_printf ("Thermal\n"); + break; + + + default: + /* Unknown Type */ + + acpi_os_printf ("Unknown Type %X\n", ACPI_GET_OBJECT_TYPE (obj_desc)); + break; + } + + return; +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ex_dump_operands + * + * PARAMETERS: Operands - Operand list + * interpreter_mode - Load or Exec + * Ident - Identification + * num_levels - # of stack entries to dump above line + * Note - Output notation + * module_name - Caller's module name + * line_number - Caller's invocation line number + * + * DESCRIPTION: Dump the object stack + * + ****************************************************************************/ + +void +acpi_ex_dump_operands ( + union acpi_operand_object **operands, + acpi_interpreter_mode interpreter_mode, + char *ident, + u32 num_levels, + char *note, + char *module_name, + u32 line_number) +{ + acpi_native_uint i; + + + ACPI_FUNCTION_NAME ("ex_dump_operands"); + + + if (!ident) { + ident = "?"; + } + + if (!note) { + note = "?"; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "************* Operand Stack Contents (Opcode [%s], %d Operands)\n", + ident, num_levels)); + + if (num_levels == 0) { + num_levels = 1; + } + + /* Dump the operand stack starting at the top */ + + for (i = 0; num_levels > 0; i--, num_levels--) { + acpi_ex_dump_operand (operands[i], 0); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "************* Stack dump from %s(%d), %s\n", + module_name, line_number, note)); + return; +} + + +#ifdef ACPI_FUTURE_USAGE + +/***************************************************************************** + * + * FUNCTION: acpi_ex_out* + * + * PARAMETERS: Title - Descriptive text + * Value - Value to be displayed + * + * DESCRIPTION: Object dump output formatting functions. These functions + * reduce the number of format strings required and keeps them + * all in one place for easy modification. + * + ****************************************************************************/ + +void +acpi_ex_out_string ( + char *title, + char *value) +{ + acpi_os_printf ("%20s : %s\n", title, value); +} + +void +acpi_ex_out_pointer ( + char *title, + void *value) +{ + acpi_os_printf ("%20s : %p\n", title, value); +} + +void +acpi_ex_out_integer ( + char *title, + u32 value) +{ + acpi_os_printf ("%20s : %X\n", title, value); +} + +void +acpi_ex_out_address ( + char *title, + acpi_physical_address value) +{ + +#if ACPI_MACHINE_WIDTH == 16 + acpi_os_printf ("%20s : %p\n", title, value); +#else + acpi_os_printf ("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64 (value)); +#endif +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ex_dump_node + * + * PARAMETERS: *Node - Descriptor to dump + * Flags - Force display + * + * DESCRIPTION: Dumps the members of the given.Node + * + ****************************************************************************/ + +void +acpi_ex_dump_node ( + struct acpi_namespace_node *node, + u32 flags) +{ + + ACPI_FUNCTION_ENTRY (); + + + if (!flags) { + if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { + return; + } + } + + acpi_os_printf ("%20s : %4.4s\n", "Name", acpi_ut_get_node_name (node)); + acpi_ex_out_string ("Type", acpi_ut_get_type_name (node->type)); + acpi_ex_out_integer ("Flags", node->flags); + acpi_ex_out_integer ("Owner Id", node->owner_id); + acpi_ex_out_integer ("Reference Count", node->reference_count); + acpi_ex_out_pointer ("Attached Object", acpi_ns_get_attached_object (node)); + acpi_ex_out_pointer ("child_list", node->child); + acpi_ex_out_pointer ("next_peer", node->peer); + acpi_ex_out_pointer ("Parent", acpi_ns_get_parent_node (node)); +} + + +/***************************************************************************** + * + * FUNCTION: acpi_ex_dump_object_descriptor + * + * PARAMETERS: *Object - Descriptor to dump + * Flags - Force display + * + * DESCRIPTION: Dumps the members of the object descriptor given. + * + ****************************************************************************/ + +void +acpi_ex_dump_object_descriptor ( + union acpi_operand_object *obj_desc, + u32 flags) +{ + u32 i; + + + ACPI_FUNCTION_TRACE ("ex_dump_object_descriptor"); + + + if (!flags) { + if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { + return_VOID; + } + } + + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) { + acpi_ex_dump_node ((struct acpi_namespace_node *) obj_desc, flags); + acpi_os_printf ("\nAttached Object (%p):\n", + ((struct acpi_namespace_node *) obj_desc)->object); + acpi_ex_dump_object_descriptor ( + ((struct acpi_namespace_node *) obj_desc)->object, flags); + return_VOID; + } + + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) { + acpi_os_printf ( + "ex_dump_object_descriptor: %p is not an ACPI operand object: [%s]\n", + obj_desc, acpi_ut_get_descriptor_name (obj_desc)); + return_VOID; + } + + /* Common Fields */ + + acpi_ex_out_string ("Type", acpi_ut_get_object_type_name (obj_desc)); + acpi_ex_out_integer ("Reference Count", obj_desc->common.reference_count); + acpi_ex_out_integer ("Flags", obj_desc->common.flags); + + /* Object-specific Fields */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_INTEGER: + + acpi_os_printf ("%20s : %8.8X%8.8X\n", "Value", + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); + break; + + + case ACPI_TYPE_STRING: + + acpi_ex_out_integer ("Length", obj_desc->string.length); + + acpi_os_printf ("%20s : %p ", "Pointer", obj_desc->string.pointer); + acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX); + acpi_os_printf ("\n"); + break; + + + case ACPI_TYPE_BUFFER: + + acpi_ex_out_integer ("Length", obj_desc->buffer.length); + acpi_ex_out_pointer ("Pointer", obj_desc->buffer.pointer); + ACPI_DUMP_BUFFER (obj_desc->buffer.pointer, obj_desc->buffer.length); + break; + + + case ACPI_TYPE_PACKAGE: + + acpi_ex_out_integer ("Flags", obj_desc->package.flags); + acpi_ex_out_integer ("Count", obj_desc->package.count); + acpi_ex_out_pointer ("Elements", obj_desc->package.elements); + + /* Dump the package contents */ + + if (obj_desc->package.count > 0) { + acpi_os_printf ("\nPackage Contents:\n"); + for (i = 0; i < obj_desc->package.count; i++) { + acpi_os_printf ("[%.3d] %p", i, obj_desc->package.elements[i]); + if (obj_desc->package.elements[i]) { + acpi_os_printf (" %s", + acpi_ut_get_object_type_name (obj_desc->package.elements[i])); + } + acpi_os_printf ("\n"); + } + } + break; + + + case ACPI_TYPE_DEVICE: + + acpi_ex_out_pointer ("Handler", obj_desc->device.handler); + acpi_ex_out_pointer ("system_notify", obj_desc->device.system_notify); + acpi_ex_out_pointer ("device_notify", obj_desc->device.device_notify); + break; + + + case ACPI_TYPE_EVENT: + + acpi_ex_out_pointer ("Semaphore", obj_desc->event.semaphore); + break; + + + case ACPI_TYPE_METHOD: + + acpi_ex_out_integer ("param_count", obj_desc->method.param_count); + acpi_ex_out_integer ("Concurrency", obj_desc->method.concurrency); + acpi_ex_out_pointer ("Semaphore", obj_desc->method.semaphore); + acpi_ex_out_integer ("owning_id", obj_desc->method.owning_id); + acpi_ex_out_integer ("aml_length", obj_desc->method.aml_length); + acpi_ex_out_pointer ("aml_start", obj_desc->method.aml_start); + break; + + + case ACPI_TYPE_MUTEX: + + acpi_ex_out_integer ("sync_level", obj_desc->mutex.sync_level); + acpi_ex_out_pointer ("owner_thread", obj_desc->mutex.owner_thread); + acpi_ex_out_integer ("acquire_depth", obj_desc->mutex.acquisition_depth); + acpi_ex_out_pointer ("Semaphore", obj_desc->mutex.semaphore); + break; + + + case ACPI_TYPE_REGION: + + acpi_ex_out_integer ("space_id", obj_desc->region.space_id); + acpi_ex_out_integer ("Flags", obj_desc->region.flags); + acpi_ex_out_address ("Address", obj_desc->region.address); + acpi_ex_out_integer ("Length", obj_desc->region.length); + acpi_ex_out_pointer ("Handler", obj_desc->region.handler); + acpi_ex_out_pointer ("Next", obj_desc->region.next); + break; + + + case ACPI_TYPE_POWER: + + acpi_ex_out_integer ("system_level", obj_desc->power_resource.system_level); + acpi_ex_out_integer ("resource_order", obj_desc->power_resource.resource_order); + acpi_ex_out_pointer ("system_notify", obj_desc->power_resource.system_notify); + acpi_ex_out_pointer ("device_notify", obj_desc->power_resource.device_notify); + break; + + + case ACPI_TYPE_PROCESSOR: + + acpi_ex_out_integer ("Processor ID", obj_desc->processor.proc_id); + acpi_ex_out_integer ("Length", obj_desc->processor.length); + acpi_ex_out_address ("Address", (acpi_physical_address) obj_desc->processor.address); + acpi_ex_out_pointer ("system_notify", obj_desc->processor.system_notify); + acpi_ex_out_pointer ("device_notify", obj_desc->processor.device_notify); + acpi_ex_out_pointer ("Handler", obj_desc->processor.handler); + break; + + + case ACPI_TYPE_THERMAL: + + acpi_ex_out_pointer ("system_notify", obj_desc->thermal_zone.system_notify); + acpi_ex_out_pointer ("device_notify", obj_desc->thermal_zone.device_notify); + acpi_ex_out_pointer ("Handler", obj_desc->thermal_zone.handler); + break; + + + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + acpi_ex_out_integer ("field_flags", obj_desc->common_field.field_flags); + acpi_ex_out_integer ("access_byte_width",obj_desc->common_field.access_byte_width); + acpi_ex_out_integer ("bit_length", obj_desc->common_field.bit_length); + acpi_ex_out_integer ("fld_bit_offset", obj_desc->common_field.start_field_bit_offset); + acpi_ex_out_integer ("base_byte_offset", obj_desc->common_field.base_byte_offset); + acpi_ex_out_pointer ("parent_node", obj_desc->common_field.node); + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_BUFFER_FIELD: + acpi_ex_out_pointer ("buffer_obj", obj_desc->buffer_field.buffer_obj); + break; + + case ACPI_TYPE_LOCAL_REGION_FIELD: + acpi_ex_out_pointer ("region_obj", obj_desc->field.region_obj); + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + acpi_ex_out_integer ("Value", obj_desc->bank_field.value); + acpi_ex_out_pointer ("region_obj", obj_desc->bank_field.region_obj); + acpi_ex_out_pointer ("bank_obj", obj_desc->bank_field.bank_obj); + break; + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + acpi_ex_out_integer ("Value", obj_desc->index_field.value); + acpi_ex_out_pointer ("Index", obj_desc->index_field.index_obj); + acpi_ex_out_pointer ("Data", obj_desc->index_field.data_obj); + break; + + default: + /* All object types covered above */ + break; + } + break; + + + case ACPI_TYPE_LOCAL_REFERENCE: + + acpi_ex_out_integer ("target_type", obj_desc->reference.target_type); + acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name); + acpi_ex_out_integer ("Offset", obj_desc->reference.offset); + acpi_ex_out_pointer ("obj_desc", obj_desc->reference.object); + acpi_ex_out_pointer ("Node", obj_desc->reference.node); + acpi_ex_out_pointer ("Where", obj_desc->reference.where); + break; + + + case ACPI_TYPE_LOCAL_ADDRESS_HANDLER: + + acpi_ex_out_integer ("space_id", obj_desc->address_space.space_id); + acpi_ex_out_pointer ("Next", obj_desc->address_space.next); + acpi_ex_out_pointer ("region_list", obj_desc->address_space.region_list); + acpi_ex_out_pointer ("Node", obj_desc->address_space.node); + acpi_ex_out_pointer ("Context", obj_desc->address_space.context); + break; + + + case ACPI_TYPE_LOCAL_NOTIFY: + + acpi_ex_out_pointer ("Node", obj_desc->notify.node); + acpi_ex_out_pointer ("Context", obj_desc->notify.context); + break; + + + case ACPI_TYPE_LOCAL_ALIAS: + case ACPI_TYPE_LOCAL_METHOD_ALIAS: + case ACPI_TYPE_LOCAL_EXTRA: + case ACPI_TYPE_LOCAL_DATA: + default: + + acpi_os_printf ( + "ex_dump_object_descriptor: Display not implemented for object type %s\n", + acpi_ut_get_object_type_name (obj_desc)); + break; + } + + return_VOID; +} + +#endif /* ACPI_FUTURE_USAGE */ + +#endif + diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c new file mode 100644 index 000000000000..be7f2124fa02 --- /dev/null +++ b/drivers/acpi/executer/exfield.c @@ -0,0 +1,367 @@ +/****************************************************************************** + * + * Module Name: exfield - ACPI AML (p-code) execution - field 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> +#include <acpi/acinterp.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exfield") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_read_data_from_field + * + * PARAMETERS: walk_state - Current execution state + * obj_desc - The named field + * ret_buffer_desc - Where the return data object is stored + * + * RETURN: Status + * + * DESCRIPTION: Read from a named field. Returns either an Integer or a + * Buffer, depending on the size of the field. + * + ******************************************************************************/ + +acpi_status +acpi_ex_read_data_from_field ( + struct acpi_walk_state *walk_state, + union acpi_operand_object *obj_desc, + union acpi_operand_object **ret_buffer_desc) +{ + acpi_status status; + union acpi_operand_object *buffer_desc; + acpi_size length; + void *buffer; + u8 locked; + + + ACPI_FUNCTION_TRACE_PTR ("ex_read_data_from_field", obj_desc); + + + /* Parameter validation */ + + if (!obj_desc) { + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_BUFFER_FIELD) { + /* + * If the buffer_field arguments have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_buffer_field_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + } + else if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) && + (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) { + /* + * This is an SMBus read. We must create a buffer to hold the data + * and directly access the region handler. + */ + buffer_desc = acpi_ut_create_buffer_object (ACPI_SMBUS_BUFFER_SIZE); + if (!buffer_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Lock entire transaction if requested */ + + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); + + /* + * Perform the read. + * Note: Smbus protocol value is passed in upper 16-bits of Function + */ + status = acpi_ex_access_region (obj_desc, 0, + ACPI_CAST_PTR (acpi_integer, buffer_desc->buffer.pointer), + ACPI_READ | (obj_desc->field.attribute << 16)); + acpi_ex_release_global_lock (locked); + goto exit; + } + + /* + * Allocate a buffer for the contents of the field. + * + * If the field is larger than the size of an acpi_integer, create + * a BUFFER to hold it. Otherwise, use an INTEGER. This allows + * the use of arithmetic operators on the returned value if the + * field size is equal or smaller than an Integer. + * + * Note: Field.length is in bits. + */ + length = (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->field.bit_length); + if (length > acpi_gbl_integer_byte_width) { + /* Field is too large for an Integer, create a Buffer instead */ + + buffer_desc = acpi_ut_create_buffer_object (length); + if (!buffer_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + buffer = buffer_desc->buffer.pointer; + } + else { + /* Field will fit within an Integer (normal case) */ + + buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!buffer_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + length = acpi_gbl_integer_byte_width; + buffer_desc->integer.value = 0; + buffer = &buffer_desc->integer.value; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "field_read [TO]: Obj %p, Type %X, Buf %p, byte_len %X\n", + obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc), buffer, (u32) length)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "field_read [FROM]: bit_len %X, bit_off %X, byte_off %X\n", + obj_desc->common_field.bit_length, + obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.base_byte_offset)); + + /* Lock entire transaction if requested */ + + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); + + /* Read from the field */ + + status = acpi_ex_extract_from_field (obj_desc, buffer, (u32) length); + acpi_ex_release_global_lock (locked); + + +exit: + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (buffer_desc); + } + else if (ret_buffer_desc) { + *ret_buffer_desc = buffer_desc; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_write_data_to_field + * + * PARAMETERS: source_desc - Contains data to write + * obj_desc - The named field + * + * RETURN: Status + * + * DESCRIPTION: Write to a named field + * + ******************************************************************************/ + +acpi_status +acpi_ex_write_data_to_field ( + union acpi_operand_object *source_desc, + union acpi_operand_object *obj_desc, + union acpi_operand_object **result_desc) +{ + acpi_status status; + u32 length; + u32 required_length; + void *buffer; + void *new_buffer; + u8 locked; + union acpi_operand_object *buffer_desc; + + + ACPI_FUNCTION_TRACE_PTR ("ex_write_data_to_field", obj_desc); + + + /* Parameter validation */ + + if (!source_desc || !obj_desc) { + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_BUFFER_FIELD) { + /* + * If the buffer_field arguments have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_buffer_field_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + } + else if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) && + (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) { + /* + * This is an SMBus write. We will bypass the entire field mechanism + * and handoff the buffer directly to the handler. + * + * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE). + */ + if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) { + ACPI_REPORT_ERROR (("SMBus write requires Buffer, found type %s\n", + acpi_ut_get_object_type_name (source_desc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) { + ACPI_REPORT_ERROR (("SMBus write requires Buffer of length %X, found length %X\n", + ACPI_SMBUS_BUFFER_SIZE, source_desc->buffer.length)); + return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); + } + + buffer_desc = acpi_ut_create_buffer_object (ACPI_SMBUS_BUFFER_SIZE); + if (!buffer_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + buffer = buffer_desc->buffer.pointer; + ACPI_MEMCPY (buffer, source_desc->buffer.pointer, ACPI_SMBUS_BUFFER_SIZE); + + /* Lock entire transaction if requested */ + + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); + + /* + * Perform the write (returns status and perhaps data in the same buffer) + * Note: SMBus protocol type is passed in upper 16-bits of Function. + */ + status = acpi_ex_access_region (obj_desc, 0, + (acpi_integer *) buffer, + ACPI_WRITE | (obj_desc->field.attribute << 16)); + acpi_ex_release_global_lock (locked); + + *result_desc = buffer_desc; + return_ACPI_STATUS (status); + } + + /* + * Get a pointer to the data to be written + */ + switch (ACPI_GET_OBJECT_TYPE (source_desc)) { + case ACPI_TYPE_INTEGER: + buffer = &source_desc->integer.value; + length = sizeof (source_desc->integer.value); + break; + + case ACPI_TYPE_BUFFER: + buffer = source_desc->buffer.pointer; + length = source_desc->buffer.length; + break; + + case ACPI_TYPE_STRING: + buffer = source_desc->string.pointer; + length = source_desc->string.length; + break; + + default: + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * We must have a buffer that is at least as long as the field + * we are writing to. This is because individual fields are + * indivisible and partial writes are not supported -- as per + * the ACPI specification. + */ + new_buffer = NULL; + required_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); + + if (length < required_length) { + /* We need to create a new buffer */ + + new_buffer = ACPI_MEM_CALLOCATE (required_length); + if (!new_buffer) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Copy the original data to the new buffer, starting + * at Byte zero. All unused (upper) bytes of the + * buffer will be 0. + */ + ACPI_MEMCPY ((char *) new_buffer, (char *) buffer, length); + buffer = new_buffer; + length = required_length; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n", + source_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (source_desc)), + ACPI_GET_OBJECT_TYPE (source_desc), buffer, length)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "field_write [TO]: Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n", + obj_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc)), + ACPI_GET_OBJECT_TYPE (obj_desc), + obj_desc->common_field.bit_length, + obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.base_byte_offset)); + + /* Lock entire transaction if requested */ + + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); + + /* Write to the field */ + + status = acpi_ex_insert_into_field (obj_desc, buffer, length); + acpi_ex_release_global_lock (locked); + + /* Free temporary buffer if we used one */ + + if (new_buffer) { + ACPI_MEM_FREE (new_buffer); + } + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c new file mode 100644 index 000000000000..9d0f9d2e9061 --- /dev/null +++ b/drivers/acpi/executer/exfldio.c @@ -0,0 +1,835 @@ +/****************************************************************************** + * + * Module Name: exfldio - Aml Field I/O + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/amlcode.h> +#include <acpi/acevents.h> +#include <acpi/acdispat.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exfldio") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_setup_region + * + * PARAMETERS: *obj_desc - Field to be read or written + * field_datum_byte_offset - Byte offset of this datum within the + * parent field + * + * RETURN: Status + * + * DESCRIPTION: Common processing for acpi_ex_extract_from_field and + * acpi_ex_insert_into_field. Initialize the Region if necessary and + * validate the request. + * + ******************************************************************************/ + +acpi_status +acpi_ex_setup_region ( + union acpi_operand_object *obj_desc, + u32 field_datum_byte_offset) +{ + acpi_status status = AE_OK; + union acpi_operand_object *rgn_desc; + + + ACPI_FUNCTION_TRACE_U32 ("ex_setup_region", field_datum_byte_offset); + + + rgn_desc = obj_desc->common_field.region_obj; + + /* We must have a valid region */ + + if (ACPI_GET_OBJECT_TYPE (rgn_desc) != ACPI_TYPE_REGION) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n", + ACPI_GET_OBJECT_TYPE (rgn_desc), + acpi_ut_get_object_type_name (rgn_desc))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * If the Region Address and Length have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_region_arguments (rgn_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { + /* SMBus has a non-linear address space */ + + return_ACPI_STATUS (AE_OK); + } + +#ifdef ACPI_UNDER_DEVELOPMENT + /* + * If the Field access is any_acc, we can now compute the optimal + * access (because we know know the length of the parent region) + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } +#endif + + /* + * Validate the request. The entire request from the byte offset for a + * length of one field datum (access width) must fit within the region. + * (Region length is specified in bytes) + */ + if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + + field_datum_byte_offset + + obj_desc->common_field.access_byte_width)) { + if (acpi_gbl_enable_interpreter_slack) { + /* + * Slack mode only: We will go ahead and allow access to this + * field if it is within the region length rounded up to the next + * access width boundary. + */ + if (ACPI_ROUND_UP (rgn_desc->region.length, + obj_desc->common_field.access_byte_width) >= + (obj_desc->common_field.base_byte_offset + + (acpi_native_uint) obj_desc->common_field.access_byte_width + + field_datum_byte_offset)) { + return_ACPI_STATUS (AE_OK); + } + } + + if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) { + /* + * This is the case where the access_type (acc_word, etc.) is wider + * than the region itself. For example, a region of length one + * byte, and a field with Dword access specified. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", + acpi_ut_get_node_name (obj_desc->common_field.node), + obj_desc->common_field.access_byte_width, + acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); + } + + /* + * Offset rounded up to next multiple of field width + * exceeds region length, indicate an error + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n", + acpi_ut_get_node_name (obj_desc->common_field.node), + obj_desc->common_field.base_byte_offset, + field_datum_byte_offset, obj_desc->common_field.access_byte_width, + acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length)); + + return_ACPI_STATUS (AE_AML_REGION_LIMIT); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_access_region + * + * PARAMETERS: *obj_desc - Field to be read + * field_datum_byte_offset - Byte offset of this datum within the + * parent field + * *Value - Where to store value (must at least + * the size of acpi_integer) + * Function - Read or Write flag plus other region- + * dependent flags + * + * RETURN: Status + * + * DESCRIPTION: Read or Write a single field datum to an Operation Region. + * + ******************************************************************************/ + +acpi_status +acpi_ex_access_region ( + union acpi_operand_object *obj_desc, + u32 field_datum_byte_offset, + acpi_integer *value, + u32 function) +{ + acpi_status status; + union acpi_operand_object *rgn_desc; + acpi_physical_address address; + + + ACPI_FUNCTION_TRACE ("ex_access_region"); + + + /* + * Ensure that the region operands are fully evaluated and verify + * the validity of the request + */ + status = acpi_ex_setup_region (obj_desc, field_datum_byte_offset); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * The physical address of this field datum is: + * + * 1) The base of the region, plus + * 2) The base offset of the field, plus + * 3) The current offset into the field + */ + rgn_desc = obj_desc->common_field.region_obj; + address = rgn_desc->region.address + + obj_desc->common_field.base_byte_offset + + field_datum_byte_offset; + + if ((function & ACPI_IO_MASK) == ACPI_READ) { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, + " Region [%s:%X], Width %X, byte_base %X, Offset %X at %8.8X%8.8X\n", + acpi_ut_get_region_name (rgn_desc->region.space_id), + rgn_desc->region.space_id, + obj_desc->common_field.access_byte_width, + obj_desc->common_field.base_byte_offset, + field_datum_byte_offset, + ACPI_FORMAT_UINT64 (address))); + + /* Invoke the appropriate address_space/op_region handler */ + + status = acpi_ev_address_space_dispatch (rgn_desc, function, + address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value); + + if (ACPI_FAILURE (status)) { + if (status == AE_NOT_IMPLEMENTED) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Region %s(%X) not implemented\n", + acpi_ut_get_region_name (rgn_desc->region.space_id), + rgn_desc->region.space_id)); + } + else if (status == AE_NOT_EXIST) { + ACPI_REPORT_ERROR (( + "Region %s(%X) has no handler\n", + acpi_ut_get_region_name (rgn_desc->region.space_id), + rgn_desc->region.space_id)); + } + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_register_overflow + * + * PARAMETERS: *obj_desc - Register(Field) to be written + * Value - Value to be stored + * + * RETURN: TRUE if value overflows the field, FALSE otherwise + * + * DESCRIPTION: Check if a value is out of range of the field being written. + * Used to check if the values written to Index and Bank registers + * are out of range. Normally, the value is simply truncated + * to fit the field, but this case is most likely a serious + * coding error in the ASL. + * + ******************************************************************************/ + +u8 +acpi_ex_register_overflow ( + union acpi_operand_object *obj_desc, + acpi_integer value) +{ + + if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) { + /* + * The field is large enough to hold the maximum integer, so we can + * never overflow it. + */ + return (FALSE); + } + + if (value >= ((acpi_integer) 1 << obj_desc->common_field.bit_length)) { + /* + * The Value is larger than the maximum value that can fit into + * the register. + */ + return (TRUE); + } + + /* The Value will fit into the field with no truncation */ + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_field_datum_io + * + * PARAMETERS: *obj_desc - Field to be read + * field_datum_byte_offset - Byte offset of this datum within the + * parent field + * *Value - Where to store value (must be 64 bits) + * read_write - Read or Write flag + * + * RETURN: Status + * + * DESCRIPTION: Read or Write a single datum of a field. The field_type is + * demultiplexed here to handle the different types of fields + * (buffer_field, region_field, index_field, bank_field) + * + ******************************************************************************/ + +acpi_status +acpi_ex_field_datum_io ( + union acpi_operand_object *obj_desc, + u32 field_datum_byte_offset, + acpi_integer *value, + u32 read_write) +{ + acpi_status status; + acpi_integer local_value; + + + ACPI_FUNCTION_TRACE_U32 ("ex_field_datum_io", field_datum_byte_offset); + + + if (read_write == ACPI_READ) { + if (!value) { + local_value = 0; + value = &local_value; /* To support reads without saving return value */ + } + + /* Clear the entire return buffer first, [Very Important!] */ + + *value = 0; + } + + /* + * The four types of fields are: + * + * buffer_field - Read/write from/to a Buffer + * region_field - Read/write from/to a Operation Region. + * bank_field - Write to a Bank Register, then read/write from/to an op_region + * index_field - Write to an Index Register, then read/write from/to a Data Register + */ + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_BUFFER_FIELD: + /* + * If the buffer_field arguments have not been previously evaluated, + * evaluate them now and save the results. + */ + if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = acpi_ds_get_buffer_field_arguments (obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + if (read_write == ACPI_READ) { + /* + * Copy the data from the source buffer. + * Length is the field width in bytes. + */ + ACPI_MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, + obj_desc->common_field.access_byte_width); + } + else { + /* + * Copy the data to the target buffer. + * Length is the field width in bytes. + */ + ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer + + obj_desc->buffer_field.base_byte_offset + + field_datum_byte_offset, + value, obj_desc->common_field.access_byte_width); + } + + status = AE_OK; + break; + + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + /* Ensure that the bank_value is not beyond the capacity of the register */ + + if (acpi_ex_register_overflow (obj_desc->bank_field.bank_obj, + (acpi_integer) obj_desc->bank_field.value)) { + return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); + } + + /* + * For bank_fields, we must write the bank_value to the bank_register + * (itself a region_field) before we can access the data. + */ + status = acpi_ex_insert_into_field (obj_desc->bank_field.bank_obj, + &obj_desc->bank_field.value, + sizeof (obj_desc->bank_field.value)); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Now that the Bank has been selected, fall through to the + * region_field case and write the datum to the Operation Region + */ + + /*lint -fallthrough */ + + + case ACPI_TYPE_LOCAL_REGION_FIELD: + /* + * For simple region_fields, we just directly access the owning + * Operation Region. + */ + status = acpi_ex_access_region (obj_desc, field_datum_byte_offset, value, + read_write); + break; + + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + + /* Ensure that the index_value is not beyond the capacity of the register */ + + if (acpi_ex_register_overflow (obj_desc->index_field.index_obj, + (acpi_integer) obj_desc->index_field.value)) { + return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); + } + + /* Write the index value to the index_register (itself a region_field) */ + + field_datum_byte_offset += obj_desc->index_field.value; + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Write to Index Register: Value %8.8X\n", + field_datum_byte_offset)); + + status = acpi_ex_insert_into_field (obj_desc->index_field.index_obj, + &field_datum_byte_offset, + sizeof (field_datum_byte_offset)); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "I/O to Data Register: value_ptr %p\n", + value)); + + if (read_write == ACPI_READ) { + /* Read the datum from the data_register */ + + status = acpi_ex_extract_from_field (obj_desc->index_field.data_obj, + value, sizeof (acpi_integer)); + } + else { + /* Write the datum to the data_register */ + + status = acpi_ex_insert_into_field (obj_desc->index_field.data_obj, + value, sizeof (acpi_integer)); + } + break; + + + default: + + ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n", + ACPI_GET_OBJECT_TYPE (obj_desc))); + status = AE_AML_INTERNAL; + break; + } + + if (ACPI_SUCCESS (status)) { + if (read_write == ACPI_READ) { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*value), + obj_desc->common_field.access_byte_width)); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*value), + obj_desc->common_field.access_byte_width)); + } + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_write_with_update_rule + * + * PARAMETERS: *obj_desc - Field to be set + * Value - Value to store + * + * RETURN: Status + * + * DESCRIPTION: Apply the field update rule to a field write + * + ******************************************************************************/ + +acpi_status +acpi_ex_write_with_update_rule ( + union acpi_operand_object *obj_desc, + acpi_integer mask, + acpi_integer field_value, + u32 field_datum_byte_offset) +{ + acpi_status status = AE_OK; + acpi_integer merged_value; + acpi_integer current_value; + + + ACPI_FUNCTION_TRACE_U32 ("ex_write_with_update_rule", mask); + + + /* Start with the new bits */ + + merged_value = field_value; + + /* If the mask is all ones, we don't need to worry about the update rule */ + + if (mask != ACPI_INTEGER_MAX) { + /* Decode the update rule */ + + switch (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK) { + case AML_FIELD_UPDATE_PRESERVE: + /* + * Check if update rule needs to be applied (not if mask is all + * ones) The left shift drops the bits we want to ignore. + */ + if ((~mask << (ACPI_MUL_8 (sizeof (mask)) - + ACPI_MUL_8 (obj_desc->common_field.access_byte_width))) != 0) { + /* + * Read the current contents of the byte/word/dword containing + * the field, and merge with the new field value. + */ + status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, + ¤t_value, ACPI_READ); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + merged_value |= (current_value & ~mask); + } + break; + + case AML_FIELD_UPDATE_WRITE_AS_ONES: + + /* Set positions outside the field to all ones */ + + merged_value |= ~mask; + break; + + case AML_FIELD_UPDATE_WRITE_AS_ZEROS: + + /* Set positions outside the field to all zeros */ + + merged_value &= mask; + break; + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "write_with_update_rule: Unknown update_rule setting: %X\n", + (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK))); + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Mask %8.8X%8.8X, datum_offset %X, Width %X, Value %8.8X%8.8X, merged_value %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (mask), + field_datum_byte_offset, + obj_desc->common_field.access_byte_width, + ACPI_FORMAT_UINT64 (field_value), + ACPI_FORMAT_UINT64 (merged_value))); + + /* Write the merged value */ + + status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset, + &merged_value, ACPI_WRITE); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_extract_from_field + * + * PARAMETERS: obj_desc - Field to be read + * Buffer - Where to store the field data + * buffer_length - Length of Buffer + * + * RETURN: Status + * + * DESCRIPTION: Retrieve the current value of the given field + * + ******************************************************************************/ + +acpi_status +acpi_ex_extract_from_field ( + union acpi_operand_object *obj_desc, + void *buffer, + u32 buffer_length) +{ + acpi_status status; + acpi_integer raw_datum; + acpi_integer merged_datum; + u32 field_offset = 0; + u32 buffer_offset = 0; + u32 buffer_tail_bits; + u32 datum_count; + u32 field_datum_count; + u32 i; + + + ACPI_FUNCTION_TRACE ("ex_extract_from_field"); + + + /* Validate target buffer and clear it */ + + if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.bit_length)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Field size %X (bits) is too large for buffer (%X)\n", + obj_desc->common_field.bit_length, buffer_length)); + + return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + } + ACPI_MEMSET (buffer, 0, buffer_length); + + /* Compute the number of datums (access width data items) */ + + datum_count = ACPI_ROUND_UP_TO ( + obj_desc->common_field.bit_length, + obj_desc->common_field.access_bit_width); + field_datum_count = ACPI_ROUND_UP_TO ( + obj_desc->common_field.bit_length + + obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.access_bit_width); + + /* Priming read from the field */ + + status = acpi_ex_field_datum_io (obj_desc, field_offset, &raw_datum, ACPI_READ); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; + + /* Read the rest of the field */ + + for (i = 1; i < field_datum_count; i++) { + /* Get next input datum from the field */ + + field_offset += obj_desc->common_field.access_byte_width; + status = acpi_ex_field_datum_io (obj_desc, field_offset, + &raw_datum, ACPI_READ); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Merge with previous datum if necessary */ + + merged_datum |= raw_datum << + (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); + + if (i == datum_count) { + break; + } + + /* Write merged datum to target buffer */ + + ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); + + buffer_offset += obj_desc->common_field.access_byte_width; + merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset; + } + + /* Mask off any extra bits in the last datum */ + + buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width; + if (buffer_tail_bits) { + merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); + } + + /* Write the last datum to the buffer */ + + ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_insert_into_field + * + * PARAMETERS: obj_desc - Field to be written + * Buffer - Data to be written + * buffer_length - Length of Buffer + * + * RETURN: Status + * + * DESCRIPTION: Store the Buffer contents into the given field + * + ******************************************************************************/ + +acpi_status +acpi_ex_insert_into_field ( + union acpi_operand_object *obj_desc, + void *buffer, + u32 buffer_length) +{ + acpi_status status; + acpi_integer mask; + acpi_integer merged_datum; + acpi_integer raw_datum = 0; + u32 field_offset = 0; + u32 buffer_offset = 0; + u32 buffer_tail_bits; + u32 datum_count; + u32 field_datum_count; + u32 i; + + + ACPI_FUNCTION_TRACE ("ex_insert_into_field"); + + + /* Validate input buffer */ + + if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.bit_length)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Field size %X (bits) is too large for buffer (%X)\n", + obj_desc->common_field.bit_length, buffer_length)); + + return_ACPI_STATUS (AE_BUFFER_OVERFLOW); + } + + /* Compute the number of datums (access width data items) */ + + mask = ACPI_MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset); + datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length, + obj_desc->common_field.access_bit_width); + field_datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length + + obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.access_bit_width); + + /* Get initial Datum from the input buffer */ + + ACPI_MEMCPY (&raw_datum, buffer, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); + + merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset; + + /* Write the entire field */ + + for (i = 1; i < field_datum_count; i++) { + /* Write merged datum to the target field */ + + merged_datum &= mask; + status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Start new output datum by merging with previous input datum */ + + field_offset += obj_desc->common_field.access_byte_width; + merged_datum = raw_datum >> + (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset); + mask = ACPI_INTEGER_MAX; + + if (i == datum_count) { + break; + } + + /* Get the next input datum from the buffer */ + + buffer_offset += obj_desc->common_field.access_byte_width; + ACPI_MEMCPY (&raw_datum, ((char *) buffer) + buffer_offset, + ACPI_MIN(obj_desc->common_field.access_byte_width, + buffer_length - buffer_offset)); + merged_datum |= raw_datum << obj_desc->common_field.start_field_bit_offset; + } + + /* Mask off any extra bits in the last datum */ + + buffer_tail_bits = (obj_desc->common_field.bit_length + + obj_desc->common_field.start_field_bit_offset) % obj_desc->common_field.access_bit_width; + if (buffer_tail_bits) { + mask &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits); + } + + /* Write the last datum to the field */ + + merged_datum &= mask; + status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset); + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c new file mode 100644 index 000000000000..b542dcd58c07 --- /dev/null +++ b/drivers/acpi/executer/exmisc.c @@ -0,0 +1,738 @@ + +/****************************************************************************** + * + * Module Name: exmisc - ACPI AML (p-code) execution - specific 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/acinterp.h> +#include <acpi/amlcode.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exmisc") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_get_object_reference + * + * PARAMETERS: obj_desc - Create a reference to this object + * return_desc - Where to store the reference + * walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Obtain and return a "reference" to the target object + * Common code for the ref_of_op and the cond_ref_of_op. + * + ******************************************************************************/ + +acpi_status +acpi_ex_get_object_reference ( + union acpi_operand_object *obj_desc, + union acpi_operand_object **return_desc, + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *reference_obj; + union acpi_operand_object *referenced_obj; + + + ACPI_FUNCTION_TRACE_PTR ("ex_get_object_reference", obj_desc); + + + *return_desc = NULL; + + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { + case ACPI_DESC_TYPE_OPERAND: + + if (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_LOCAL_REFERENCE) { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * Must be a reference to a Local or Arg + */ + switch (obj_desc->reference.opcode) { + case AML_LOCAL_OP: + case AML_ARG_OP: + case AML_DEBUG_OP: + + /* The referenced object is the pseudo-node for the local/arg */ + + referenced_obj = obj_desc->reference.object; + break; + + default: + + ACPI_REPORT_ERROR (("Unknown Reference opcode in get_reference %X\n", + obj_desc->reference.opcode)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + break; + + + case ACPI_DESC_TYPE_NAMED: + + /* + * A named reference that has already been resolved to a Node + */ + referenced_obj = obj_desc; + break; + + + default: + + ACPI_REPORT_ERROR (("Invalid descriptor type in get_reference: %X\n", + ACPI_GET_DESCRIPTOR_TYPE (obj_desc))); + return_ACPI_STATUS (AE_TYPE); + } + + + /* Create a new reference object */ + + reference_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_REFERENCE); + if (!reference_obj) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + reference_obj->reference.opcode = AML_REF_OF_OP; + reference_obj->reference.object = referenced_obj; + *return_desc = reference_obj; + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object %p Type [%s], returning Reference %p\n", + obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_concat_template + * + * PARAMETERS: Operand0 - First source object + * Operand1 - Second source object + * actual_return_desc - Where to place the return object + * walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Concatenate two resource templates + * + ******************************************************************************/ + +acpi_status +acpi_ex_concat_template ( + union acpi_operand_object *operand0, + union acpi_operand_object *operand1, + union acpi_operand_object **actual_return_desc, + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *return_desc; + u8 *new_buf; + u8 *end_tag1; + u8 *end_tag2; + acpi_size length1; + acpi_size length2; + + + ACPI_FUNCTION_TRACE ("ex_concat_template"); + + + /* Find the end_tags in each resource template */ + + end_tag1 = acpi_ut_get_resource_end_tag (operand0); + end_tag2 = acpi_ut_get_resource_end_tag (operand1); + if (!end_tag1 || !end_tag2) { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Compute the length of each part */ + + length1 = ACPI_PTR_DIFF (end_tag1, operand0->buffer.pointer); + length2 = ACPI_PTR_DIFF (end_tag2, operand1->buffer.pointer) + + 2; /* Size of END_TAG */ + + /* Create a new buffer object for the result */ + + return_desc = acpi_ut_create_buffer_object (length1 + length2); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Copy the templates to the new descriptor */ + + new_buf = return_desc->buffer.pointer; + ACPI_MEMCPY (new_buf, operand0->buffer.pointer, length1); + ACPI_MEMCPY (new_buf + length1, operand1->buffer.pointer, length2); + + /* Compute the new checksum */ + + new_buf[return_desc->buffer.length - 1] = + acpi_ut_generate_checksum (return_desc->buffer.pointer, + (return_desc->buffer.length - 1)); + + /* Return the completed template descriptor */ + + *actual_return_desc = return_desc; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_do_concatenate + * + * PARAMETERS: Operand0 - First source object + * Operand1 - Second source object + * actual_return_desc - Where to place the return object + * walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Concatenate two objects OF THE SAME TYPE. + * + ******************************************************************************/ + +acpi_status +acpi_ex_do_concatenate ( + union acpi_operand_object *operand0, + union acpi_operand_object *operand1, + union acpi_operand_object **actual_return_desc, + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *local_operand1 = operand1; + union acpi_operand_object *return_desc; + char *new_buf; + acpi_status status; + acpi_size new_length; + + + ACPI_FUNCTION_TRACE ("ex_do_concatenate"); + + + /* + * Convert the second operand if necessary. The first operand + * determines the type of the second operand, (See the Data Types + * section of the ACPI specification.) Both object types are + * guaranteed to be either Integer/String/Buffer by the operand + * resolution mechanism. + */ + switch (ACPI_GET_OBJECT_TYPE (operand0)) { + case ACPI_TYPE_INTEGER: + status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16); + break; + + case ACPI_TYPE_STRING: + status = acpi_ex_convert_to_string (operand1, &local_operand1, + ACPI_IMPLICIT_CONVERT_HEX); + break; + + case ACPI_TYPE_BUFFER: + status = acpi_ex_convert_to_buffer (operand1, &local_operand1); + break; + + default: + ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n", + ACPI_GET_OBJECT_TYPE (operand0))); + status = AE_AML_INTERNAL; + } + + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* + * Both operands are now known to be the same object type + * (Both are Integer, String, or Buffer), and we can now perform the + * concatenation. + */ + + /* + * There are three cases to handle: + * + * 1) Two Integers concatenated to produce a new Buffer + * 2) Two Strings concatenated to produce a new String + * 3) Two Buffers concatenated to produce a new Buffer + */ + switch (ACPI_GET_OBJECT_TYPE (operand0)) { + case ACPI_TYPE_INTEGER: + + /* Result of two Integers is a Buffer */ + /* Need enough buffer space for two integers */ + + return_desc = acpi_ut_create_buffer_object ( + ACPI_MUL_2 (acpi_gbl_integer_byte_width)); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + new_buf = (char *) return_desc->buffer.pointer; + + /* Copy the first integer, LSB first */ + + ACPI_MEMCPY (new_buf, + &operand0->integer.value, + acpi_gbl_integer_byte_width); + + /* Copy the second integer (LSB first) after the first */ + + ACPI_MEMCPY (new_buf + acpi_gbl_integer_byte_width, + &local_operand1->integer.value, + acpi_gbl_integer_byte_width); + break; + + case ACPI_TYPE_STRING: + + /* Result of two Strings is a String */ + + new_length = (acpi_size) operand0->string.length + + (acpi_size) local_operand1->string.length; + if (new_length > ACPI_MAX_STRING_CONVERSION) { + status = AE_AML_STRING_LIMIT; + goto cleanup; + } + + return_desc = acpi_ut_create_string_object (new_length); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + new_buf = return_desc->string.pointer; + + /* Concatenate the strings */ + + ACPI_STRCPY (new_buf, + operand0->string.pointer); + ACPI_STRCPY (new_buf + operand0->string.length, + local_operand1->string.pointer); + break; + + case ACPI_TYPE_BUFFER: + + /* Result of two Buffers is a Buffer */ + + return_desc = acpi_ut_create_buffer_object ( + (acpi_size) operand0->buffer.length + + (acpi_size) local_operand1->buffer.length); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + new_buf = (char *) return_desc->buffer.pointer; + + /* Concatenate the buffers */ + + ACPI_MEMCPY (new_buf, + operand0->buffer.pointer, + operand0->buffer.length); + ACPI_MEMCPY (new_buf + operand0->buffer.length, + local_operand1->buffer.pointer, + local_operand1->buffer.length); + break; + + default: + + /* Invalid object type, should not happen here */ + + ACPI_REPORT_ERROR (("Concatenate - Invalid object type: %X\n", + ACPI_GET_OBJECT_TYPE (operand0))); + status =AE_AML_INTERNAL; + goto cleanup; + } + + *actual_return_desc = return_desc; + +cleanup: + if (local_operand1 != operand1) { + acpi_ut_remove_reference (local_operand1); + } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_do_math_op + * + * PARAMETERS: Opcode - AML opcode + * Integer0 - Integer operand #0 + * Integer1 - Integer operand #1 + * + * RETURN: Integer result of the operation + * + * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the + * math functions here is to prevent a lot of pointer dereferencing + * to obtain the operands. + * + ******************************************************************************/ + +acpi_integer +acpi_ex_do_math_op ( + u16 opcode, + acpi_integer integer0, + acpi_integer integer1) +{ + + ACPI_FUNCTION_ENTRY (); + + + switch (opcode) { + case AML_ADD_OP: /* Add (Integer0, Integer1, Result) */ + + return (integer0 + integer1); + + + case AML_BIT_AND_OP: /* And (Integer0, Integer1, Result) */ + + return (integer0 & integer1); + + + case AML_BIT_NAND_OP: /* NAnd (Integer0, Integer1, Result) */ + + return (~(integer0 & integer1)); + + + case AML_BIT_OR_OP: /* Or (Integer0, Integer1, Result) */ + + return (integer0 | integer1); + + + case AML_BIT_NOR_OP: /* NOr (Integer0, Integer1, Result) */ + + return (~(integer0 | integer1)); + + + case AML_BIT_XOR_OP: /* XOr (Integer0, Integer1, Result) */ + + return (integer0 ^ integer1); + + + case AML_MULTIPLY_OP: /* Multiply (Integer0, Integer1, Result) */ + + return (integer0 * integer1); + + + case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */ + + return (integer0 << integer1); + + + case AML_SHIFT_RIGHT_OP: /* shift_right (Operand, shift_count, Result) */ + + return (integer0 >> integer1); + + + case AML_SUBTRACT_OP: /* Subtract (Integer0, Integer1, Result) */ + + return (integer0 - integer1); + + default: + + return (0); + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_do_logical_numeric_op + * + * PARAMETERS: Opcode - AML opcode + * Integer0 - Integer operand #0 + * Integer1 - Integer operand #1 + * logical_result - TRUE/FALSE result of the operation + * + * RETURN: Status + * + * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric + * operators (LAnd and LOr), both operands must be integers. + * + * Note: cleanest machine code seems to be produced by the code + * below, rather than using statements of the form: + * Result = (Integer0 && Integer1); + * + ******************************************************************************/ + +acpi_status +acpi_ex_do_logical_numeric_op ( + u16 opcode, + acpi_integer integer0, + acpi_integer integer1, + u8 *logical_result) +{ + acpi_status status = AE_OK; + u8 local_result = FALSE; + + + ACPI_FUNCTION_TRACE ("ex_do_logical_numeric_op"); + + + switch (opcode) { + case AML_LAND_OP: /* LAnd (Integer0, Integer1) */ + + if (integer0 && integer1) { + local_result = TRUE; + } + break; + + case AML_LOR_OP: /* LOr (Integer0, Integer1) */ + + if (integer0 || integer1) { + local_result = TRUE; + } + break; + + default: + status = AE_AML_INTERNAL; + break; + } + + /* Return the logical result and status */ + + *logical_result = local_result; + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_do_logical_op + * + * PARAMETERS: Opcode - AML opcode + * Operand0 - operand #0 + * Operand1 - operand #1 + * logical_result - TRUE/FALSE result of the operation + * + * RETURN: Status + * + * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the + * functions here is to prevent a lot of pointer dereferencing + * to obtain the operands and to simplify the generation of the + * logical value. For the Numeric operators (LAnd and LOr), both + * operands must be integers. For the other logical operators, + * operands can be any combination of Integer/String/Buffer. The + * first operand determines the type to which the second operand + * will be converted. + * + * Note: cleanest machine code seems to be produced by the code + * below, rather than using statements of the form: + * Result = (Operand0 == Operand1); + * + ******************************************************************************/ + +acpi_status +acpi_ex_do_logical_op ( + u16 opcode, + union acpi_operand_object *operand0, + union acpi_operand_object *operand1, + u8 *logical_result) +{ + union acpi_operand_object *local_operand1 = operand1; + acpi_integer integer0; + acpi_integer integer1; + u32 length0; + u32 length1; + acpi_status status = AE_OK; + u8 local_result = FALSE; + int compare; + + + ACPI_FUNCTION_TRACE ("ex_do_logical_op"); + + + /* + * Convert the second operand if necessary. The first operand + * determines the type of the second operand, (See the Data Types + * section of the ACPI 3.0+ specification.) Both object types are + * guaranteed to be either Integer/String/Buffer by the operand + * resolution mechanism. + */ + switch (ACPI_GET_OBJECT_TYPE (operand0)) { + case ACPI_TYPE_INTEGER: + status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16); + break; + + case ACPI_TYPE_STRING: + status = acpi_ex_convert_to_string (operand1, &local_operand1, + ACPI_IMPLICIT_CONVERT_HEX); + break; + + case ACPI_TYPE_BUFFER: + status = acpi_ex_convert_to_buffer (operand1, &local_operand1); + break; + + default: + status = AE_AML_INTERNAL; + break; + } + + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* + * Two cases: 1) Both Integers, 2) Both Strings or Buffers + */ + if (ACPI_GET_OBJECT_TYPE (operand0) == ACPI_TYPE_INTEGER) { + /* + * 1) Both operands are of type integer + * Note: local_operand1 may have changed above + */ + integer0 = operand0->integer.value; + integer1 = local_operand1->integer.value; + + switch (opcode) { + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + + if (integer0 == integer1) { + local_result = TRUE; + } + break; + + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + + if (integer0 > integer1) { + local_result = TRUE; + } + break; + + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + + if (integer0 < integer1) { + local_result = TRUE; + } + break; + + default: + status = AE_AML_INTERNAL; + break; + } + } + else { + /* + * 2) Both operands are Strings or both are Buffers + * Note: Code below takes advantage of common Buffer/String + * object fields. local_operand1 may have changed above. Use + * memcmp to handle nulls in buffers. + */ + length0 = operand0->buffer.length; + length1 = local_operand1->buffer.length; + + /* Lexicographic compare: compare the data bytes */ + + compare = ACPI_MEMCMP ((const char * ) operand0->buffer.pointer, + (const char * ) local_operand1->buffer.pointer, + (length0 > length1) ? length1 : length0); + + switch (opcode) { + case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ + + /* Length and all bytes must be equal */ + + if ((length0 == length1) && + (compare == 0)) { + /* Length and all bytes match ==> TRUE */ + + local_result = TRUE; + } + break; + + case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ + + if (compare > 0) { + local_result = TRUE; + goto cleanup; /* TRUE */ + } + if (compare < 0) { + goto cleanup; /* FALSE */ + } + + /* Bytes match (to shortest length), compare lengths */ + + if (length0 > length1) { + local_result = TRUE; + } + break; + + case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ + + if (compare > 0) { + goto cleanup; /* FALSE */ + } + if (compare < 0) { + local_result = TRUE; + goto cleanup; /* TRUE */ + } + + /* Bytes match (to shortest length), compare lengths */ + + if (length0 < length1) { + local_result = TRUE; + } + break; + + default: + status = AE_AML_INTERNAL; + break; + } + } + +cleanup: + + /* New object was created if implicit conversion performed - delete */ + + if (local_operand1 != operand1) { + acpi_ut_remove_reference (local_operand1); + } + + /* Return the logical result and status */ + + *logical_result = local_result; + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c new file mode 100644 index 000000000000..68c4bb1970a5 --- /dev/null +++ b/drivers/acpi/executer/exmutex.c @@ -0,0 +1,363 @@ + +/****************************************************************************** + * + * Module Name: exmutex - ASL Mutex Acquire/Release functions + * + *****************************************************************************/ + +/* + * 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/acinterp.h> + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exmutex") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_unlink_mutex + * + * PARAMETERS: obj_desc - The mutex to be unlinked + * + * RETURN: Status + * + * DESCRIPTION: Remove a mutex from the "acquired_mutex" list + * + ******************************************************************************/ + +void +acpi_ex_unlink_mutex ( + union acpi_operand_object *obj_desc) +{ + struct acpi_thread_state *thread = obj_desc->mutex.owner_thread; + + + if (!thread) { + return; + } + + /* Doubly linked list */ + + if (obj_desc->mutex.next) { + (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev; + } + + if (obj_desc->mutex.prev) { + (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; + } + else { + thread->acquired_mutex_list = obj_desc->mutex.next; + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_link_mutex + * + * PARAMETERS: obj_desc - The mutex to be linked + * list_head - head of the "acquired_mutex" list + * + * RETURN: Status + * + * DESCRIPTION: Add a mutex to the "acquired_mutex" list for this walk + * + ******************************************************************************/ + +void +acpi_ex_link_mutex ( + union acpi_operand_object *obj_desc, + struct acpi_thread_state *thread) +{ + union acpi_operand_object *list_head; + + + list_head = thread->acquired_mutex_list; + + /* This object will be the first object in the list */ + + obj_desc->mutex.prev = NULL; + obj_desc->mutex.next = list_head; + + /* Update old first object to point back to this object */ + + if (list_head) { + list_head->mutex.prev = obj_desc; + } + + /* Update list head */ + + thread->acquired_mutex_list = obj_desc; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_acquire_mutex + * + * PARAMETERS: time_desc - The 'time to delay' object descriptor + * obj_desc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Acquire an AML mutex + * + ******************************************************************************/ + +acpi_status +acpi_ex_acquire_mutex ( + union acpi_operand_object *time_desc, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ex_acquire_mutex", obj_desc); + + + if (!obj_desc) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Sanity check -- we must have a valid thread ID */ + + if (!walk_state->thread) { + ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], null thread info\n", + acpi_ut_get_node_name (obj_desc->mutex.node))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* + * Current Sync must be less than or equal to the sync level of the + * mutex. This mechanism provides some deadlock prevention + */ + if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) { + ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], incorrect sync_level\n", + acpi_ut_get_node_name (obj_desc->mutex.node))); + return_ACPI_STATUS (AE_AML_MUTEX_ORDER); + } + + /* Support for multiple acquires by the owning thread */ + + if (obj_desc->mutex.owner_thread) { + /* Special case for Global Lock, allow all threads */ + + if ((obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id) || + (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore)) { + /* + * The mutex is already owned by this thread, + * just increment the acquisition depth + */ + obj_desc->mutex.acquisition_depth++; + return_ACPI_STATUS (AE_OK); + } + } + + /* Acquire the mutex, wait if necessary */ + + status = acpi_ex_system_acquire_mutex (time_desc, obj_desc); + if (ACPI_FAILURE (status)) { + /* Includes failure from a timeout on time_desc */ + + return_ACPI_STATUS (status); + } + + /* Have the mutex: update mutex and walk info and save the sync_level */ + + obj_desc->mutex.owner_thread = walk_state->thread; + obj_desc->mutex.acquisition_depth = 1; + obj_desc->mutex.original_sync_level = walk_state->thread->current_sync_level; + + walk_state->thread->current_sync_level = obj_desc->mutex.sync_level; + + /* Link the mutex to the current thread for force-unlock at method exit */ + + acpi_ex_link_mutex (obj_desc, walk_state->thread); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_release_mutex + * + * PARAMETERS: obj_desc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Release a previously acquired Mutex. + * + ******************************************************************************/ + +acpi_status +acpi_ex_release_mutex ( + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ex_release_mutex"); + + + if (!obj_desc) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* The mutex must have been previously acquired in order to release it */ + + if (!obj_desc->mutex.owner_thread) { + ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], not acquired\n", + acpi_ut_get_node_name (obj_desc->mutex.node))); + return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED); + } + + /* Sanity check -- we must have a valid thread ID */ + + if (!walk_state->thread) { + ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], null thread info\n", + acpi_ut_get_node_name (obj_desc->mutex.node))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* + * The Mutex is owned, but this thread must be the owner. + * Special case for Global Lock, any thread can release + */ + if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) && + (obj_desc->mutex.semaphore != acpi_gbl_global_lock_semaphore)) { + ACPI_REPORT_ERROR (( + "Thread %X cannot release Mutex [%4.4s] acquired by thread %X\n", + walk_state->thread->thread_id, + acpi_ut_get_node_name (obj_desc->mutex.node), + obj_desc->mutex.owner_thread->thread_id)); + return_ACPI_STATUS (AE_AML_NOT_OWNER); + } + + /* + * The sync level of the mutex must be less than or + * equal to the current sync level + */ + if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { + ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], incorrect sync_level\n", + acpi_ut_get_node_name (obj_desc->mutex.node))); + return_ACPI_STATUS (AE_AML_MUTEX_ORDER); + } + + /* Match multiple Acquires with multiple Releases */ + + obj_desc->mutex.acquisition_depth--; + if (obj_desc->mutex.acquisition_depth != 0) { + /* Just decrement the depth and return */ + + return_ACPI_STATUS (AE_OK); + } + + /* Unlink the mutex from the owner's list */ + + acpi_ex_unlink_mutex (obj_desc); + + /* Release the mutex */ + + status = acpi_ex_system_release_mutex (obj_desc); + + /* Update the mutex and walk state, restore sync_level before acquire */ + + obj_desc->mutex.owner_thread = NULL; + walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level; + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_release_all_mutexes + * + * PARAMETERS: mutex_list - Head of the mutex list + * + * RETURN: Status + * + * DESCRIPTION: Release all mutexes in the list + * + ******************************************************************************/ + +void +acpi_ex_release_all_mutexes ( + struct acpi_thread_state *thread) +{ + union acpi_operand_object *next = thread->acquired_mutex_list; + union acpi_operand_object *this; + acpi_status status; + + + ACPI_FUNCTION_ENTRY (); + + + /* Traverse the list of owned mutexes, releasing each one */ + + while (next) { + this = next; + next = this->mutex.next; + + this->mutex.acquisition_depth = 1; + this->mutex.prev = NULL; + this->mutex.next = NULL; + + /* Release the mutex */ + + status = acpi_ex_system_release_mutex (this); + if (ACPI_FAILURE (status)) { + continue; + } + + /* Mark mutex unowned */ + + this->mutex.owner_thread = NULL; + + /* Update Thread sync_level (Last mutex is the important one) */ + + thread->current_sync_level = this->mutex.original_sync_level; + } +} + + diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c new file mode 100644 index 000000000000..7911c533c265 --- /dev/null +++ b/drivers/acpi/executer/exnames.c @@ -0,0 +1,427 @@ + +/****************************************************************************** + * + * Module Name: exnames - interpreter/scanner name load/execute + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/amlcode.h> + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exnames") + + +/* AML Package Length encodings */ + +#define ACPI_AML_PACKAGE_TYPE1 0x40 +#define ACPI_AML_PACKAGE_TYPE2 0x4000 +#define ACPI_AML_PACKAGE_TYPE3 0x400000 +#define ACPI_AML_PACKAGE_TYPE4 0x40000000 + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_allocate_name_string + * + * PARAMETERS: prefix_count - Count of parent levels. Special cases: + * (-1) = root, 0 = none + * num_name_segs - count of 4-character name segments + * + * RETURN: A pointer to the allocated string segment. This segment must + * be deleted by the caller. + * + * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name + * string is long enough, and set up prefix if any. + * + ******************************************************************************/ + +char * +acpi_ex_allocate_name_string ( + u32 prefix_count, + u32 num_name_segs) +{ + char *temp_ptr; + char *name_string; + u32 size_needed; + + ACPI_FUNCTION_TRACE ("ex_allocate_name_string"); + + + /* + * Allow room for all \ and ^ prefixes, all segments, and a multi_name_prefix. + * Also, one byte for the null terminator. + * This may actually be somewhat longer than needed. + */ + if (prefix_count == ACPI_UINT32_MAX) { + /* Special case for root */ + + size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; + } + else { + size_needed = prefix_count + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1; + } + + /* + * Allocate a buffer for the name. + * This buffer must be deleted by the caller! + */ + name_string = ACPI_MEM_ALLOCATE (size_needed); + if (!name_string) { + ACPI_REPORT_ERROR (("ex_allocate_name_string: Could not allocate size %d\n", size_needed)); + return_PTR (NULL); + } + + temp_ptr = name_string; + + /* Set up Root or Parent prefixes if needed */ + + if (prefix_count == ACPI_UINT32_MAX) { + *temp_ptr++ = AML_ROOT_PREFIX; + } + else { + while (prefix_count--) { + *temp_ptr++ = AML_PARENT_PREFIX; + } + } + + + /* Set up Dual or Multi prefixes if needed */ + + if (num_name_segs > 2) { + /* Set up multi prefixes */ + + *temp_ptr++ = AML_MULTI_NAME_PREFIX_OP; + *temp_ptr++ = (char) num_name_segs; + } + else if (2 == num_name_segs) { + /* Set up dual prefixes */ + + *temp_ptr++ = AML_DUAL_NAME_PREFIX; + } + + /* + * Terminate string following prefixes. acpi_ex_name_segment() will + * append the segment(s) + */ + *temp_ptr = 0; + + return_PTR (name_string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_name_segment + * + * PARAMETERS: interpreter_mode - Current running mode (load1/Load2/Exec) + * + * RETURN: Status + * + * DESCRIPTION: Execute a name segment (4 bytes) + * + ******************************************************************************/ + +acpi_status +acpi_ex_name_segment ( + u8 **in_aml_address, + char *name_string) +{ + char *aml_address = (void *) *in_aml_address; + acpi_status status = AE_OK; + u32 index; + char char_buf[5]; + + + ACPI_FUNCTION_TRACE ("ex_name_segment"); + + + /* + * If first character is a digit, then we know that we aren't looking at a + * valid name segment + */ + char_buf[0] = *aml_address; + + if ('0' <= char_buf[0] && char_buf[0] <= '9') { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "leading digit: %c\n", char_buf[0])); + return_ACPI_STATUS (AE_CTRL_PENDING); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Bytes from stream:\n")); + + for (index = 0; + (index < ACPI_NAME_SIZE) && (acpi_ut_valid_acpi_character (*aml_address)); + index++) { + char_buf[index] = *aml_address++; + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "%c\n", char_buf[index])); + } + + + /* Valid name segment */ + + if (index == 4) { + /* Found 4 valid characters */ + + char_buf[4] = '\0'; + + if (name_string) { + ACPI_STRCAT (name_string, char_buf); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Appended to - %s \n", name_string)); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "No Name string - %s \n", char_buf)); + } + } + else if (index == 0) { + /* + * First character was not a valid name character, + * so we are looking at something other than a name. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Leading character is not alpha: %02Xh (not a name)\n", + char_buf[0])); + status = AE_CTRL_PENDING; + } + else { + /* Segment started with one or more valid characters, but fewer than 4 */ + + status = AE_AML_BAD_NAME; + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad character %02x in name, at %p\n", + *aml_address, aml_address)); + } + + *in_aml_address = (u8 *) aml_address; + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_get_name_string + * + * PARAMETERS: data_type - Data type to be associated with this name + * + * RETURN: Status + * + * DESCRIPTION: Get a name, including any prefixes. + * + ******************************************************************************/ + +acpi_status +acpi_ex_get_name_string ( + acpi_object_type data_type, + u8 *in_aml_address, + char **out_name_string, + u32 *out_name_length) +{ + acpi_status status = AE_OK; + u8 *aml_address = in_aml_address; + char *name_string = NULL; + u32 num_segments; + u32 prefix_count = 0; + u8 has_prefix = FALSE; + + + ACPI_FUNCTION_TRACE_PTR ("ex_get_name_string", aml_address); + + + if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type || + ACPI_TYPE_LOCAL_BANK_FIELD == data_type || + ACPI_TYPE_LOCAL_INDEX_FIELD == data_type) { + /* Disallow prefixes for types associated with field_unit names */ + + name_string = acpi_ex_allocate_name_string (0, 1); + if (!name_string) { + status = AE_NO_MEMORY; + } + else { + status = acpi_ex_name_segment (&aml_address, name_string); + } + } + else { + /* + * data_type is not a field name. + * Examine first character of name for root or parent prefix operators + */ + switch (*aml_address) { + case AML_ROOT_PREFIX: + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "root_prefix(\\) at %p\n", aml_address)); + + /* + * Remember that we have a root_prefix -- + * see comment in acpi_ex_allocate_name_string() + */ + aml_address++; + prefix_count = ACPI_UINT32_MAX; + has_prefix = TRUE; + break; + + + case AML_PARENT_PREFIX: + + /* Increment past possibly multiple parent prefixes */ + + do { + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "parent_prefix (^) at %p\n", aml_address)); + + aml_address++; + prefix_count++; + + } while (*aml_address == AML_PARENT_PREFIX); + + has_prefix = TRUE; + break; + + + default: + + /* Not a prefix character */ + + break; + } + + + /* Examine first character of name for name segment prefix operator */ + + switch (*aml_address) { + case AML_DUAL_NAME_PREFIX: + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "dual_name_prefix at %p\n", aml_address)); + + aml_address++; + name_string = acpi_ex_allocate_name_string (prefix_count, 2); + if (!name_string) { + status = AE_NO_MEMORY; + break; + } + + /* Indicate that we processed a prefix */ + + has_prefix = TRUE; + + status = acpi_ex_name_segment (&aml_address, name_string); + if (ACPI_SUCCESS (status)) { + status = acpi_ex_name_segment (&aml_address, name_string); + } + break; + + + case AML_MULTI_NAME_PREFIX_OP: + + ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "multi_name_prefix at %p\n", aml_address)); + + /* Fetch count of segments remaining in name path */ + + aml_address++; + num_segments = *aml_address; + + name_string = acpi_ex_allocate_name_string (prefix_count, num_segments); + if (!name_string) { + status = AE_NO_MEMORY; + break; + } + + /* Indicate that we processed a prefix */ + + aml_address++; + has_prefix = TRUE; + + while (num_segments && + (status = acpi_ex_name_segment (&aml_address, name_string)) == AE_OK) { + num_segments--; + } + + break; + + + case 0: + + /* null_name valid as of 8-12-98 ASL/AML Grammar Update */ + + if (prefix_count == ACPI_UINT32_MAX) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "name_seg is \"\\\" followed by NULL\n")); + } + + /* Consume the NULL byte */ + + aml_address++; + name_string = acpi_ex_allocate_name_string (prefix_count, 0); + if (!name_string) { + status = AE_NO_MEMORY; + break; + } + + break; + + + default: + + /* Name segment string */ + + name_string = acpi_ex_allocate_name_string (prefix_count, 1); + if (!name_string) { + status = AE_NO_MEMORY; + break; + } + + status = acpi_ex_name_segment (&aml_address, name_string); + break; + } + } + + if (AE_CTRL_PENDING == status && has_prefix) { + /* Ran out of segments after processing a prefix */ + + ACPI_REPORT_ERROR ( + ("ex_do_name: Malformed Name at %p\n", name_string)); + status = AE_AML_BAD_NAME; + } + + *out_name_string = name_string; + *out_name_length = (u32) (aml_address - in_aml_address); + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c new file mode 100644 index 000000000000..8482aefaf38b --- /dev/null +++ b/drivers/acpi/executer/exoparg1.c @@ -0,0 +1,1013 @@ + +/****************************************************************************** + * + * Module Name: exoparg1 - AML execution - opcodes with 1 argument + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/amlcode.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exoparg1") + + +/*! + * Naming convention for AML interpreter execution routines. + * + * The routines that begin execution of AML opcodes are named with a common + * convention based upon the number of arguments, the number of target operands, + * and whether or not a value is returned: + * + * AcpiExOpcode_xA_yT_zR + * + * Where: + * + * xA - ARGUMENTS: The number of arguments (input operands) that are + * required for this opcode type (0 through 6 args). + * yT - TARGETS: The number of targets (output operands) that are required + * for this opcode type (0, 1, or 2 targets). + * zR - RETURN VALUE: Indicates whether this opcode type returns a value + * as the function return (0 or 1). + * + * The AcpiExOpcode* functions are called via the Dispatcher component with + * fully resolved operands. +!*/ + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_0A_0T_1R + * + * PARAMETERS: walk_state - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute operator with no operands, one return value + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_0A_0T_1R ( + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_operand_object *return_desc = NULL; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_0A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + + + /* Examine the AML opcode */ + + switch (walk_state->opcode) { + case AML_TIMER_OP: /* Timer () */ + + /* Create a return object of type Integer */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + return_desc->integer.value = acpi_os_get_timer (); + break; + + default: /* Unknown opcode */ + + ACPI_REPORT_ERROR (("acpi_ex_opcode_0A_0T_1R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + break; + } + +cleanup: + + if (!walk_state->result_obj) { + walk_state->result_obj = return_desc; + } + + /* Delete return object on error */ + + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (return_desc); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_1A_0T_0R + * + * PARAMETERS: walk_state - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute Type 1 monadic operator with numeric operand on + * object stack + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_1A_0T_0R ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + + + /* Examine the AML opcode */ + + switch (walk_state->opcode) { + case AML_RELEASE_OP: /* Release (mutex_object) */ + + status = acpi_ex_release_mutex (operand[0], walk_state); + break; + + + case AML_RESET_OP: /* Reset (event_object) */ + + status = acpi_ex_system_reset_event (operand[0]); + break; + + + case AML_SIGNAL_OP: /* Signal (event_object) */ + + status = acpi_ex_system_signal_event (operand[0]); + break; + + + case AML_SLEEP_OP: /* Sleep (msec_time) */ + + status = acpi_ex_system_do_suspend (operand[0]->integer.value); + break; + + + case AML_STALL_OP: /* Stall (usec_time) */ + + status = acpi_ex_system_do_stall ((u32) operand[0]->integer.value); + break; + + + case AML_UNLOAD_OP: /* Unload (Handle) */ + + status = acpi_ex_unload_table (operand[0]); + break; + + + default: /* Unknown opcode */ + + ACPI_REPORT_ERROR (("acpi_ex_opcode_1A_0T_0R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + break; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_1A_1T_0R + * + * PARAMETERS: walk_state - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with one argument, one target, and no + * return value. + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_1A_1T_0R ( + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_operand_object **operand = &walk_state->operands[0]; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + + + /* Examine the AML opcode */ + + switch (walk_state->opcode) { + case AML_LOAD_OP: + + status = acpi_ex_load_op (operand[0], operand[1], walk_state); + break; + + default: /* Unknown opcode */ + + ACPI_REPORT_ERROR (("acpi_ex_opcode_1A_1T_0R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + goto cleanup; + } + + +cleanup: + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_1A_1T_1R + * + * PARAMETERS: walk_state - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with one argument, one target, and a + * return value. + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_1A_1T_1R ( + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *return_desc = NULL; + union acpi_operand_object *return_desc2 = NULL; + u32 temp32; + u32 i; + acpi_integer power_of_ten; + acpi_integer digit; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + + + /* Examine the AML opcode */ + + switch (walk_state->opcode) { + case AML_BIT_NOT_OP: + case AML_FIND_SET_LEFT_BIT_OP: + case AML_FIND_SET_RIGHT_BIT_OP: + case AML_FROM_BCD_OP: + case AML_TO_BCD_OP: + case AML_COND_REF_OF_OP: + + /* Create a return object of type Integer for these opcodes */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + switch (walk_state->opcode) { + case AML_BIT_NOT_OP: /* Not (Operand, Result) */ + + return_desc->integer.value = ~operand[0]->integer.value; + break; + + + case AML_FIND_SET_LEFT_BIT_OP: /* find_set_left_bit (Operand, Result) */ + + return_desc->integer.value = operand[0]->integer.value; + + /* + * Acpi specification describes Integer type as a little + * endian unsigned value, so this boundary condition is valid. + */ + for (temp32 = 0; return_desc->integer.value && + temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { + return_desc->integer.value >>= 1; + } + + return_desc->integer.value = temp32; + break; + + + case AML_FIND_SET_RIGHT_BIT_OP: /* find_set_right_bit (Operand, Result) */ + + return_desc->integer.value = operand[0]->integer.value; + + /* + * The Acpi specification describes Integer type as a little + * endian unsigned value, so this boundary condition is valid. + */ + for (temp32 = 0; return_desc->integer.value && + temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { + return_desc->integer.value <<= 1; + } + + /* Since the bit position is one-based, subtract from 33 (65) */ + + return_desc->integer.value = temp32 == 0 ? 0 : + (ACPI_INTEGER_BIT_SIZE + 1) - temp32; + break; + + + case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */ + + /* + * The 64-bit ACPI integer can hold 16 4-bit BCD characters + * (if table is 32-bit, integer can hold 8 BCD characters) + * Convert each 4-bit BCD value + */ + power_of_ten = 1; + return_desc->integer.value = 0; + digit = operand[0]->integer.value; + + /* Convert each BCD digit (each is one nybble wide) */ + + for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { + /* Get the least significant 4-bit BCD digit */ + + temp32 = ((u32) digit) & 0xF; + + /* Check the range of the digit */ + + if (temp32 > 9) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "BCD digit too large (not decimal): 0x%X\n", + temp32)); + + status = AE_AML_NUMERIC_OVERFLOW; + goto cleanup; + } + + /* Sum the digit into the result with the current power of 10 */ + + return_desc->integer.value += (((acpi_integer) temp32) * + power_of_ten); + + /* Shift to next BCD digit */ + + digit >>= 4; + + /* Next power of 10 */ + + power_of_ten *= 10; + } + break; + + + case AML_TO_BCD_OP: /* to_bcd (Operand, Result) */ + + return_desc->integer.value = 0; + digit = operand[0]->integer.value; + + /* Each BCD digit is one nybble wide */ + + for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) { + (void) acpi_ut_short_divide (digit, 10, &digit, &temp32); + + /* Insert the BCD digit that resides in the remainder from above */ + + return_desc->integer.value |= (((acpi_integer) temp32) << + ACPI_MUL_4 (i)); + } + + /* Overflow if there is any data left in Digit */ + + if (digit > 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Integer too large to convert to BCD: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (operand[0]->integer.value))); + status = AE_AML_NUMERIC_OVERFLOW; + goto cleanup; + } + break; + + + case AML_COND_REF_OF_OP: /* cond_ref_of (source_object, Result) */ + + /* + * This op is a little strange because the internal return value is + * different than the return value stored in the result descriptor + * (There are really two return values) + */ + if ((struct acpi_namespace_node *) operand[0] == acpi_gbl_root_node) { + /* + * This means that the object does not exist in the namespace, + * return FALSE + */ + return_desc->integer.value = 0; + goto cleanup; + } + + /* Get the object reference, store it, and remove our reference */ + + status = acpi_ex_get_object_reference (operand[0], &return_desc2, walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + status = acpi_ex_store (return_desc2, operand[1], walk_state); + acpi_ut_remove_reference (return_desc2); + + /* The object exists in the namespace, return TRUE */ + + return_desc->integer.value = ACPI_INTEGER_MAX; + goto cleanup; + + + default: + /* No other opcodes get here */ + break; + } + break; + + + case AML_STORE_OP: /* Store (Source, Target) */ + + /* + * A store operand is typically a number, string, buffer or lvalue + * Be careful about deleting the source object, + * since the object itself may have been stored. + */ + status = acpi_ex_store (operand[0], operand[1], walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* It is possible that the Store already produced a return object */ + + if (!walk_state->result_obj) { + /* + * Normally, we would remove a reference on the Operand[0] parameter; + * But since it is being used as the internal return object + * (meaning we would normally increment it), the two cancel out, + * and we simply don't do anything. + */ + walk_state->result_obj = operand[0]; + walk_state->operands[0] = NULL; /* Prevent deletion */ + } + return_ACPI_STATUS (status); + + + /* + * ACPI 2.0 Opcodes + */ + case AML_COPY_OP: /* Copy (Source, Target) */ + + status = acpi_ut_copy_iobject_to_iobject (operand[0], &return_desc, + walk_state); + break; + + + case AML_TO_DECSTRING_OP: /* to_decimal_string (Data, Result) */ + + status = acpi_ex_convert_to_string (operand[0], &return_desc, + ACPI_EXPLICIT_CONVERT_DECIMAL); + if (return_desc == operand[0]) { + /* No conversion performed, add ref to handle return value */ + acpi_ut_add_reference (return_desc); + } + break; + + + case AML_TO_HEXSTRING_OP: /* to_hex_string (Data, Result) */ + + status = acpi_ex_convert_to_string (operand[0], &return_desc, + ACPI_EXPLICIT_CONVERT_HEX); + if (return_desc == operand[0]) { + /* No conversion performed, add ref to handle return value */ + acpi_ut_add_reference (return_desc); + } + break; + + + case AML_TO_BUFFER_OP: /* to_buffer (Data, Result) */ + + status = acpi_ex_convert_to_buffer (operand[0], &return_desc); + if (return_desc == operand[0]) { + /* No conversion performed, add ref to handle return value */ + acpi_ut_add_reference (return_desc); + } + break; + + + case AML_TO_INTEGER_OP: /* to_integer (Data, Result) */ + + status = acpi_ex_convert_to_integer (operand[0], &return_desc, + ACPI_ANY_BASE); + if (return_desc == operand[0]) { + /* No conversion performed, add ref to handle return value */ + acpi_ut_add_reference (return_desc); + } + break; + + + case AML_SHIFT_LEFT_BIT_OP: /* shift_left_bit (Source, bit_num) */ + case AML_SHIFT_RIGHT_BIT_OP: /* shift_right_bit (Source, bit_num) */ + + /* + * These are two obsolete opcodes + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "%s is obsolete and not implemented\n", + acpi_ps_get_opcode_name (walk_state->opcode))); + status = AE_SUPPORT; + goto cleanup; + + + default: /* Unknown opcode */ + + ACPI_REPORT_ERROR (("acpi_ex_opcode_1A_1T_1R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + goto cleanup; + } + + if (ACPI_SUCCESS (status)) { + /* + * Store the return value computed above into the target object + */ + status = acpi_ex_store (return_desc, operand[1], walk_state); + } + + +cleanup: + + if (!walk_state->result_obj) { + walk_state->result_obj = return_desc; + } + + /* Delete return object on error */ + + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (return_desc); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_1A_0T_1R + * + * PARAMETERS: walk_state - Current state (contains AML opcode) + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with one argument, no target, and a return value + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_1A_0T_1R ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *temp_desc; + union acpi_operand_object *return_desc = NULL; + acpi_status status = AE_OK; + u32 type; + acpi_integer value; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + + + /* Examine the AML opcode */ + + switch (walk_state->opcode) { + case AML_LNOT_OP: /* LNot (Operand) */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* + * Set result to ONES (TRUE) if Value == 0. Note: + * return_desc->Integer.Value is initially == 0 (FALSE) from above. + */ + if (!operand[0]->integer.value) { + return_desc->integer.value = ACPI_INTEGER_MAX; + } + break; + + + case AML_DECREMENT_OP: /* Decrement (Operand) */ + case AML_INCREMENT_OP: /* Increment (Operand) */ + + /* + * Create a new integer. Can't just get the base integer and + * increment it because it may be an Arg or Field. + */ + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* + * Since we are expecting a Reference operand, it can be either a + * NS Node or an internal object. + */ + temp_desc = operand[0]; + if (ACPI_GET_DESCRIPTOR_TYPE (temp_desc) == ACPI_DESC_TYPE_OPERAND) { + /* Internal reference object - prevent deletion */ + + acpi_ut_add_reference (temp_desc); + } + + /* + * Convert the Reference operand to an Integer (This removes a + * reference on the Operand[0] object) + * + * NOTE: We use LNOT_OP here in order to force resolution of the + * reference operand to an actual integer. + */ + status = acpi_ex_resolve_operands (AML_LNOT_OP, &temp_desc, walk_state); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s: bad operand(s) %s\n", + acpi_ps_get_opcode_name (walk_state->opcode), + acpi_format_exception(status))); + + goto cleanup; + } + + /* + * temp_desc is now guaranteed to be an Integer object -- + * Perform the actual increment or decrement + */ + if (walk_state->opcode == AML_INCREMENT_OP) { + return_desc->integer.value = temp_desc->integer.value +1; + } + else { + return_desc->integer.value = temp_desc->integer.value -1; + } + + /* Finished with this Integer object */ + + acpi_ut_remove_reference (temp_desc); + + /* + * Store the result back (indirectly) through the original + * Reference object + */ + status = acpi_ex_store (return_desc, operand[0], walk_state); + break; + + + case AML_TYPE_OP: /* object_type (source_object) */ + + /* + * Note: The operand is not resolved at this point because we want to + * get the associated object, not its value. For example, we don't want + * to resolve a field_unit to its value, we want the actual field_unit + * object. + */ + + /* Get the type of the base object */ + + status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, NULL); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + /* Allocate a descriptor to hold the type. */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + return_desc->integer.value = type; + break; + + + case AML_SIZE_OF_OP: /* size_of (source_object) */ + + /* + * Note: The operand is not resolved at this point because we want to + * get the associated object, not its value. + */ + + /* Get the base object */ + + status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, &temp_desc); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* + * The type of the base object must be integer, buffer, string, or + * package. All others are not supported. + * + * NOTE: Integer is not specifically supported by the ACPI spec, + * but is supported implicitly via implicit operand conversion. + * rather than bother with conversion, we just use the byte width + * global (4 or 8 bytes). + */ + switch (type) { + case ACPI_TYPE_INTEGER: + value = acpi_gbl_integer_byte_width; + break; + + case ACPI_TYPE_BUFFER: + value = temp_desc->buffer.length; + break; + + case ACPI_TYPE_STRING: + value = temp_desc->string.length; + break; + + case ACPI_TYPE_PACKAGE: + value = temp_desc->package.count; + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "size_of - Operand is not Buf/Int/Str/Pkg - found type %s\n", + acpi_ut_get_type_name (type))); + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + + /* + * Now that we have the size of the object, create a result + * object to hold the value + */ + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + return_desc->integer.value = value; + break; + + + case AML_REF_OF_OP: /* ref_of (source_object) */ + + status = acpi_ex_get_object_reference (operand[0], &return_desc, walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + break; + + + case AML_DEREF_OF_OP: /* deref_of (obj_reference | String) */ + + /* Check for a method local or argument, or standalone String */ + + if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) != ACPI_DESC_TYPE_NAMED) { + switch (ACPI_GET_OBJECT_TYPE (operand[0])) { + case ACPI_TYPE_LOCAL_REFERENCE: + /* + * This is a deref_of (local_x | arg_x) + * + * Must resolve/dereference the local/arg reference first + */ + switch (operand[0]->reference.opcode) { + case AML_LOCAL_OP: + case AML_ARG_OP: + + /* Set Operand[0] to the value of the local/arg */ + + status = acpi_ds_method_data_get_value (operand[0]->reference.opcode, + operand[0]->reference.offset, walk_state, &temp_desc); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* + * Delete our reference to the input object and + * point to the object just retrieved + */ + acpi_ut_remove_reference (operand[0]); + operand[0] = temp_desc; + break; + + case AML_REF_OF_OP: + + /* Get the object to which the reference refers */ + + temp_desc = operand[0]->reference.object; + acpi_ut_remove_reference (operand[0]); + operand[0] = temp_desc; + break; + + default: + + /* Must be an Index op - handled below */ + break; + } + break; + + + case ACPI_TYPE_STRING: + + /* + * This is a deref_of (String). The string is a reference to a named ACPI object. + * + * 1) Find the owning Node + * 2) Dereference the node to an actual object. Could be a Field, so we nee + * to resolve the node to a value. + */ + status = acpi_ns_get_node_by_path (operand[0]->string.pointer, + walk_state->scope_info->scope.node, ACPI_NS_SEARCH_PARENT, + ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc)); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + status = acpi_ex_resolve_node_to_value ( + ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc), walk_state); + goto cleanup; + + + default: + + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + } + + /* Operand[0] may have changed from the code above */ + + if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) == ACPI_DESC_TYPE_NAMED) { + /* + * This is a deref_of (object_reference) + * Get the actual object from the Node (This is the dereference). + * -- This case may only happen when a local_x or arg_x is dereferenced above. + */ + return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) operand[0]); + } + else { + /* + * This must be a reference object produced by either the Index() or + * ref_of() operator + */ + switch (operand[0]->reference.opcode) { + case AML_INDEX_OP: + + /* + * The target type for the Index operator must be + * either a Buffer or a Package + */ + switch (operand[0]->reference.target_type) { + case ACPI_TYPE_BUFFER_FIELD: + + temp_desc = operand[0]->reference.object; + + /* + * Create a new object that contains one element of the + * buffer -- the element pointed to by the index. + * + * NOTE: index into a buffer is NOT a pointer to a + * sub-buffer of the main buffer, it is only a pointer to a + * single element (byte) of the buffer! + */ + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* + * Since we are returning the value of the buffer at the + * indexed location, we don't need to add an additional + * reference to the buffer itself. + */ + return_desc->integer.value = + temp_desc->buffer.pointer[operand[0]->reference.offset]; + break; + + + case ACPI_TYPE_PACKAGE: + + /* + * Return the referenced element of the package. We must add + * another reference to the referenced object, however. + */ + return_desc = *(operand[0]->reference.where); + if (!return_desc) { + /* + * We can't return a NULL dereferenced value. This is + * an uninitialized package element and is thus a + * severe error. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "NULL package element obj %p\n", + operand[0])); + status = AE_AML_UNINITIALIZED_ELEMENT; + goto cleanup; + } + + acpi_ut_add_reference (return_desc); + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown Index target_type %X in obj %p\n", + operand[0]->reference.target_type, operand[0])); + status = AE_AML_OPERAND_TYPE; + goto cleanup; + } + break; + + + case AML_REF_OF_OP: + + return_desc = operand[0]->reference.object; + + if (ACPI_GET_DESCRIPTOR_TYPE (return_desc) == ACPI_DESC_TYPE_NAMED) { + + return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) return_desc); + } + + /* Add another reference to the object! */ + + acpi_ut_add_reference (return_desc); + break; + + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown opcode in ref(%p) - %X\n", + operand[0], operand[0]->reference.opcode)); + + status = AE_TYPE; + goto cleanup; + } + } + break; + + + default: + + ACPI_REPORT_ERROR (("acpi_ex_opcode_1A_0T_1R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + goto cleanup; + } + + +cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (return_desc); + } + + walk_state->result_obj = return_desc; + return_ACPI_STATUS (status); +} + diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c new file mode 100644 index 000000000000..8be4d80ceed5 --- /dev/null +++ b/drivers/acpi/executer/exoparg2.c @@ -0,0 +1,608 @@ +/****************************************************************************** + * + * Module Name: exoparg2 - AML execution - opcodes with 2 arguments + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/acevents.h> +#include <acpi/amlcode.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exoparg2") + + +/*! + * Naming convention for AML interpreter execution routines. + * + * The routines that begin execution of AML opcodes are named with a common + * convention based upon the number of arguments, the number of target operands, + * and whether or not a value is returned: + * + * AcpiExOpcode_xA_yT_zR + * + * Where: + * + * xA - ARGUMENTS: The number of arguments (input operands) that are + * required for this opcode type (1 through 6 args). + * yT - TARGETS: The number of targets (output operands) that are required + * for this opcode type (0, 1, or 2 targets). + * zR - RETURN VALUE: Indicates whether this opcode type returns a value + * as the function return (0 or 1). + * + * The AcpiExOpcode* functions are called via the Dispatcher component with + * fully resolved operands. +!*/ + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_2A_0T_0R + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with two arguments, no target, and no return + * value. + * + * ALLOCATION: Deletes both operands + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_2A_0T_0R ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + struct acpi_namespace_node *node; + u32 value; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_2A_0T_0R", + acpi_ps_get_opcode_name (walk_state->opcode)); + + + /* Examine the opcode */ + + switch (walk_state->opcode) { + case AML_NOTIFY_OP: /* Notify (notify_object, notify_value) */ + + /* The first operand is a namespace node */ + + node = (struct acpi_namespace_node *) operand[0]; + + /* Second value is the notify value */ + + value = (u32) operand[1]->integer.value; + + /* Notifies allowed on this object? */ + + if (!acpi_ev_is_notify_object (node)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unexpected notify object type [%s]\n", + acpi_ut_get_type_name (node->type))); + + status = AE_AML_OPERAND_TYPE; + break; + } + +#ifdef ACPI_GPE_NOTIFY_CHECK + /* + * GPE method wake/notify check. Here, we want to ensure that we + * don't receive any "device_wake" Notifies from a GPE _Lxx or _Exx + * GPE method during system runtime. If we do, the GPE is marked + * as "wake-only" and disabled. + * + * 1) Is the Notify() value == device_wake? + * 2) Is this a GPE deferred method? (An _Lxx or _Exx method) + * 3) Did the original GPE happen at system runtime? + * (versus during wake) + * + * If all three cases are true, this is a wake-only GPE that should + * be disabled at runtime. + */ + if (value == 2) /* device_wake */ { + status = acpi_ev_check_for_wake_only_gpe (walk_state->gpe_event_info); + if (ACPI_FAILURE (status)) { + /* AE_WAKE_ONLY_GPE only error, means ignore this notify */ + + return_ACPI_STATUS (AE_OK) + } + } +#endif + + /* + * Dispatch the notify to the appropriate handler + * NOTE: the request is queued for execution after this method + * completes. The notify handlers are NOT invoked synchronously + * from this thread -- because handlers may in turn run other + * control methods. + */ + status = acpi_ev_queue_notify_request (node, value); + break; + + + default: + + ACPI_REPORT_ERROR (("acpi_ex_opcode_2A_0T_0R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_2A_2T_1R + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets + * and one implicit return value. + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_2A_2T_1R ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *return_desc1 = NULL; + union acpi_operand_object *return_desc2 = NULL; + acpi_status status; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_2A_2T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); + + + /* + * Execute the opcode + */ + switch (walk_state->opcode) { + case AML_DIVIDE_OP: /* Divide (Dividend, Divisor, remainder_result quotient_result) */ + + return_desc1 = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc1) { + status = AE_NO_MEMORY; + goto cleanup; + } + + return_desc2 = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc2) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Quotient to return_desc1, remainder to return_desc2 */ + + status = acpi_ut_divide (operand[0]->integer.value, + operand[1]->integer.value, + &return_desc1->integer.value, + &return_desc2->integer.value); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + break; + + + default: + + ACPI_REPORT_ERROR (("acpi_ex_opcode_2A_2T_1R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + goto cleanup; + } + + + /* Store the results to the target reference operands */ + + status = acpi_ex_store (return_desc2, operand[2], walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + status = acpi_ex_store (return_desc1, operand[3], walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Return the remainder */ + + walk_state->result_obj = return_desc1; + + +cleanup: + /* + * Since the remainder is not returned indirectly, remove a reference to + * it. Only the quotient is returned indirectly. + */ + acpi_ut_remove_reference (return_desc2); + + if (ACPI_FAILURE (status)) { + /* Delete the return object */ + + acpi_ut_remove_reference (return_desc1); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_2A_1T_1R + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with two arguments, one target, and a return + * value. + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_2A_1T_1R ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *return_desc = NULL; + u32 index; + acpi_status status = AE_OK; + acpi_size length; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_2A_1T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); + + + /* + * Execute the opcode + */ + if (walk_state->op_info->flags & AML_MATH) { + /* All simple math opcodes (add, etc.) */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + return_desc->integer.value = acpi_ex_do_math_op (walk_state->opcode, + operand[0]->integer.value, + operand[1]->integer.value); + goto store_result_to_target; + } + + + switch (walk_state->opcode) { + case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* return_desc will contain the remainder */ + + status = acpi_ut_divide (operand[0]->integer.value, + operand[1]->integer.value, + NULL, + &return_desc->integer.value); + break; + + + case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ + + status = acpi_ex_do_concatenate (operand[0], operand[1], + &return_desc, walk_state); + break; + + + case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */ + + /* + * Input object is guaranteed to be a buffer at this point (it may have + * been converted.) Copy the raw buffer data to a new object of type String. + */ + + /* + * Get the length of the new string. It is the smallest of: + * 1) Length of the input buffer + * 2) Max length as specified in the to_string operator + * 3) Length of input buffer up to a zero byte (null terminator) + * + * NOTE: A length of zero is ok, and will create a zero-length, null + * terminated string. + */ + length = 0; + while ((length < operand[0]->buffer.length) && + (length < operand[1]->integer.value) && + (operand[0]->buffer.pointer[length])) { + length++; + if (length > ACPI_MAX_STRING_CONVERSION) { + status = AE_AML_STRING_LIMIT; + goto cleanup; + } + } + + /* Allocate a new string object */ + + return_desc = acpi_ut_create_string_object (length); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Copy the raw buffer data with no transform. NULL terminated already. */ + + ACPI_MEMCPY (return_desc->string.pointer, + operand[0]->buffer.pointer, length); + break; + + + case AML_CONCAT_RES_OP: /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ + + status = acpi_ex_concat_template (operand[0], operand[1], + &return_desc, walk_state); + break; + + + case AML_INDEX_OP: /* Index (Source Index Result) */ + + /* Create the internal return object */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_REFERENCE); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + index = (u32) operand[1]->integer.value; + + /* + * At this point, the Source operand is a Package, Buffer, or String + */ + if (ACPI_GET_OBJECT_TYPE (operand[0]) == ACPI_TYPE_PACKAGE) { + /* Object to be indexed is a Package */ + + if (index >= operand[0]->package.count) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Index value (%X) beyond package end (%X)\n", + index, operand[0]->package.count)); + status = AE_AML_PACKAGE_LIMIT; + goto cleanup; + } + + return_desc->reference.target_type = ACPI_TYPE_PACKAGE; + return_desc->reference.object = operand[0]; + return_desc->reference.where = &operand[0]->package.elements [index]; + } + else { + /* Object to be indexed is a Buffer/String */ + + if (index >= operand[0]->buffer.length) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Index value (%X) beyond end of buffer (%X)\n", + index, operand[0]->buffer.length)); + status = AE_AML_BUFFER_LIMIT; + goto cleanup; + } + + return_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD; + return_desc->reference.object = operand[0]; + } + + /* + * Add a reference to the target package/buffer/string for the life + * of the index. + */ + acpi_ut_add_reference (operand[0]); + + /* Complete the Index reference object */ + + return_desc->reference.opcode = AML_INDEX_OP; + return_desc->reference.offset = index; + + /* Store the reference to the Target */ + + status = acpi_ex_store (return_desc, operand[2], walk_state); + + /* Return the reference */ + + walk_state->result_obj = return_desc; + goto cleanup; + + + default: + + ACPI_REPORT_ERROR (("acpi_ex_opcode_2A_1T_1R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + break; + } + + +store_result_to_target: + + if (ACPI_SUCCESS (status)) { + /* + * Store the result of the operation (which is now in return_desc) into + * the Target descriptor. + */ + status = acpi_ex_store (return_desc, operand[2], walk_state); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + if (!walk_state->result_obj) { + walk_state->result_obj = return_desc; + } + } + + +cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (return_desc); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_2A_0T_1R + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_2A_0T_1R ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *return_desc = NULL; + acpi_status status = AE_OK; + u8 logical_result = FALSE; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_2A_0T_1R", + acpi_ps_get_opcode_name (walk_state->opcode)); + + + /* Create the internal return object */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* + * Execute the Opcode + */ + if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) /* logical_op (Operand0, Operand1) */ { + status = acpi_ex_do_logical_numeric_op (walk_state->opcode, + operand[0]->integer.value, operand[1]->integer.value, + &logical_result); + goto store_logical_result; + } + else if (walk_state->op_info->flags & AML_LOGICAL) /* logical_op (Operand0, Operand1) */ { + status = acpi_ex_do_logical_op (walk_state->opcode, operand[0], + operand[1], &logical_result); + goto store_logical_result; + } + + + switch (walk_state->opcode) { + case AML_ACQUIRE_OP: /* Acquire (mutex_object, Timeout) */ + + status = acpi_ex_acquire_mutex (operand[1], operand[0], walk_state); + if (status == AE_TIME) { + logical_result = TRUE; /* TRUE = Acquire timed out */ + status = AE_OK; + } + break; + + + case AML_WAIT_OP: /* Wait (event_object, Timeout) */ + + status = acpi_ex_system_wait_event (operand[1], operand[0]); + if (status == AE_TIME) { + logical_result = TRUE; /* TRUE, Wait timed out */ + status = AE_OK; + } + break; + + + default: + + ACPI_REPORT_ERROR (("acpi_ex_opcode_2A_0T_1R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + goto cleanup; + } + + +store_logical_result: + /* + * Set return value to according to logical_result. logical TRUE (all ones) + * Default is FALSE (zero) + */ + if (logical_result) { + return_desc->integer.value = ACPI_INTEGER_MAX; + } + + walk_state->result_obj = return_desc; + + +cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (return_desc); + } + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c new file mode 100644 index 000000000000..29d0b167745d --- /dev/null +++ b/drivers/acpi/executer/exoparg3.c @@ -0,0 +1,256 @@ + +/****************************************************************************** + * + * Module Name: exoparg3 - AML execution - opcodes with 3 arguments + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/acparser.h> +#include <acpi/amlcode.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exoparg3") + + +/*! + * Naming convention for AML interpreter execution routines. + * + * The routines that begin execution of AML opcodes are named with a common + * convention based upon the number of arguments, the number of target operands, + * and whether or not a value is returned: + * + * AcpiExOpcode_xA_yT_zR + * + * Where: + * + * xA - ARGUMENTS: The number of arguments (input operands) that are + * required for this opcode type (1 through 6 args). + * yT - TARGETS: The number of targets (output operands) that are required + * for this opcode type (0, 1, or 2 targets). + * zR - RETURN VALUE: Indicates whether this opcode type returns a value + * as the function return (0 or 1). + * + * The AcpiExOpcode* functions are called via the Dispatcher component with + * fully resolved operands. +!*/ + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_3A_0T_0R + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute Triadic operator (3 operands) + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_3A_0T_0R ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + struct acpi_signal_fatal_info *fatal; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode)); + + + switch (walk_state->opcode) { + case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", + (u32) operand[0]->integer.value, + (u32) operand[1]->integer.value, + (u32) operand[2]->integer.value)); + + fatal = ACPI_MEM_ALLOCATE (sizeof (struct acpi_signal_fatal_info)); + if (fatal) { + fatal->type = (u32) operand[0]->integer.value; + fatal->code = (u32) operand[1]->integer.value; + fatal->argument = (u32) operand[2]->integer.value; + } + + /* + * Always signal the OS! + */ + status = acpi_os_signal (ACPI_SIGNAL_FATAL, fatal); + + /* Might return while OS is shutting down, just continue */ + + ACPI_MEM_FREE (fatal); + break; + + + default: + + ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + goto cleanup; + } + + +cleanup: + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_3A_1T_1R + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute Triadic operator (3 operands) + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_3A_1T_1R ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *return_desc = NULL; + char *buffer; + acpi_status status = AE_OK; + acpi_native_uint index; + acpi_size length; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + + + switch (walk_state->opcode) { + case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ + + /* + * Create the return object. The Source operand is guaranteed to be + * either a String or a Buffer, so just use its type. + */ + return_desc = acpi_ut_create_internal_object (ACPI_GET_OBJECT_TYPE (operand[0])); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Get the Integer values from the objects */ + + index = (acpi_native_uint) operand[1]->integer.value; + length = (acpi_size) operand[2]->integer.value; + + /* + * If the index is beyond the length of the String/Buffer, or if the + * requested length is zero, return a zero-length String/Buffer + */ + if ((index < operand[0]->string.length) && + (length > 0)) { + /* Truncate request if larger than the actual String/Buffer */ + + if ((index + length) > + operand[0]->string.length) { + length = (acpi_size) operand[0]->string.length - index; + } + + /* Allocate a new buffer for the String/Buffer */ + + buffer = ACPI_MEM_CALLOCATE ((acpi_size) length + 1); + if (!buffer) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Copy the portion requested */ + + ACPI_MEMCPY (buffer, operand[0]->string.pointer + index, + length); + + /* Set the length of the new String/Buffer */ + + return_desc->string.pointer = buffer; + return_desc->string.length = (u32) length; + } + + /* Mark buffer initialized */ + + return_desc->buffer.flags |= AOPOBJ_DATA_VALID; + break; + + + default: + + ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + goto cleanup; + } + + /* Store the result in the target */ + + status = acpi_ex_store (return_desc, operand[3], walk_state); + +cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (return_desc); + } + + /* Set the return object and exit */ + + if (!walk_state->result_obj) { + walk_state->result_obj = return_desc; + } + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c new file mode 100644 index 000000000000..d32624331626 --- /dev/null +++ b/drivers/acpi/executer/exoparg6.c @@ -0,0 +1,336 @@ + +/****************************************************************************** + * + * Module Name: exoparg6 - AML execution - opcodes with 6 arguments + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/acparser.h> +#include <acpi/amlcode.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exoparg6") + + +/*! + * Naming convention for AML interpreter execution routines. + * + * The routines that begin execution of AML opcodes are named with a common + * convention based upon the number of arguments, the number of target operands, + * and whether or not a value is returned: + * + * AcpiExOpcode_xA_yT_zR + * + * Where: + * + * xA - ARGUMENTS: The number of arguments (input operands) that are + * required for this opcode type (1 through 6 args). + * yT - TARGETS: The number of targets (output operands) that are required + * for this opcode type (0, 1, or 2 targets). + * zR - RETURN VALUE: Indicates whether this opcode type returns a value + * as the function return (0 or 1). + * + * The AcpiExOpcode* functions are called via the Dispatcher component with + * fully resolved operands. +!*/ + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_do_match + * + * PARAMETERS: match_op - The AML match operand + * package_obj - Object from the target package + * match_obj - Object to be matched + * + * RETURN: TRUE if the match is successful, FALSE otherwise + * + * DESCRIPTION: Implements the low-level match for the ASL Match operator. + * Package elements will be implicitly converted to the type of + * the match object (Integer/Buffer/String). + * + ******************************************************************************/ + +u8 +acpi_ex_do_match ( + u32 match_op, + union acpi_operand_object *package_obj, + union acpi_operand_object *match_obj) +{ + u8 logical_result = TRUE; + acpi_status status; + + + /* + * Note: Since the package_obj/match_obj ordering is opposite to that of + * the standard logical operators, we have to reverse them when we call + * do_logical_op in order to make the implicit conversion rules work + * correctly. However, this means we have to flip the entire equation + * also. A bit ugly perhaps, but overall, better than fussing the + * parameters around at runtime, over and over again. + * + * Below, P[i] refers to the package element, M refers to the Match object. + */ + switch (match_op) { + case MATCH_MTR: + + /* Always true */ + + break; + + case MATCH_MEQ: + + /* + * True if equal: (P[i] == M) + * Change to: (M == P[i]) + */ + status = acpi_ex_do_logical_op (AML_LEQUAL_OP, match_obj, package_obj, + &logical_result); + if (ACPI_FAILURE (status)) { + return (FALSE); + } + break; + + case MATCH_MLE: + + /* + * True if less than or equal: (P[i] <= M) (P[i] not_greater than M) + * Change to: (M >= P[i]) (M not_less than P[i]) + */ + status = acpi_ex_do_logical_op (AML_LLESS_OP, match_obj, package_obj, + &logical_result); + if (ACPI_FAILURE (status)) { + return (FALSE); + } + logical_result = (u8) !logical_result; + break; + + case MATCH_MLT: + + /* + * True if less than: (P[i] < M) + * Change to: (M > P[i]) + */ + status = acpi_ex_do_logical_op (AML_LGREATER_OP, match_obj, package_obj, + &logical_result); + if (ACPI_FAILURE (status)) { + return (FALSE); + } + break; + + case MATCH_MGE: + + /* + * True if greater than or equal: (P[i] >= M) (P[i] not_less than M) + * Change to: (M <= P[i]) (M not_greater than P[i]) + */ + status = acpi_ex_do_logical_op (AML_LGREATER_OP, match_obj, package_obj, + &logical_result); + if (ACPI_FAILURE (status)) { + return (FALSE); + } + logical_result = (u8)!logical_result; + break; + + case MATCH_MGT: + + /* + * True if greater than: (P[i] > M) + * Change to: (M < P[i]) + */ + status = acpi_ex_do_logical_op (AML_LLESS_OP, match_obj, package_obj, + &logical_result); + if (ACPI_FAILURE (status)) { + return (FALSE); + } + break; + + default: + + /* Undefined */ + + return (FALSE); + } + + return logical_result; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_opcode_6A_0T_1R + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Execute opcode with 6 arguments, no target, and a return value + * + ******************************************************************************/ + +acpi_status +acpi_ex_opcode_6A_0T_1R ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *return_desc = NULL; + acpi_status status = AE_OK; + u32 index; + union acpi_operand_object *this_element; + + + ACPI_FUNCTION_TRACE_STR ("ex_opcode_6A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode)); + + + switch (walk_state->opcode) { + case AML_MATCH_OP: + /* + * Match (search_pkg[0], match_op1[1], match_obj1[2], + * match_op2[3], match_obj2[4], start_index[5]) + */ + + /* Validate both Match Term Operators (MTR, MEQ, etc.) */ + + if ((operand[1]->integer.value > MAX_MATCH_OPERATOR) || + (operand[3]->integer.value > MAX_MATCH_OPERATOR)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Match operator out of range\n")); + status = AE_AML_OPERAND_VALUE; + goto cleanup; + } + + /* Get the package start_index, validate against the package length */ + + index = (u32) operand[5]->integer.value; + if (index >= (u32) operand[0]->package.count) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index beyond package end\n")); + status = AE_AML_PACKAGE_LIMIT; + goto cleanup; + } + + /* Create an integer for the return value */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + status = AE_NO_MEMORY; + goto cleanup; + + } + + /* Default return value if no match found */ + + return_desc->integer.value = ACPI_INTEGER_MAX; + + /* + * Examine each element until a match is found. Both match conditions + * must be satisfied for a match to occur. Within the loop, + * "continue" signifies that the current element does not match + * and the next should be examined. + * + * Upon finding a match, the loop will terminate via "break" at + * the bottom. If it terminates "normally", match_value will be + * ACPI_INTEGER_MAX (Ones) (its initial value) indicating that no + * match was found. + */ + for ( ; index < operand[0]->package.count; index++) { + /* Get the current package element */ + + this_element = operand[0]->package.elements[index]; + + /* Treat any uninitialized (NULL) elements as non-matching */ + + if (!this_element) { + continue; + } + + /* + * Both match conditions must be satisfied. Execution of a continue + * (proceed to next iteration of enclosing for loop) signifies a + * non-match. + */ + if (!acpi_ex_do_match ((u32) operand[1]->integer.value, + this_element, operand[2])) { + continue; + } + + if (!acpi_ex_do_match ((u32) operand[3]->integer.value, + this_element, operand[4])) { + continue; + } + + /* Match found: Index is the return value */ + + return_desc->integer.value = index; + break; + } + break; + + + case AML_LOAD_TABLE_OP: + + status = acpi_ex_load_table_op (walk_state, &return_desc); + break; + + + default: + + ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n", + walk_state->opcode)); + status = AE_AML_BAD_OPCODE; + goto cleanup; + } + + + walk_state->result_obj = return_desc; + + +cleanup: + + /* Delete return object on error */ + + if (ACPI_FAILURE (status)) { + acpi_ut_remove_reference (return_desc); + } + + return_ACPI_STATUS (status); +} diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c new file mode 100644 index 000000000000..264ef3bba31b --- /dev/null +++ b/drivers/acpi/executer/exprep.c @@ -0,0 +1,530 @@ + +/****************************************************************************** + * + * Module Name: exprep - ACPI AML (p-code) execution - field prep 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/acinterp.h> +#include <acpi/amlcode.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exprep") + + +#ifdef ACPI_UNDER_DEVELOPMENT +/******************************************************************************* + * + * FUNCTION: acpi_ex_generate_access + * + * PARAMETERS: field_bit_offset - Start of field within parent region/buffer + * field_bit_length - Length of field in bits + * region_length - Length of parent in bytes + * + * RETURN: Field granularity (8, 16, 32 or 64) and + * byte_alignment (1, 2, 3, or 4) + * + * DESCRIPTION: Generate an optimal access width for fields defined with the + * any_acc keyword. + * + * NOTE: Need to have the region_length in order to check for boundary + * conditions (end-of-region). However, the region_length is a deferred + * operation. Therefore, to complete this implementation, the generation + * of this access width must be deferred until the region length has + * been evaluated. + * + ******************************************************************************/ + +static u32 +acpi_ex_generate_access ( + u32 field_bit_offset, + u32 field_bit_length, + u32 region_length) +{ + u32 field_byte_length; + u32 field_byte_offset; + u32 field_byte_end_offset; + u32 access_byte_width; + u32 field_start_offset; + u32 field_end_offset; + u32 minimum_access_width = 0xFFFFFFFF; + u32 minimum_accesses = 0xFFFFFFFF; + u32 accesses; + + + ACPI_FUNCTION_TRACE ("ex_generate_access"); + + + /* Round Field start offset and length to "minimal" byte boundaries */ + + field_byte_offset = ACPI_DIV_8 (ACPI_ROUND_DOWN (field_bit_offset, 8)); + field_byte_end_offset = ACPI_DIV_8 (ACPI_ROUND_UP (field_bit_length + field_bit_offset, 8)); + field_byte_length = field_byte_end_offset - field_byte_offset; + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Bit length %d, Bit offset %d\n", + field_bit_length, field_bit_offset)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Byte Length %d, Byte Offset %d, End Offset %d\n", + field_byte_length, field_byte_offset, field_byte_end_offset)); + + /* + * Iterative search for the maximum access width that is both aligned + * and does not go beyond the end of the region + * + * Start at byte_acc and work upwards to qword_acc max. (1,2,4,8 bytes) + */ + for (access_byte_width = 1; access_byte_width <= 8; access_byte_width <<= 1) { + /* + * 1) Round end offset up to next access boundary and make sure that this + * does not go beyond the end of the parent region. + * 2) When the Access width is greater than the field_byte_length, we are done. + * (This does not optimize for the perfectly aligned case yet). + */ + if (ACPI_ROUND_UP (field_byte_end_offset, access_byte_width) <= region_length) { + field_start_offset = ACPI_ROUND_DOWN (field_byte_offset, access_byte_width) / + access_byte_width; + field_end_offset = ACPI_ROUND_UP ((field_byte_length + field_byte_offset), + access_byte_width) / access_byte_width; + accesses = field_end_offset - field_start_offset; + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "access_width %d end is within region\n", access_byte_width)); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field Start %d, Field End %d -- requires %d accesses\n", + field_start_offset, field_end_offset, accesses)); + + /* Single access is optimal */ + + if (accesses <= 1) { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Entire field can be accessed with one operation of size %d\n", + access_byte_width)); + return_VALUE (access_byte_width); + } + + /* + * Fits in the region, but requires more than one read/write. + * try the next wider access on next iteration + */ + if (accesses < minimum_accesses) { + minimum_accesses = accesses; + minimum_access_width = access_byte_width; + } + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "access_width %d end is NOT within region\n", access_byte_width)); + if (access_byte_width == 1) { + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Field goes beyond end-of-region!\n")); + return_VALUE (0); /* Field does not fit in the region at all */ + } + + /* This width goes beyond the end-of-region, back off to previous access */ + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Backing off to previous optimal access width of %d\n", + minimum_access_width)); + return_VALUE (minimum_access_width); + } + } + + /* Could not read/write field with one operation, just use max access width */ + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Cannot access field in one operation, using width 8\n")); + return_VALUE (8); +} +#endif /* ACPI_UNDER_DEVELOPMENT */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_decode_field_access + * + * PARAMETERS: Access - Encoded field access bits + * Length - Field length. + * + * RETURN: Field granularity (8, 16, 32 or 64) and + * byte_alignment (1, 2, 3, or 4) + * + * DESCRIPTION: Decode the access_type bits of a field definition. + * + ******************************************************************************/ + +static u32 +acpi_ex_decode_field_access ( + union acpi_operand_object *obj_desc, + u8 field_flags, + u32 *return_byte_alignment) +{ + u32 access; + u32 byte_alignment; + u32 bit_length; + + + ACPI_FUNCTION_TRACE ("ex_decode_field_access"); + + + access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK); + + switch (access) { + case AML_FIELD_ACCESS_ANY: + +#ifdef ACPI_UNDER_DEVELOPMENT + byte_alignment = acpi_ex_generate_access (obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.bit_length, + 0xFFFFFFFF /* Temp until we pass region_length as param */); + bit_length = byte_alignment * 8; +#endif + + byte_alignment = 1; + bit_length = 8; + break; + + case AML_FIELD_ACCESS_BYTE: + case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 (SMBus Buffer) */ + byte_alignment = 1; + bit_length = 8; + break; + + case AML_FIELD_ACCESS_WORD: + byte_alignment = 2; + bit_length = 16; + break; + + case AML_FIELD_ACCESS_DWORD: + byte_alignment = 4; + bit_length = 32; + break; + + case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */ + byte_alignment = 8; + bit_length = 64; + break; + + default: + /* Invalid field access type */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Unknown field access type %X\n", + access)); + return_VALUE (0); + } + + if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_BUFFER_FIELD) { + /* + * buffer_field access can be on any byte boundary, so the + * byte_alignment is always 1 byte -- regardless of any byte_alignment + * implied by the field access type. + */ + byte_alignment = 1; + } + + *return_byte_alignment = byte_alignment; + return_VALUE (bit_length); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_prep_common_field_object + * + * PARAMETERS: obj_desc - The field object + * field_flags - Access, lock_rule, and update_rule. + * The format of a field_flag is described + * in the ACPI specification + * field_bit_position - Field start position + * field_bit_length - Field length in number of bits + * + * RETURN: Status + * + * DESCRIPTION: Initialize the areas of the field object that are common + * to the various types of fields. Note: This is very "sensitive" + * code because we are solving the general case for field + * alignment. + * + ******************************************************************************/ + +acpi_status +acpi_ex_prep_common_field_object ( + union acpi_operand_object *obj_desc, + u8 field_flags, + u8 field_attribute, + u32 field_bit_position, + u32 field_bit_length) +{ + u32 access_bit_width; + u32 byte_alignment; + u32 nearest_byte_address; + + + ACPI_FUNCTION_TRACE ("ex_prep_common_field_object"); + + + /* + * Note: the structure being initialized is the + * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common + * area are initialized by this procedure. + */ + obj_desc->common_field.field_flags = field_flags; + obj_desc->common_field.attribute = field_attribute; + obj_desc->common_field.bit_length = field_bit_length; + + /* + * Decode the access type so we can compute offsets. The access type gives + * two pieces of information - the width of each field access and the + * necessary byte_alignment (address granularity) of the access. + * + * For any_acc, the access_bit_width is the largest width that is both + * necessary and possible in an attempt to access the whole field in one + * I/O operation. However, for any_acc, the byte_alignment is always one + * byte. + * + * For all Buffer Fields, the byte_alignment is always one byte. + * + * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is + * the same (equivalent) as the byte_alignment. + */ + access_bit_width = acpi_ex_decode_field_access (obj_desc, field_flags, + &byte_alignment); + if (!access_bit_width) { + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + + /* Setup width (access granularity) fields */ + + obj_desc->common_field.access_byte_width = (u8) + ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */ + + obj_desc->common_field.access_bit_width = (u8) access_bit_width; + + /* + * base_byte_offset is the address of the start of the field within the + * region. It is the byte address of the first *datum* (field-width data + * unit) of the field. (i.e., the first datum that contains at least the + * first *bit* of the field.) + * + * Note: byte_alignment is always either equal to the access_bit_width or 8 + * (Byte access), and it defines the addressing granularity of the parent + * region or buffer. + */ + nearest_byte_address = + ACPI_ROUND_BITS_DOWN_TO_BYTES (field_bit_position); + obj_desc->common_field.base_byte_offset = (u32) + ACPI_ROUND_DOWN (nearest_byte_address, byte_alignment); + + /* + * start_field_bit_offset is the offset of the first bit of the field within + * a field datum. + */ + obj_desc->common_field.start_field_bit_offset = (u8) + (field_bit_position - ACPI_MUL_8 (obj_desc->common_field.base_byte_offset)); + + /* + * Does the entire field fit within a single field access element? (datum) + * (i.e., without crossing a datum boundary) + */ + if ((obj_desc->common_field.start_field_bit_offset + field_bit_length) <= + (u16) access_bit_width) { + obj_desc->common.flags |= AOPOBJ_SINGLE_DATUM; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_prep_field_value + * + * PARAMETERS: Node - Owning Node + * region_node - Region in which field is being defined + * field_flags - Access, lock_rule, and update_rule. + * field_bit_position - Field start position + * field_bit_length - Field length in number of bits + * + * RETURN: Status + * + * DESCRIPTION: Construct an union acpi_operand_object of type def_field and + * connect it to the parent Node. + * + ******************************************************************************/ + +acpi_status +acpi_ex_prep_field_value ( + struct acpi_create_field_info *info) +{ + union acpi_operand_object *obj_desc; + u32 type; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ex_prep_field_value"); + + + /* Parameter validation */ + + if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { + if (!info->region_node) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null region_node\n")); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + type = acpi_ns_get_type (info->region_node); + if (type != ACPI_TYPE_REGION) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed Region, found type %X (%s)\n", + type, acpi_ut_get_type_name (type))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + } + + /* Allocate a new field object */ + + obj_desc = acpi_ut_create_internal_object (info->field_type); + if (!obj_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Initialize areas of the object that are common to all fields */ + + obj_desc->common_field.node = info->field_node; + status = acpi_ex_prep_common_field_object (obj_desc, info->field_flags, + info->attribute, info->field_bit_position, info->field_bit_length); + if (ACPI_FAILURE (status)) { + acpi_ut_delete_object_desc (obj_desc); + return_ACPI_STATUS (status); + } + + /* Initialize areas of the object that are specific to the field type */ + + switch (info->field_type) { + case ACPI_TYPE_LOCAL_REGION_FIELD: + + obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node); + + /* An additional reference for the container */ + + acpi_ut_add_reference (obj_desc->field.region_obj); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "region_field: bit_off %X, Off %X, Gran %X, Region %p\n", + obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset, + obj_desc->field.access_byte_width, obj_desc->field.region_obj)); + break; + + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + obj_desc->bank_field.value = info->bank_value; + obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (info->region_node); + obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object (info->register_node); + + /* An additional reference for the attached objects */ + + acpi_ut_add_reference (obj_desc->bank_field.region_obj); + acpi_ut_add_reference (obj_desc->bank_field.bank_obj); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Bank Field: bit_off %X, Off %X, Gran %X, Region %p, bank_reg %p\n", + obj_desc->bank_field.start_field_bit_offset, + obj_desc->bank_field.base_byte_offset, + obj_desc->field.access_byte_width, + obj_desc->bank_field.region_obj, + obj_desc->bank_field.bank_obj)); + break; + + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + obj_desc->index_field.index_obj = acpi_ns_get_attached_object (info->register_node); + obj_desc->index_field.data_obj = acpi_ns_get_attached_object (info->data_register_node); + obj_desc->index_field.value = (u32) + (info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width)); + + if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { + ACPI_REPORT_ERROR (("Null Index Object during field prep\n")); + acpi_ut_delete_object_desc (obj_desc); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* An additional reference for the attached objects */ + + acpi_ut_add_reference (obj_desc->index_field.data_obj); + acpi_ut_add_reference (obj_desc->index_field.index_obj); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "index_field: bit_off %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", + obj_desc->index_field.start_field_bit_offset, + obj_desc->index_field.base_byte_offset, + obj_desc->index_field.value, + obj_desc->field.access_byte_width, + obj_desc->index_field.index_obj, + obj_desc->index_field.data_obj)); + break; + + default: + /* No other types should get here */ + break; + } + + /* + * Store the constructed descriptor (obj_desc) into the parent Node, + * preserving the current type of that named_obj. + */ + status = acpi_ns_attach_object (info->field_node, obj_desc, + acpi_ns_get_type (info->field_node)); + + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Set named_obj %p [%4.4s], obj_desc %p\n", + info->field_node, acpi_ut_get_node_name (info->field_node), obj_desc)); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + return_ACPI_STATUS (status); +} + diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c new file mode 100644 index 000000000000..7cfd0684c70b --- /dev/null +++ b/drivers/acpi/executer/exregion.c @@ -0,0 +1,528 @@ + +/****************************************************************************** + * + * Module Name: exregion - ACPI default op_region (address space) handlers + * + *****************************************************************************/ + +/* + * 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/acinterp.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exregion") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_memory_space_handler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * bit_width - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * handler_context - Pointer to Handler's context + * region_context - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the System Memory address space (Op Region) + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_memory_space_handler ( + u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer *value, + void *handler_context, + void *region_context) +{ + acpi_status status = AE_OK; + void *logical_addr_ptr = NULL; + struct acpi_mem_space_context *mem_info = region_context; + u32 length; + acpi_size window_size; +#ifndef ACPI_MISALIGNED_TRANSFERS + u32 remainder; +#endif + + ACPI_FUNCTION_TRACE ("ex_system_memory_space_handler"); + + + /* Validate and translate the bit width */ + + switch (bit_width) { + case 8: + length = 1; + break; + + case 16: + length = 2; + break; + + case 32: + length = 4; + break; + + case 64: + length = 8; + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid system_memory width %d\n", + bit_width)); + return_ACPI_STATUS (AE_AML_OPERAND_VALUE); + } + + +#ifndef ACPI_MISALIGNED_TRANSFERS + /* + * Hardware does not support non-aligned data transfers, we must verify + * the request. + */ + (void) acpi_ut_short_divide ((acpi_integer) address, length, NULL, &remainder); + if (remainder != 0) { + return_ACPI_STATUS (AE_AML_ALIGNMENT); + } +#endif + + /* + * Does the request fit into the cached memory mapping? + * Is 1) Address below the current mapping? OR + * 2) Address beyond the current mapping? + */ + if ((address < mem_info->mapped_physical_address) || + (((acpi_integer) address + length) > + ((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) { + /* + * The request cannot be resolved by the current memory mapping; + * Delete the existing mapping and create a new one. + */ + if (mem_info->mapped_length) { + /* Valid mapping, delete it */ + + acpi_os_unmap_memory (mem_info->mapped_logical_address, + mem_info->mapped_length); + } + + /* + * Don't attempt to map memory beyond the end of the region, and + * constrain the maximum mapping size to something reasonable. + */ + window_size = (acpi_size) ((mem_info->address + mem_info->length) - address); + if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) { + window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE; + } + + /* Create a new mapping starting at the address given */ + + status = acpi_os_map_memory (address, window_size, + (void **) &mem_info->mapped_logical_address); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n", + ACPI_FORMAT_UINT64 (address), (u32) window_size)); + mem_info->mapped_length = 0; + return_ACPI_STATUS (status); + } + + /* Save the physical address and mapping size */ + + mem_info->mapped_physical_address = address; + mem_info->mapped_length = window_size; + } + + /* + * Generate a logical pointer corresponding to the address we want to + * access + */ + logical_addr_ptr = mem_info->mapped_logical_address + + ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, + ACPI_FORMAT_UINT64 (address))); + + /* + * Perform the memory read or write + * + * Note: For machines that do not support non-aligned transfers, the target + * address was checked for alignment above. We do not attempt to break the + * transfer up into smaller (byte-size) chunks because the AML specifically + * asked for a transfer width that the hardware may require. + */ + switch (function) { + case ACPI_READ: + + *value = 0; + switch (bit_width) { + case 8: + *value = (acpi_integer) *((u8 *) logical_addr_ptr); + break; + + case 16: + *value = (acpi_integer) *((u16 *) logical_addr_ptr); + break; + + case 32: + *value = (acpi_integer) *((u32 *) logical_addr_ptr); + break; + +#if ACPI_MACHINE_WIDTH != 16 + case 64: + *value = (acpi_integer) *((u64 *) logical_addr_ptr); + break; +#endif + default: + /* bit_width was already validated */ + break; + } + break; + + case ACPI_WRITE: + + switch (bit_width) { + case 8: + *(u8 *) logical_addr_ptr = (u8) *value; + break; + + case 16: + *(u16 *) logical_addr_ptr = (u16) *value; + break; + + case 32: + *(u32 *) logical_addr_ptr = (u32) *value; + break; + +#if ACPI_MACHINE_WIDTH != 16 + case 64: + *(u64 *) logical_addr_ptr = (u64) *value; + break; +#endif + + default: + /* bit_width was already validated */ + break; + } + break; + + default: + status = AE_BAD_PARAMETER; + break; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_io_space_handler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * bit_width - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * handler_context - Pointer to Handler's context + * region_context - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the System IO address space (Op Region) + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_io_space_handler ( + u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer *value, + void *handler_context, + void *region_context) +{ + acpi_status status = AE_OK; + u32 value32; + + + ACPI_FUNCTION_TRACE ("ex_system_io_space_handler"); + + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "system_iO %d (%d width) Address=%8.8X%8.8X\n", function, bit_width, + ACPI_FORMAT_UINT64 (address))); + + /* Decode the function parameter */ + + switch (function) { + case ACPI_READ: + + status = acpi_os_read_port ((acpi_io_address) address, &value32, bit_width); + *value = value32; + break; + + case ACPI_WRITE: + + status = acpi_os_write_port ((acpi_io_address) address, (u32) *value, bit_width); + break; + + default: + status = AE_BAD_PARAMETER; + break; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_pci_config_space_handler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * bit_width - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * handler_context - Pointer to Handler's context + * region_context - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the PCI Config address space (Op Region) + * + ******************************************************************************/ + +acpi_status +acpi_ex_pci_config_space_handler ( + u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer *value, + void *handler_context, + void *region_context) +{ + acpi_status status = AE_OK; + struct acpi_pci_id *pci_id; + u16 pci_register; + + + ACPI_FUNCTION_TRACE ("ex_pci_config_space_handler"); + + + /* + * The arguments to acpi_os(Read|Write)pci_configuration are: + * + * pci_segment is the PCI bus segment range 0-31 + * pci_bus is the PCI bus number range 0-255 + * pci_device is the PCI device number range 0-31 + * pci_function is the PCI device function number + * pci_register is the Config space register range 0-255 bytes + * + * Value - input value for write, output address for read + * + */ + pci_id = (struct acpi_pci_id *) region_context; + pci_register = (u16) (u32) address; + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "pci_config %d (%d) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n", + function, bit_width, pci_id->segment, pci_id->bus, pci_id->device, + pci_id->function, pci_register)); + + switch (function) { + case ACPI_READ: + + *value = 0; + status = acpi_os_read_pci_configuration (pci_id, pci_register, value, bit_width); + break; + + case ACPI_WRITE: + + status = acpi_os_write_pci_configuration (pci_id, pci_register, *value, bit_width); + break; + + default: + + status = AE_BAD_PARAMETER; + break; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_cmos_space_handler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * bit_width - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * handler_context - Pointer to Handler's context + * region_context - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the CMOS address space (Op Region) + * + ******************************************************************************/ + +acpi_status +acpi_ex_cmos_space_handler ( + u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer *value, + void *handler_context, + void *region_context) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ex_cmos_space_handler"); + + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_pci_bar_space_handler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * bit_width - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * handler_context - Pointer to Handler's context + * region_context - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the PCI bar_target address space (Op Region) + * + ******************************************************************************/ + +acpi_status +acpi_ex_pci_bar_space_handler ( + u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer *value, + void *handler_context, + void *region_context) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ex_pci_bar_space_handler"); + + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_data_table_space_handler + * + * PARAMETERS: Function - Read or Write operation + * Address - Where in the space to read or write + * bit_width - Field width in bits (8, 16, or 32) + * Value - Pointer to in or out value + * handler_context - Pointer to Handler's context + * region_context - Pointer to context specific to the + * accessed region + * + * RETURN: Status + * + * DESCRIPTION: Handler for the Data Table address space (Op Region) + * + ******************************************************************************/ + +acpi_status +acpi_ex_data_table_space_handler ( + u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer *value, + void *handler_context, + void *region_context) +{ + acpi_status status = AE_OK; + u32 byte_width = ACPI_DIV_8 (bit_width); + u32 i; + char *logical_addr_ptr; + + + ACPI_FUNCTION_TRACE ("ex_data_table_space_handler"); + + + logical_addr_ptr = ACPI_PHYSADDR_TO_PTR (address); + + + /* Perform the memory read or write */ + + switch (function) { + case ACPI_READ: + + for (i = 0; i < byte_width; i++) { + ((char *) value) [i] = logical_addr_ptr[i]; + } + break; + + case ACPI_WRITE: + default: + + return_ACPI_STATUS (AE_SUPPORT); + } + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c new file mode 100644 index 000000000000..7936329a0e35 --- /dev/null +++ b/drivers/acpi/executer/exresnte.c @@ -0,0 +1,289 @@ + +/****************************************************************************** + * + * Module Name: exresnte - AML Interpreter object resolution + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/acnamesp.h> +#include <acpi/acparser.h> +#include <acpi/amlcode.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exresnte") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_resolve_node_to_value + * + * PARAMETERS: object_ptr - Pointer to a location that contains + * a pointer to a NS node, and will receive a + * pointer to the resolved object. + * walk_state - Current state. Valid only if executing AML + * code. NULL if simply resolving an object + * + * RETURN: Status + * + * DESCRIPTION: Resolve a Namespace node to a valued object + * + * Note: for some of the data types, the pointer attached to the Node + * can be either a pointer to an actual internal object or a pointer into the + * AML stream itself. These types are currently: + * + * ACPI_TYPE_INTEGER + * ACPI_TYPE_STRING + * ACPI_TYPE_BUFFER + * ACPI_TYPE_MUTEX + * ACPI_TYPE_PACKAGE + * + ******************************************************************************/ + +acpi_status +acpi_ex_resolve_node_to_value ( + struct acpi_namespace_node **object_ptr, + struct acpi_walk_state *walk_state) + +{ + acpi_status status = AE_OK; + union acpi_operand_object *source_desc; + union acpi_operand_object *obj_desc = NULL; + struct acpi_namespace_node *node; + acpi_object_type entry_type; + + + ACPI_FUNCTION_TRACE ("ex_resolve_node_to_value"); + + + /* + * The stack pointer points to a struct acpi_namespace_node (Node). Get the + * object that is attached to the Node. + */ + node = *object_ptr; + source_desc = acpi_ns_get_attached_object (node); + entry_type = acpi_ns_get_type ((acpi_handle) node); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Entry=%p source_desc=%p [%s]\n", + node, source_desc, acpi_ut_get_type_name (entry_type))); + + if ((entry_type == ACPI_TYPE_LOCAL_ALIAS) || + (entry_type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { + /* There is always exactly one level of indirection */ + + node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object); + source_desc = acpi_ns_get_attached_object (node); + entry_type = acpi_ns_get_type ((acpi_handle) node); + *object_ptr = node; + } + + /* + * Several object types require no further processing: + * 1) Devices rarely have an attached object, return the Node + * 2) Method locals and arguments have a pseudo-Node + */ + if (entry_type == ACPI_TYPE_DEVICE || + (node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) { + return_ACPI_STATUS (AE_OK); + } + + if (!source_desc) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No object attached to node %p\n", + node)); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + /* + * Action is based on the type of the Node, which indicates the type + * of the attached object or pointer + */ + switch (entry_type) { + case ACPI_TYPE_PACKAGE: + + if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_PACKAGE) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a Package, type %s\n", + acpi_ut_get_object_type_name (source_desc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + status = acpi_ds_get_package_arguments (source_desc); + if (ACPI_SUCCESS (status)) { + /* Return an additional reference to the object */ + + obj_desc = source_desc; + acpi_ut_add_reference (obj_desc); + } + break; + + + case ACPI_TYPE_BUFFER: + + if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a Buffer, type %s\n", + acpi_ut_get_object_type_name (source_desc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + status = acpi_ds_get_buffer_arguments (source_desc); + if (ACPI_SUCCESS (status)) { + /* Return an additional reference to the object */ + + obj_desc = source_desc; + acpi_ut_add_reference (obj_desc); + } + break; + + + case ACPI_TYPE_STRING: + + if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_STRING) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a String, type %s\n", + acpi_ut_get_object_type_name (source_desc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Return an additional reference to the object */ + + obj_desc = source_desc; + acpi_ut_add_reference (obj_desc); + break; + + + case ACPI_TYPE_INTEGER: + + if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_INTEGER) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a Integer, type %s\n", + acpi_ut_get_object_type_name (source_desc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Return an additional reference to the object */ + + obj_desc = source_desc; + acpi_ut_add_reference (obj_desc); + break; + + + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "field_read Node=%p source_desc=%p Type=%X\n", + node, source_desc, entry_type)); + + status = acpi_ex_read_data_from_field (walk_state, source_desc, &obj_desc); + break; + + /* + * For these objects, just return the object attached to the Node + */ + case ACPI_TYPE_MUTEX: + case ACPI_TYPE_METHOD: + case ACPI_TYPE_POWER: + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + case ACPI_TYPE_EVENT: + case ACPI_TYPE_REGION: + + /* Return an additional reference to the object */ + + obj_desc = source_desc; + acpi_ut_add_reference (obj_desc); + break; + + + /* TYPE_ANY is untyped, and thus there is no object associated with it */ + + case ACPI_TYPE_ANY: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Untyped entry %p, no attached object!\n", + node)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */ + + + case ACPI_TYPE_LOCAL_REFERENCE: + + switch (source_desc->reference.opcode) { + case AML_LOAD_OP: + + /* This is a ddb_handle */ + /* Return an additional reference to the object */ + + obj_desc = source_desc; + acpi_ut_add_reference (obj_desc); + break; + + default: + /* No named references are allowed here */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode %X (%s)\n", + source_desc->reference.opcode, + acpi_ps_get_opcode_name (source_desc->reference.opcode))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + break; + + + /* Default case is for unknown types */ + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Node %p - Unknown object type %X\n", + node, entry_type)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + + } /* switch (entry_type) */ + + + /* Put the object descriptor on the stack */ + + *object_ptr = (void *) obj_desc; + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c new file mode 100644 index 000000000000..7be604911156 --- /dev/null +++ b/drivers/acpi/executer/exresolv.c @@ -0,0 +1,546 @@ + +/****************************************************************************** + * + * Module Name: exresolv - AML Interpreter object resolution + * + *****************************************************************************/ + +/* + * 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_EXECUTER + ACPI_MODULE_NAME ("exresolv") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_resolve_to_value + * + * PARAMETERS: **stack_ptr - Points to entry on obj_stack, which can + * be either an (union acpi_operand_object *) + * or an acpi_handle. + * walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Convert Reference objects to values + * + ******************************************************************************/ + +acpi_status +acpi_ex_resolve_to_value ( + union acpi_operand_object **stack_ptr, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE_PTR ("ex_resolve_to_value", stack_ptr); + + + if (!stack_ptr || !*stack_ptr) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null pointer\n")); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + /* + * The entity pointed to by the stack_ptr can be either + * 1) A valid union acpi_operand_object, or + * 2) A struct acpi_namespace_node (named_obj) + */ + if (ACPI_GET_DESCRIPTOR_TYPE (*stack_ptr) == ACPI_DESC_TYPE_OPERAND) { + status = acpi_ex_resolve_object_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * Object on the stack may have changed if acpi_ex_resolve_object_to_value() + * was called (i.e., we can't use an _else_ here.) + */ + if (ACPI_GET_DESCRIPTOR_TYPE (*stack_ptr) == ACPI_DESC_TYPE_NAMED) { + status = acpi_ex_resolve_node_to_value ( + ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, stack_ptr), + walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr)); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_resolve_object_to_value + * + * PARAMETERS: stack_ptr - Pointer to a stack location that contains a + * ptr to an internal object. + * walk_state - Current method state + * + * RETURN: Status + * + * DESCRIPTION: Retrieve the value from an internal object. The Reference type + * uses the associated AML opcode to determine the value. + * + ******************************************************************************/ + +acpi_status +acpi_ex_resolve_object_to_value ( + union acpi_operand_object **stack_ptr, + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_operand_object *stack_desc; + void *temp_node; + union acpi_operand_object *obj_desc; + u16 opcode; + + + ACPI_FUNCTION_TRACE ("ex_resolve_object_to_value"); + + + stack_desc = *stack_ptr; + + /* This is an union acpi_operand_object */ + + switch (ACPI_GET_OBJECT_TYPE (stack_desc)) { + case ACPI_TYPE_LOCAL_REFERENCE: + + opcode = stack_desc->reference.opcode; + + switch (opcode) { + case AML_NAME_OP: + + /* + * Convert indirect name ptr to a direct name ptr. + * Then, acpi_ex_resolve_node_to_value can be used to get the value + */ + temp_node = stack_desc->reference.object; + + /* Delete the Reference Object */ + + acpi_ut_remove_reference (stack_desc); + + /* Put direct name pointer onto stack and exit */ + + (*stack_ptr) = temp_node; + break; + + + case AML_LOCAL_OP: + case AML_ARG_OP: + + /* + * Get the local from the method's state info + * Note: this increments the local's object reference count + */ + status = acpi_ds_method_data_get_value (opcode, + stack_desc->reference.offset, walk_state, &obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] value_obj is %p\n", + stack_desc->reference.offset, obj_desc)); + + /* + * Now we can delete the original Reference Object and + * replace it with the resolved value + */ + acpi_ut_remove_reference (stack_desc); + *stack_ptr = obj_desc; + break; + + + case AML_INDEX_OP: + + switch (stack_desc->reference.target_type) { + case ACPI_TYPE_BUFFER_FIELD: + + /* Just return - leave the Reference on the stack */ + break; + + + case ACPI_TYPE_PACKAGE: + + obj_desc = *stack_desc->reference.where; + if (obj_desc) { + /* + * Valid obj descriptor, copy pointer to return value + * (i.e., dereference the package index) + * Delete the ref object, increment the returned object + */ + acpi_ut_remove_reference (stack_desc); + acpi_ut_add_reference (obj_desc); + *stack_ptr = obj_desc; + } + else { + /* + * A NULL object descriptor means an unitialized element of + * the package, can't dereference it + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Attempt to deref an Index to NULL pkg element Idx=%p\n", + stack_desc)); + status = AE_AML_UNINITIALIZED_ELEMENT; + } + break; + + + default: + + /* Invalid reference object */ + + ACPI_REPORT_ERROR (( + "During resolve, Unknown target_type %X in Index/Reference obj %p\n", + stack_desc->reference.target_type, stack_desc)); + status = AE_AML_INTERNAL; + break; + } + break; + + + case AML_REF_OF_OP: + case AML_DEBUG_OP: + case AML_LOAD_OP: + + /* Just leave the object as-is */ + + break; + + + default: + + ACPI_REPORT_ERROR (("During resolve, Unknown Reference opcode %X (%s) in %p\n", + opcode, acpi_ps_get_opcode_name (opcode), stack_desc)); + status = AE_AML_INTERNAL; + break; + } + break; + + + case ACPI_TYPE_BUFFER: + + status = acpi_ds_get_buffer_arguments (stack_desc); + break; + + + case ACPI_TYPE_PACKAGE: + + status = acpi_ds_get_package_arguments (stack_desc); + break; + + + /* + * These cases may never happen here, but just in case.. + */ + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "field_read source_desc=%p Type=%X\n", + stack_desc, ACPI_GET_OBJECT_TYPE (stack_desc))); + + status = acpi_ex_read_data_from_field (walk_state, stack_desc, &obj_desc); + *stack_ptr = (void *) obj_desc; + break; + + default: + break; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_resolve_multiple + * + * PARAMETERS: walk_state - Current state (contains AML opcode) + * Operand - Starting point for resolution + * return_type - Where the object type is returned + * return_desc - Where the resolved object is returned + * + * RETURN: Status + * + * DESCRIPTION: Return the base object and type. Traverse a reference list if + * necessary to get to the base object. + * + ******************************************************************************/ + +acpi_status +acpi_ex_resolve_multiple ( + struct acpi_walk_state *walk_state, + union acpi_operand_object *operand, + acpi_object_type *return_type, + union acpi_operand_object **return_desc) +{ + union acpi_operand_object *obj_desc = (void *) operand; + struct acpi_namespace_node *node; + acpi_object_type type; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("acpi_ex_resolve_multiple"); + + + /* + * Operand can be either a namespace node or an operand descriptor + */ + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { + case ACPI_DESC_TYPE_OPERAND: + type = obj_desc->common.type; + break; + + case ACPI_DESC_TYPE_NAMED: + type = ((struct acpi_namespace_node *) obj_desc)->type; + obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) obj_desc); + + /* If we had an Alias node, use the attached object for type info */ + + if (type == ACPI_TYPE_LOCAL_ALIAS) { + type = ((struct acpi_namespace_node *) obj_desc)->type; + obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) obj_desc); + } + break; + + default: + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + + /* + * If type is anything other than a reference, we are done + */ + if (type != ACPI_TYPE_LOCAL_REFERENCE) { + goto exit; + } + + /* + * For reference objects created via the ref_of or Index operators, + * we need to get to the base object (as per the ACPI specification + * of the object_type and size_of operators). This means traversing + * the list of possibly many nested references. + */ + while (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) { + switch (obj_desc->reference.opcode) { + case AML_REF_OF_OP: + + /* Dereference the reference pointer */ + + node = obj_desc->reference.object; + + /* All "References" point to a NS node */ + + if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { + ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* Get the attached object */ + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + /* No object, use the NS node type */ + + type = acpi_ns_get_type (node); + goto exit; + } + + /* Check for circular references */ + + if (obj_desc == operand) { + return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE); + } + break; + + + case AML_INDEX_OP: + + /* Get the type of this reference (index into another object) */ + + type = obj_desc->reference.target_type; + if (type != ACPI_TYPE_PACKAGE) { + goto exit; + } + + /* + * The main object is a package, we want to get the type + * of the individual package element that is referenced by + * the index. + * + * This could of course in turn be another reference object. + */ + obj_desc = *(obj_desc->reference.where); + if (!obj_desc) { + /* NULL package elements are allowed */ + + type = 0; /* Uninitialized */ + goto exit; + } + break; + + + case AML_INT_NAMEPATH_OP: + + /* Dereference the reference pointer */ + + node = obj_desc->reference.node; + + /* All "References" point to a NS node */ + + if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { + ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* Get the attached object */ + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + /* No object, use the NS node type */ + + type = acpi_ns_get_type (node); + goto exit; + } + + /* Check for circular references */ + + if (obj_desc == operand) { + return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE); + } + break; + + + case AML_LOCAL_OP: + case AML_ARG_OP: + + if (return_desc) { + status = acpi_ds_method_data_get_value (obj_desc->reference.opcode, + obj_desc->reference.offset, walk_state, &obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + acpi_ut_remove_reference (obj_desc); + } + else { + status = acpi_ds_method_data_get_node (obj_desc->reference.opcode, + obj_desc->reference.offset, walk_state, &node); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + type = ACPI_TYPE_ANY; + goto exit; + } + } + break; + + + case AML_DEBUG_OP: + + /* The Debug Object is of type "debug_object" */ + + type = ACPI_TYPE_DEBUG_OBJECT; + goto exit; + + + default: + + ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Unknown Reference subtype %X\n", + obj_desc->reference.opcode)); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + } + + /* + * Now we are guaranteed to have an object that has not been created + * via the ref_of or Index operators. + */ + type = ACPI_GET_OBJECT_TYPE (obj_desc); + + +exit: + /* Convert internal types to external types */ + + switch (type) { + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + type = ACPI_TYPE_FIELD_UNIT; + break; + + case ACPI_TYPE_LOCAL_SCOPE: + + /* Per ACPI Specification, Scope is untyped */ + + type = ACPI_TYPE_ANY; + break; + + default: + /* No change to Type required */ + break; + } + + *return_type = type; + if (return_desc) { + *return_desc = obj_desc; + } + return_ACPI_STATUS (AE_OK); +} + + diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c new file mode 100644 index 000000000000..c92890220c32 --- /dev/null +++ b/drivers/acpi/executer/exresop.c @@ -0,0 +1,661 @@ + +/****************************************************************************** + * + * Module Name: exresop - AML Interpreter operand/object resolution + * + *****************************************************************************/ + +/* + * 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/acparser.h> +#include <acpi/acinterp.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exresop") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_check_object_type + * + * PARAMETERS: type_needed Object type needed + * this_type Actual object type + * Object Object pointer + * + * RETURN: Status + * + * DESCRIPTION: Check required type against actual type + * + ******************************************************************************/ + +acpi_status +acpi_ex_check_object_type ( + acpi_object_type type_needed, + acpi_object_type this_type, + void *object) +{ + ACPI_FUNCTION_NAME ("ex_check_object_type"); + + + if (type_needed == ACPI_TYPE_ANY) { + /* All types OK, so we don't perform any typechecks */ + + return (AE_OK); + } + + if (type_needed == ACPI_TYPE_LOCAL_REFERENCE) { + /* + * Allow the AML "Constant" opcodes (Zero, One, etc.) to be reference + * objects and thus allow them to be targets. (As per the ACPI + * specification, a store to a constant is a noop.) + */ + if ((this_type == ACPI_TYPE_INTEGER) && + (((union acpi_operand_object *) object)->common.flags & AOPOBJ_AML_CONSTANT)) { + return (AE_OK); + } + } + + if (type_needed != this_type) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [%s], found [%s] %p\n", + acpi_ut_get_type_name (type_needed), + acpi_ut_get_type_name (this_type), object)); + + return (AE_AML_OPERAND_TYPE); + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_resolve_operands + * + * PARAMETERS: Opcode - Opcode being interpreted + * stack_ptr - Pointer to the operand stack to be + * resolved + * walk_state - Current state + * + * RETURN: Status + * + * DESCRIPTION: Convert multiple input operands to the types required by the + * target operator. + * + * Each 5-bit group in arg_types represents one required + * operand and indicates the required Type. The corresponding operand + * will be converted to the required type if possible, otherwise we + * abort with an exception. + * + ******************************************************************************/ + +acpi_status +acpi_ex_resolve_operands ( + u16 opcode, + union acpi_operand_object **stack_ptr, + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *obj_desc; + acpi_status status = AE_OK; + u8 object_type; + void *temp_node; + u32 arg_types; + const struct acpi_opcode_info *op_info; + u32 this_arg_type; + acpi_object_type type_needed; + + + ACPI_FUNCTION_TRACE_U32 ("ex_resolve_operands", opcode); + + + op_info = acpi_ps_get_opcode_info (opcode); + if (op_info->class == AML_CLASS_UNKNOWN) { + return_ACPI_STATUS (AE_AML_BAD_OPCODE); + } + + arg_types = op_info->runtime_args; + if (arg_types == ARGI_INVALID_OPCODE) { + ACPI_REPORT_ERROR (("resolve_operands: %X is not a valid AML opcode\n", + opcode)); + + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] required_operand_types=%8.8X \n", + opcode, op_info->name, arg_types)); + + /* + * Normal exit is with (arg_types == 0) at end of argument list. + * Function will return an exception from within the loop upon + * finding an entry which is not (or cannot be converted + * to) the required type; if stack underflows; or upon + * finding a NULL stack entry (which should not happen). + */ + while (GET_CURRENT_ARG_TYPE (arg_types)) { + if (!stack_ptr || !*stack_ptr) { + ACPI_REPORT_ERROR (("resolve_operands: Null stack entry at %p\n", + stack_ptr)); + + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* Extract useful items */ + + obj_desc = *stack_ptr; + + /* Decode the descriptor type */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { + case ACPI_DESC_TYPE_NAMED: + + /* Node */ + + object_type = ((struct acpi_namespace_node *) obj_desc)->type; + break; + + + case ACPI_DESC_TYPE_OPERAND: + + /* ACPI internal object */ + + object_type = ACPI_GET_OBJECT_TYPE (obj_desc); + + /* Check for bad acpi_object_type */ + + if (!acpi_ut_valid_object_type (object_type)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad operand object type [%X]\n", + object_type)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) { + /* + * Decode the Reference + */ + op_info = acpi_ps_get_opcode_info (opcode); + if (op_info->class == AML_CLASS_UNKNOWN) { + return_ACPI_STATUS (AE_AML_BAD_OPCODE); + } + + switch (obj_desc->reference.opcode) { + case AML_DEBUG_OP: + case AML_NAME_OP: + case AML_INDEX_OP: + case AML_REF_OF_OP: + case AML_ARG_OP: + case AML_LOCAL_OP: + case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */ + + ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Operand is a Reference, ref_opcode [%s]\n", + (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name))); + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Operand is a Reference, Unknown Reference Opcode %X [%s]\n", + obj_desc->reference.opcode, + (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + } + break; + + + default: + + /* Invalid descriptor */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Invalid descriptor %p [%s]\n", + obj_desc, acpi_ut_get_descriptor_name (obj_desc))); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + + /* + * Get one argument type, point to the next + */ + this_arg_type = GET_CURRENT_ARG_TYPE (arg_types); + INCREMENT_ARG_LIST (arg_types); + + /* + * Handle cases where the object does not need to be + * resolved to a value + */ + switch (this_arg_type) { + case ARGI_REF_OR_STRING: /* Can be a String or Reference */ + + if ((ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_OPERAND) && + (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_STRING)) { + /* + * String found - the string references a named object and must be + * resolved to a node + */ + goto next_operand; + } + + /* Else not a string - fall through to the normal Reference case below */ + /*lint -fallthrough */ + + case ARGI_REFERENCE: /* References: */ + case ARGI_INTEGER_REF: + case ARGI_OBJECT_REF: + case ARGI_DEVICE_REF: + case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ + case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ + case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */ + + /* Need an operand of type ACPI_TYPE_LOCAL_REFERENCE */ + + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) /* Node (name) ptr OK as-is */ { + goto next_operand; + } + + status = acpi_ex_check_object_type (ACPI_TYPE_LOCAL_REFERENCE, + object_type, obj_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (AML_NAME_OP == obj_desc->reference.opcode) { + /* + * Convert an indirect name ptr to direct name ptr and put + * it on the stack + */ + temp_node = obj_desc->reference.object; + acpi_ut_remove_reference (obj_desc); + (*stack_ptr) = temp_node; + } + goto next_operand; + + + case ARGI_DATAREFOBJ: /* Store operator only */ + + /* + * We don't want to resolve index_op reference objects during + * a store because this would be an implicit de_ref_of operation. + * Instead, we just want to store the reference object. + * -- All others must be resolved below. + */ + if ((opcode == AML_STORE_OP) && + (ACPI_GET_OBJECT_TYPE (*stack_ptr) == ACPI_TYPE_LOCAL_REFERENCE) && + ((*stack_ptr)->reference.opcode == AML_INDEX_OP)) { + goto next_operand; + } + break; + + default: + /* All cases covered above */ + break; + } + + + /* + * Resolve this object to a value + */ + status = acpi_ex_resolve_to_value (stack_ptr, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Get the resolved object */ + + obj_desc = *stack_ptr; + + /* + * Check the resulting object (value) type + */ + switch (this_arg_type) { + /* + * For the simple cases, only one type of resolved object + * is allowed + */ + case ARGI_MUTEX: + + /* Need an operand of type ACPI_TYPE_MUTEX */ + + type_needed = ACPI_TYPE_MUTEX; + break; + + case ARGI_EVENT: + + /* Need an operand of type ACPI_TYPE_EVENT */ + + type_needed = ACPI_TYPE_EVENT; + break; + + case ARGI_PACKAGE: /* Package */ + + /* Need an operand of type ACPI_TYPE_PACKAGE */ + + type_needed = ACPI_TYPE_PACKAGE; + break; + + case ARGI_ANYTYPE: + + /* Any operand type will do */ + + type_needed = ACPI_TYPE_ANY; + break; + + case ARGI_DDBHANDLE: + + /* Need an operand of type ACPI_TYPE_DDB_HANDLE */ + + type_needed = ACPI_TYPE_LOCAL_REFERENCE; + break; + + + /* + * The more complex cases allow multiple resolved object types + */ + case ARGI_INTEGER: /* Number */ + + /* + * Need an operand of type ACPI_TYPE_INTEGER, + * But we can implicitly convert from a STRING or BUFFER + * Aka - "Implicit Source Operand Conversion" + */ + status = acpi_ex_convert_to_integer (obj_desc, stack_ptr, 16); + if (ACPI_FAILURE (status)) { + if (status == AE_TYPE) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Integer/String/Buffer], found [%s] %p\n", + acpi_ut_get_object_type_name (obj_desc), obj_desc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + return_ACPI_STATUS (status); + } + goto next_operand; + + + case ARGI_BUFFER: + + /* + * Need an operand of type ACPI_TYPE_BUFFER, + * But we can implicitly convert from a STRING or INTEGER + * Aka - "Implicit Source Operand Conversion" + */ + status = acpi_ex_convert_to_buffer (obj_desc, stack_ptr); + if (ACPI_FAILURE (status)) { + if (status == AE_TYPE) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Integer/String/Buffer], found [%s] %p\n", + acpi_ut_get_object_type_name (obj_desc), obj_desc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + return_ACPI_STATUS (status); + } + goto next_operand; + + + case ARGI_STRING: + + /* + * Need an operand of type ACPI_TYPE_STRING, + * But we can implicitly convert from a BUFFER or INTEGER + * Aka - "Implicit Source Operand Conversion" + */ + status = acpi_ex_convert_to_string (obj_desc, stack_ptr, + ACPI_IMPLICIT_CONVERT_HEX); + if (ACPI_FAILURE (status)) { + if (status == AE_TYPE) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Integer/String/Buffer], found [%s] %p\n", + acpi_ut_get_object_type_name (obj_desc), obj_desc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + return_ACPI_STATUS (status); + } + goto next_operand; + + + case ARGI_COMPUTEDATA: + + /* Need an operand of type INTEGER, STRING or BUFFER */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* Valid operand */ + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Integer/String/Buffer], found [%s] %p\n", + acpi_ut_get_object_type_name (obj_desc), obj_desc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto next_operand; + + + case ARGI_BUFFER_OR_STRING: + + /* Need an operand of type STRING or BUFFER */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* Valid operand */ + break; + + case ACPI_TYPE_INTEGER: + + /* Highest priority conversion is to type Buffer */ + + status = acpi_ex_convert_to_buffer (obj_desc, stack_ptr); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Integer/String/Buffer], found [%s] %p\n", + acpi_ut_get_object_type_name (obj_desc), obj_desc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto next_operand; + + + case ARGI_DATAOBJECT: + /* + * ARGI_DATAOBJECT is only used by the size_of operator. + * Need a buffer, string, package, or ref_of reference. + * + * The only reference allowed here is a direct reference to + * a namespace node. + */ + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_LOCAL_REFERENCE: + + /* Valid operand */ + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Buffer/String/Package/Reference], found [%s] %p\n", + acpi_ut_get_object_type_name (obj_desc), obj_desc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto next_operand; + + + case ARGI_COMPLEXOBJ: + + /* Need a buffer or package or (ACPI 2.0) String */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* Valid operand */ + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Buffer/String/Package], found [%s] %p\n", + acpi_ut_get_object_type_name (obj_desc), obj_desc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto next_operand; + + + case ARGI_REGION_OR_FIELD: + + /* Need an operand of type ACPI_TYPE_REGION or a FIELD in a region */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_REGION: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + /* Valid operand */ + break; + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed [Region/region_field], found [%s] %p\n", + acpi_ut_get_object_type_name (obj_desc), obj_desc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto next_operand; + + + case ARGI_DATAREFOBJ: + + /* Used by the Store() operator only */ + + switch (ACPI_GET_OBJECT_TYPE (obj_desc)) { + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_PACKAGE: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REFERENCE: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + case ACPI_TYPE_DDB_HANDLE: + + /* Valid operand */ + break; + + default: + + if (acpi_gbl_enable_interpreter_slack) { + /* + * Enable original behavior of Store(), allowing any and all + * objects as the source operand. The ACPI spec does not + * allow this, however. + */ + break; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p\n", + acpi_ut_get_object_type_name (obj_desc), obj_desc)); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + goto next_operand; + + + default: + + /* Unknown type */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Internal - Unknown ARGI (required operand) type %X\n", + this_arg_type)); + + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Make sure that the original object was resolved to the + * required object type (Simple cases only). + */ + status = acpi_ex_check_object_type (type_needed, + ACPI_GET_OBJECT_TYPE (*stack_ptr), *stack_ptr); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + +next_operand: + /* + * If more operands needed, decrement stack_ptr to point + * to next operand on stack + */ + if (GET_CURRENT_ARG_TYPE (arg_types)) { + stack_ptr--; + } + + } /* while (*Types) */ + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c new file mode 100644 index 000000000000..e0fc6aba1253 --- /dev/null +++ b/drivers/acpi/executer/exstore.c @@ -0,0 +1,536 @@ + +/****************************************************************************** + * + * Module Name: exstore - AML Interpreter object store support + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/amlcode.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exstore") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_store + * + * PARAMETERS: *source_desc - Value to be stored + * *dest_desc - Where to store it. Must be an NS node + * or an union acpi_operand_object of type + * Reference; + * walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Store the value described by source_desc into the location + * described by dest_desc. Called by various interpreter + * functions to store the result of an operation into + * the destination operand -- not just simply the actual "Store" + * ASL operator. + * + ******************************************************************************/ + +acpi_status +acpi_ex_store ( + union acpi_operand_object *source_desc, + union acpi_operand_object *dest_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_operand_object *ref_desc = dest_desc; + + + ACPI_FUNCTION_TRACE_PTR ("ex_store", dest_desc); + + + /* Validate parameters */ + + if (!source_desc || !dest_desc) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null parameter\n")); + return_ACPI_STATUS (AE_AML_NO_OPERAND); + } + + /* dest_desc can be either a namespace node or an ACPI object */ + + if (ACPI_GET_DESCRIPTOR_TYPE (dest_desc) == ACPI_DESC_TYPE_NAMED) { + /* + * Dest is a namespace node, + * Storing an object into a Named node. + */ + status = acpi_ex_store_object_to_node (source_desc, + (struct acpi_namespace_node *) dest_desc, walk_state, + ACPI_IMPLICIT_CONVERSION); + + return_ACPI_STATUS (status); + } + + /* Destination object must be a Reference or a Constant object */ + + switch (ACPI_GET_OBJECT_TYPE (dest_desc)) { + case ACPI_TYPE_LOCAL_REFERENCE: + break; + + case ACPI_TYPE_INTEGER: + + /* Allow stores to Constants -- a Noop as per ACPI spec */ + + if (dest_desc->common.flags & AOPOBJ_AML_CONSTANT) { + return_ACPI_STATUS (AE_OK); + } + + /*lint -fallthrough */ + + default: + + /* Destination is not a Reference object */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Target is not a Reference or Constant object - %s [%p]\n", + acpi_ut_get_object_type_name (dest_desc), dest_desc)); + + ACPI_DUMP_STACK_ENTRY (source_desc); + ACPI_DUMP_STACK_ENTRY (dest_desc); + ACPI_DUMP_OPERANDS (&dest_desc, ACPI_IMODE_EXECUTE, "ex_store", + 2, "Target is not a Reference or Constant object"); + + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * Examine the Reference opcode. These cases are handled: + * + * 1) Store to Name (Change the object associated with a name) + * 2) Store to an indexed area of a Buffer or Package + * 3) Store to a Method Local or Arg + * 4) Store to the debug object + */ + switch (ref_desc->reference.opcode) { + case AML_NAME_OP: + case AML_REF_OF_OP: + + /* Storing an object into a Name "container" */ + + status = acpi_ex_store_object_to_node (source_desc, ref_desc->reference.object, + walk_state, ACPI_IMPLICIT_CONVERSION); + break; + + + case AML_INDEX_OP: + + /* Storing to an Index (pointer into a packager or buffer) */ + + status = acpi_ex_store_object_to_index (source_desc, ref_desc, walk_state); + break; + + + case AML_LOCAL_OP: + case AML_ARG_OP: + + /* Store to a method local/arg */ + + status = acpi_ds_store_object_to_local (ref_desc->reference.opcode, + ref_desc->reference.offset, source_desc, walk_state); + break; + + + case AML_DEBUG_OP: + + /* + * Storing to the Debug object causes the value stored to be + * displayed and otherwise has no effect -- see ACPI Specification + */ + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "**** Write to Debug Object: Object %p %s ****:\n\n", + source_desc, acpi_ut_get_object_type_name (source_desc))); + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %s: ", + acpi_ut_get_object_type_name (source_desc))); + + if (!acpi_ut_valid_internal_object (source_desc)) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, + "%p, Invalid Internal Object!\n", source_desc)); + break; + } + + switch (ACPI_GET_OBJECT_TYPE (source_desc)) { + case ACPI_TYPE_INTEGER: + + if (acpi_gbl_integer_byte_width == 4) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n", + (u32) source_desc->integer.value)); + } + else { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (source_desc->integer.value))); + } + break; + + + case ACPI_TYPE_BUFFER: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]", + (u32) source_desc->buffer.length)); + ACPI_DUMP_BUFFER (source_desc->buffer.pointer, + (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32); + break; + + + case ACPI_TYPE_STRING: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n", + source_desc->string.length, source_desc->string.pointer)); + break; + + + case ACPI_TYPE_PACKAGE: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] Elements Ptr - %p\n", + source_desc->package.count, source_desc->package.elements)); + break; + + + default: + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p\n", + source_desc)); + break; + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n")); + break; + + + default: + + ACPI_REPORT_ERROR (("ex_store: Unknown Reference opcode %X\n", + ref_desc->reference.opcode)); + ACPI_DUMP_ENTRY (ref_desc, ACPI_LV_ERROR); + + status = AE_AML_INTERNAL; + break; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_store_object_to_index + * + * PARAMETERS: *source_desc - Value to be stored + * *dest_desc - Named object to receive the value + * walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Store the object to indexed Buffer or Package element + * + ******************************************************************************/ + +acpi_status +acpi_ex_store_object_to_index ( + union acpi_operand_object *source_desc, + union acpi_operand_object *index_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_operand_object *obj_desc; + union acpi_operand_object *new_desc; + u8 value = 0; + u32 i; + + + ACPI_FUNCTION_TRACE ("ex_store_object_to_index"); + + + /* + * Destination must be a reference pointer, and + * must point to either a buffer or a package + */ + switch (index_desc->reference.target_type) { + case ACPI_TYPE_PACKAGE: + /* + * Storing to a package element. Copy the object and replace + * any existing object with the new object. No implicit + * conversion is performed. + * + * The object at *(index_desc->Reference.Where) is the + * element within the package that is to be modified. + * The parent package object is at index_desc->Reference.Object + */ + obj_desc = *(index_desc->reference.where); + + status = acpi_ut_copy_iobject_to_iobject (source_desc, &new_desc, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (obj_desc) { + /* Decrement reference count by the ref count of the parent package */ + + for (i = 0; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) { + acpi_ut_remove_reference (obj_desc); + } + } + + *(index_desc->reference.where) = new_desc; + + /* Increment reference count by the ref count of the parent package -1 */ + + for (i = 1; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) { + acpi_ut_add_reference (new_desc); + } + + break; + + + case ACPI_TYPE_BUFFER_FIELD: + + /* + * Store into a Buffer or String (not actually a real buffer_field) + * at a location defined by an Index. + * + * The first 8-bit element of the source object is written to the + * 8-bit Buffer location defined by the Index destination object, + * according to the ACPI 2.0 specification. + */ + + /* + * Make sure the target is a Buffer or String. An error should + * not happen here, since the reference_object was constructed + * by the INDEX_OP code. + */ + obj_desc = index_desc->reference.object; + if ((ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_BUFFER) && + (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_STRING)) { + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* + * The assignment of the individual elements will be slightly + * different for each source type. + */ + switch (ACPI_GET_OBJECT_TYPE (source_desc)) { + case ACPI_TYPE_INTEGER: + + /* Use the least-significant byte of the integer */ + + value = (u8) (source_desc->integer.value); + break; + + case ACPI_TYPE_BUFFER: + case ACPI_TYPE_STRING: + + /* Note: Takes advantage of common string/buffer fields */ + + value = source_desc->buffer.pointer[0]; + break; + + default: + + /* All other types are invalid */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Source must be Integer/Buffer/String type, not %s\n", + acpi_ut_get_object_type_name (source_desc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + /* Store the source value into the target buffer byte */ + + obj_desc->buffer.pointer[index_desc->reference.offset] = value; + break; + + + default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Target is not a Package or buffer_field\n")); + status = AE_AML_OPERAND_TYPE; + break; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_store_object_to_node + * + * PARAMETERS: source_desc - Value to be stored + * Node - Named object to receive the value + * walk_state - Current walk state + * implicit_conversion - Perform implicit conversion (yes/no) + * + * RETURN: Status + * + * DESCRIPTION: Store the object to the named object. + * + * The Assignment of an object to a named object is handled here + * The value passed in will replace the current value (if any) + * with the input value. + * + * When storing into an object the data is converted to the + * target object type then stored in the object. This means + * that the target object type (for an initialized target) will + * not be changed by a store operation. + * + * Assumes parameters are already validated. + * + ******************************************************************************/ + +acpi_status +acpi_ex_store_object_to_node ( + union acpi_operand_object *source_desc, + struct acpi_namespace_node *node, + struct acpi_walk_state *walk_state, + u8 implicit_conversion) +{ + acpi_status status = AE_OK; + union acpi_operand_object *target_desc; + union acpi_operand_object *new_desc; + acpi_object_type target_type; + + + ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_node", source_desc); + + + /* + * Get current type of the node, and object attached to Node + */ + target_type = acpi_ns_get_type (node); + target_desc = acpi_ns_get_attached_object (node); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n", + source_desc, acpi_ut_get_object_type_name (source_desc), + node, acpi_ut_get_type_name (target_type))); + + /* + * Resolve the source object to an actual value + * (If it is a reference object) + */ + status = acpi_ex_resolve_object (&source_desc, target_type, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* If no implicit conversion, drop into the default case below */ + + if (!implicit_conversion) { + /* Force execution of default (no implicit conversion) */ + + target_type = ACPI_TYPE_ANY; + } + + /* + * Do the actual store operation + */ + switch (target_type) { + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + /* + * For fields, copy the source data to the target field. + */ + status = acpi_ex_write_data_to_field (source_desc, target_desc, &walk_state->result_obj); + break; + + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* + * These target types are all of type Integer/String/Buffer, and + * therefore support implicit conversion before the store. + * + * Copy and/or convert the source object to a new target object + */ + status = acpi_ex_store_object_to_object (source_desc, target_desc, &new_desc, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (new_desc != target_desc) { + /* + * Store the new new_desc as the new value of the Name, and set + * the Name's type to that of the value being stored in it. + * source_desc reference count is incremented by attach_object. + * + * Note: This may change the type of the node if an explicit store + * has been performed such that the node/object type has been + * changed. + */ + status = acpi_ns_attach_object (node, new_desc, new_desc->common.type); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Store %s into %s via Convert/Attach\n", + acpi_ut_get_object_type_name (source_desc), + acpi_ut_get_object_type_name (new_desc))); + } + break; + + + default: + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Storing %s (%p) directly into node (%p), no implicit conversion\n", + acpi_ut_get_object_type_name (source_desc), source_desc, node)); + + /* No conversions for all other types. Just attach the source object */ + + status = acpi_ns_attach_object (node, source_desc, ACPI_GET_OBJECT_TYPE (source_desc)); + break; + } + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c new file mode 100644 index 000000000000..d3677feb07fd --- /dev/null +++ b/drivers/acpi/executer/exstoren.c @@ -0,0 +1,306 @@ + +/****************************************************************************** + * + * Module Name: exstoren - AML Interpreter object store support, + * Store to Node (namespace object) + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/amlcode.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exstoren") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_resolve_object + * + * PARAMETERS: source_desc_ptr - Pointer to the source object + * target_type - Current type of the target + * walk_state - Current walk state + * + * RETURN: Status, resolved object in source_desc_ptr. + * + * DESCRIPTION: Resolve an object. If the object is a reference, dereference + * it and return the actual object in the source_desc_ptr. + * + ******************************************************************************/ + +acpi_status +acpi_ex_resolve_object ( + union acpi_operand_object **source_desc_ptr, + acpi_object_type target_type, + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *source_desc = *source_desc_ptr; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ex_resolve_object"); + + + /* + * Ensure we have a Target that can be stored to + */ + switch (target_type) { + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + /* + * These cases all require only Integers or values that + * can be converted to Integers (Strings or Buffers) + */ + + case ACPI_TYPE_INTEGER: + case ACPI_TYPE_STRING: + case ACPI_TYPE_BUFFER: + + /* + * Stores into a Field/Region or into a Integer/Buffer/String + * are all essentially the same. This case handles the + * "interchangeable" types Integer, String, and Buffer. + */ + if (ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_LOCAL_REFERENCE) { + /* Resolve a reference object first */ + + status = acpi_ex_resolve_to_value (source_desc_ptr, walk_state); + if (ACPI_FAILURE (status)) { + break; + } + } + + /* For copy_object, no further validation necessary */ + + if (walk_state->opcode == AML_COPY_OP) { + break; + } + + /* + * Must have a Integer, Buffer, or String + */ + if ((ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_INTEGER) && + (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) && + (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_STRING) && + !((ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_LOCAL_REFERENCE) && (source_desc->reference.opcode == AML_LOAD_OP))) { + /* + * Conversion successful but still not a valid type + */ + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Cannot assign type %s to %s (must be type Int/Str/Buf)\n", + acpi_ut_get_object_type_name (source_desc), + acpi_ut_get_type_name (target_type))); + status = AE_AML_OPERAND_TYPE; + } + break; + + + case ACPI_TYPE_LOCAL_ALIAS: + case ACPI_TYPE_LOCAL_METHOD_ALIAS: + + /* + * Aliases are resolved by acpi_ex_prep_operands + */ + ACPI_REPORT_ERROR (("Store into Alias - should never happen\n")); + status = AE_AML_INTERNAL; + break; + + + case ACPI_TYPE_PACKAGE: + default: + + /* + * All other types than Alias and the various Fields come here, + * including the untyped case - ACPI_TYPE_ANY. + */ + break; + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_store_object_to_object + * + * PARAMETERS: source_desc - Object to store + * dest_desc - Object to receive a copy of the source + * new_desc - New object if dest_desc is obsoleted + * walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: "Store" an object to another object. This may include + * converting the source type to the target type (implicit + * conversion), and a copy of the value of the source to + * the target. + * + * The Assignment of an object to another (not named) object + * is handled here. + * The Source passed in will replace the current value (if any) + * with the input value. + * + * When storing into an object the data is converted to the + * target object type then stored in the object. This means + * that the target object type (for an initialized target) will + * not be changed by a store operation. + * + * This module allows destination types of Number, String, + * Buffer, and Package. + * + * Assumes parameters are already validated. NOTE: source_desc + * resolution (from a reference object) must be performed by + * the caller if necessary. + * + ******************************************************************************/ + +acpi_status +acpi_ex_store_object_to_object ( + union acpi_operand_object *source_desc, + union acpi_operand_object *dest_desc, + union acpi_operand_object **new_desc, + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *actual_src_desc; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_object", source_desc); + + + actual_src_desc = source_desc; + if (!dest_desc) { + /* + * There is no destination object (An uninitialized node or + * package element), so we can simply copy the source object + * creating a new destination object + */ + status = acpi_ut_copy_iobject_to_iobject (actual_src_desc, new_desc, walk_state); + return_ACPI_STATUS (status); + } + + if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_GET_OBJECT_TYPE (dest_desc)) { + /* + * The source type does not match the type of the destination. + * Perform the "implicit conversion" of the source to the current type + * of the target as per the ACPI specification. + * + * If no conversion performed, actual_src_desc = source_desc. + * Otherwise, actual_src_desc is a temporary object to hold the + * converted object. + */ + status = acpi_ex_convert_to_target_type (ACPI_GET_OBJECT_TYPE (dest_desc), + source_desc, &actual_src_desc, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (source_desc == actual_src_desc) { + /* + * No conversion was performed. Return the source_desc as the + * new object. + */ + *new_desc = source_desc; + return_ACPI_STATUS (AE_OK); + } + } + + /* + * We now have two objects of identical types, and we can perform a + * copy of the *value* of the source object. + */ + switch (ACPI_GET_OBJECT_TYPE (dest_desc)) { + case ACPI_TYPE_INTEGER: + + dest_desc->integer.value = actual_src_desc->integer.value; + + /* Truncate value if we are executing from a 32-bit ACPI table */ + + acpi_ex_truncate_for32bit_table (dest_desc); + break; + + case ACPI_TYPE_STRING: + + status = acpi_ex_store_string_to_string (actual_src_desc, dest_desc); + break; + + case ACPI_TYPE_BUFFER: + + /* + * Note: There is different store behavior depending on the original + * source type + */ + status = acpi_ex_store_buffer_to_buffer (actual_src_desc, dest_desc); + break; + + case ACPI_TYPE_PACKAGE: + + status = acpi_ut_copy_iobject_to_iobject (actual_src_desc, &dest_desc, + walk_state); + break; + + default: + /* + * All other types come here. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Store into type %s not implemented\n", + acpi_ut_get_object_type_name (dest_desc))); + + status = AE_NOT_IMPLEMENTED; + break; + } + + if (actual_src_desc != source_desc) { + /* Delete the intermediate (temporary) source object */ + + acpi_ut_remove_reference (actual_src_desc); + } + + *new_desc = dest_desc; + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c new file mode 100644 index 000000000000..05e1ecae8d92 --- /dev/null +++ b/drivers/acpi/executer/exstorob.c @@ -0,0 +1,216 @@ + +/****************************************************************************** + * + * Module Name: exstorob - AML Interpreter object store support, store to object + * + *****************************************************************************/ + +/* + * 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/acinterp.h> + + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exstorob") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_store_buffer_to_buffer + * + * PARAMETERS: source_desc - Source object to copy + * target_desc - Destination object of the copy + * + * RETURN: Status + * + * DESCRIPTION: Copy a buffer object to another buffer object. + * + ******************************************************************************/ + +acpi_status +acpi_ex_store_buffer_to_buffer ( + union acpi_operand_object *source_desc, + union acpi_operand_object *target_desc) +{ + u32 length; + u8 *buffer; + + + ACPI_FUNCTION_TRACE_PTR ("ex_store_buffer_to_buffer", source_desc); + + + /* We know that source_desc is a buffer by now */ + + buffer = (u8 *) source_desc->buffer.pointer; + length = source_desc->buffer.length; + + /* + * If target is a buffer of length zero or is a static buffer, + * allocate a new buffer of the proper length + */ + if ((target_desc->buffer.length == 0) || + (target_desc->common.flags & AOPOBJ_STATIC_POINTER)) { + target_desc->buffer.pointer = ACPI_MEM_ALLOCATE (length); + if (!target_desc->buffer.pointer) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + target_desc->buffer.length = length; + } + + /* Copy source buffer to target buffer */ + + if (length <= target_desc->buffer.length) { + /* Clear existing buffer and copy in the new one */ + + ACPI_MEMSET (target_desc->buffer.pointer, 0, target_desc->buffer.length); + ACPI_MEMCPY (target_desc->buffer.pointer, buffer, length); + +#ifdef ACPI_OBSOLETE_BEHAVIOR + /* + * NOTE: ACPI versions up to 3.0 specified that the buffer must be + * truncated if the string is smaller than the buffer. However, "other" + * implementations of ACPI never did this and thus became the defacto + * standard. ACPi 3.0_a changes this behavior such that the buffer + * is no longer truncated. + */ + + /* + * OBSOLETE BEHAVIOR: + * If the original source was a string, we must truncate the buffer, + * according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer + * copy must not truncate the original buffer. + */ + if (original_src_type == ACPI_TYPE_STRING) { + /* Set the new length of the target */ + + target_desc->buffer.length = length; + } +#endif + } + else { + /* Truncate the source, copy only what will fit */ + + ACPI_MEMCPY (target_desc->buffer.pointer, buffer, target_desc->buffer.length); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Truncating source buffer from %X to %X\n", + length, target_desc->buffer.length)); + } + + /* Copy flags */ + + target_desc->buffer.flags = source_desc->buffer.flags; + target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER; + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_store_string_to_string + * + * PARAMETERS: source_desc - Source object to copy + * target_desc - Destination object of the copy + * + * RETURN: Status + * + * DESCRIPTION: Copy a String object to another String object + * + ******************************************************************************/ + +acpi_status +acpi_ex_store_string_to_string ( + union acpi_operand_object *source_desc, + union acpi_operand_object *target_desc) +{ + u32 length; + u8 *buffer; + + + ACPI_FUNCTION_TRACE_PTR ("ex_store_string_to_string", source_desc); + + + /* We know that source_desc is a string by now */ + + buffer = (u8 *) source_desc->string.pointer; + length = source_desc->string.length; + + /* + * Replace existing string value if it will fit and the string + * pointer is not a static pointer (part of an ACPI table) + */ + if ((length < target_desc->string.length) && + (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) { + /* + * String will fit in existing non-static buffer. + * Clear old string and copy in the new one + */ + ACPI_MEMSET (target_desc->string.pointer, 0, (acpi_size) target_desc->string.length + 1); + ACPI_MEMCPY (target_desc->string.pointer, buffer, length); + } + else { + /* + * Free the current buffer, then allocate a new buffer + * large enough to hold the value + */ + if (target_desc->string.pointer && + (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) { + /* Only free if not a pointer into the DSDT */ + + ACPI_MEM_FREE (target_desc->string.pointer); + } + + target_desc->string.pointer = ACPI_MEM_CALLOCATE ((acpi_size) length + 1); + if (!target_desc->string.pointer) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER; + ACPI_MEMCPY (target_desc->string.pointer, buffer, length); + } + + /* Set the new target length */ + + target_desc->string.length = length; + return_ACPI_STATUS (AE_OK); +} + + diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c new file mode 100644 index 000000000000..f92efc512890 --- /dev/null +++ b/drivers/acpi/executer/exsystem.c @@ -0,0 +1,378 @@ + +/****************************************************************************** + * + * Module Name: exsystem - Interface to OS services + * + *****************************************************************************/ + +/* + * 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/acinterp.h> +#include <acpi/acevents.h> + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exsystem") + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_wait_semaphore + * + * PARAMETERS: Semaphore - OSD semaphore to wait on + * Timeout - Max time to wait + * + * RETURN: Status + * + * DESCRIPTION: Implements a semaphore wait with a check to see if the + * semaphore is available immediately. If it is not, the + * interpreter is released. + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_wait_semaphore ( + acpi_handle semaphore, + u16 timeout) +{ + acpi_status status; + acpi_status status2; + + + ACPI_FUNCTION_TRACE ("ex_system_wait_semaphore"); + + + status = acpi_os_wait_semaphore (semaphore, 1, 0); + if (ACPI_SUCCESS (status)) { + return_ACPI_STATUS (status); + } + + if (status == AE_TIME) { + /* We must wait, so unlock the interpreter */ + + acpi_ex_exit_interpreter (); + + status = acpi_os_wait_semaphore (semaphore, 1, timeout); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*** Thread awake after blocking, %s\n", + acpi_format_exception (status))); + + /* Reacquire the interpreter */ + + status2 = acpi_ex_enter_interpreter (); + if (ACPI_FAILURE (status2)) { + /* Report fatal error, could not acquire interpreter */ + + return_ACPI_STATUS (status2); + } + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_do_stall + * + * PARAMETERS: how_long - The amount of time to stall, + * in microseconds + * + * RETURN: Status + * + * DESCRIPTION: Suspend running thread for specified amount of time. + * Note: ACPI specification requires that Stall() does not + * relinquish the processor, and delays longer than 100 usec + * should use Sleep() instead. We allow stalls up to 255 usec + * for compatibility with other interpreters and existing BIOSs. + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_do_stall ( + u32 how_long) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_ENTRY (); + + + if (how_long > 255) /* 255 microseconds */ { + /* + * Longer than 255 usec, this is an error + * + * (ACPI specifies 100 usec as max, but this gives some slack in + * order to support existing BIOSs) + */ + ACPI_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n", how_long)); + status = AE_AML_OPERAND_VALUE; + } + else { + acpi_os_stall (how_long); + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_do_suspend + * + * PARAMETERS: how_long - The amount of time to suspend, + * in milliseconds + * + * RETURN: None + * + * DESCRIPTION: Suspend running thread for specified amount of time. + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_do_suspend ( + acpi_integer how_long) +{ + acpi_status status; + + + ACPI_FUNCTION_ENTRY (); + + + /* Since this thread will sleep, we must release the interpreter */ + + acpi_ex_exit_interpreter (); + + acpi_os_sleep (how_long); + + /* And now we must get the interpreter again */ + + status = acpi_ex_enter_interpreter (); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_acquire_mutex + * + * PARAMETERS: *time_desc - The 'time to delay' object descriptor + * *obj_desc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Provides an access point to perform synchronization operations + * within the AML. This function will cause a lock to be generated + * for the Mutex pointed to by obj_desc. + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_acquire_mutex ( + union acpi_operand_object *time_desc, + union acpi_operand_object *obj_desc) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE_PTR ("ex_system_acquire_mutex", obj_desc); + + + if (!obj_desc) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Support for the _GL_ Mutex object -- go get the global lock + */ + if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { + status = acpi_ev_acquire_global_lock ((u16) time_desc->integer.value); + return_ACPI_STATUS (status); + } + + status = acpi_ex_system_wait_semaphore (obj_desc->mutex.semaphore, + (u16) time_desc->integer.value); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_release_mutex + * + * PARAMETERS: *obj_desc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Provides an access point to perform synchronization operations + * within the AML. This operation is a request to release a + * previously acquired Mutex. If the Mutex variable is set then + * it will be decremented. + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_release_mutex ( + union acpi_operand_object *obj_desc) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ex_system_release_mutex"); + + + if (!obj_desc) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * Support for the _GL_ Mutex object -- release the global lock + */ + if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { + status = acpi_ev_release_global_lock (); + return_ACPI_STATUS (status); + } + + status = acpi_os_signal_semaphore (obj_desc->mutex.semaphore, 1); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_signal_event + * + * PARAMETERS: *obj_desc - The object descriptor for this op + * + * RETURN: AE_OK + * + * DESCRIPTION: Provides an access point to perform synchronization operations + * within the AML. + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_signal_event ( + union acpi_operand_object *obj_desc) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ex_system_signal_event"); + + + if (obj_desc) { + status = acpi_os_signal_semaphore (obj_desc->event.semaphore, 1); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_wait_event + * + * PARAMETERS: *time_desc - The 'time to delay' object descriptor + * *obj_desc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Provides an access point to perform synchronization operations + * within the AML. This operation is a request to wait for an + * event. + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_wait_event ( + union acpi_operand_object *time_desc, + union acpi_operand_object *obj_desc) +{ + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ex_system_wait_event"); + + + if (obj_desc) { + status = acpi_ex_system_wait_semaphore (obj_desc->event.semaphore, + (u16) time_desc->integer.value); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_system_reset_event + * + * PARAMETERS: *obj_desc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Reset an event to a known state. + * + ******************************************************************************/ + +acpi_status +acpi_ex_system_reset_event ( + union acpi_operand_object *obj_desc) +{ + acpi_status status = AE_OK; + void *temp_semaphore; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * We are going to simply delete the existing semaphore and + * create a new one! + */ + status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore); + if (ACPI_SUCCESS (status)) { + (void) acpi_os_delete_semaphore (obj_desc->event.semaphore); + obj_desc->event.semaphore = temp_semaphore; + } + + return (status); +} + diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c new file mode 100644 index 000000000000..40c6abb8b49a --- /dev/null +++ b/drivers/acpi/executer/exutils.c @@ -0,0 +1,378 @@ + +/****************************************************************************** + * + * Module Name: exutils - interpreter/scanner 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. + */ + + +/* + * DEFINE_AML_GLOBALS is tested in amlcode.h + * to determine whether certain global names should be "defined" or only + * "declared" in the current compilation. This enhances maintainability + * by enabling a single header file to embody all knowledge of the names + * in question. + * + * Exactly one module of any executable should #define DEFINE_GLOBALS + * before #including the header files which use this convention. The + * names in question will be defined and initialized in that module, + * and declared as extern in all other modules which #include those + * header files. + */ + +#define DEFINE_AML_GLOBALS + +#include <acpi/acpi.h> +#include <acpi/acinterp.h> +#include <acpi/amlcode.h> +#include <acpi/acevents.h> + +#define _COMPONENT ACPI_EXECUTER + ACPI_MODULE_NAME ("exutils") + + +#ifndef ACPI_NO_METHOD_EXECUTION + +/******************************************************************************* + * + * FUNCTION: acpi_ex_enter_interpreter + * + * PARAMETERS: None + * + * DESCRIPTION: Enter the interpreter execution region. Failure to enter + * the interpreter region is a fatal system error + * + ******************************************************************************/ + +acpi_status +acpi_ex_enter_interpreter (void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE ("ex_enter_interpreter"); + + + status = acpi_ut_acquire_mutex (ACPI_MTX_EXECUTE); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not acquire interpreter mutex\n")); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_exit_interpreter + * + * PARAMETERS: None + * + * DESCRIPTION: Exit the interpreter execution region + * + * Cases where the interpreter is unlocked: + * 1) Completion of the execution of a control method + * 2) Method blocked on a Sleep() AML opcode + * 3) Method blocked on an Acquire() AML opcode + * 4) Method blocked on a Wait() AML opcode + * 5) Method blocked to acquire the global lock + * 6) Method blocked to execute a serialized control method that is + * already executing + * 7) About to invoke a user-installed opregion handler + * + ******************************************************************************/ + +void +acpi_ex_exit_interpreter (void) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ex_exit_interpreter"); + + + status = acpi_ut_release_mutex (ACPI_MTX_EXECUTE); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (("Could not release interpreter mutex\n")); + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_truncate_for32bit_table + * + * PARAMETERS: obj_desc - Object to be truncated + * + * RETURN: none + * + * DESCRIPTION: Truncate a number to 32-bits if the currently executing method + * belongs to a 32-bit ACPI table. + * + ******************************************************************************/ + +void +acpi_ex_truncate_for32bit_table ( + union acpi_operand_object *obj_desc) +{ + + ACPI_FUNCTION_ENTRY (); + + + /* + * Object must be a valid number and we must be executing + * a control method + */ + if ((!obj_desc) || + (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_INTEGER)) { + return; + } + + if (acpi_gbl_integer_byte_width == 4) { + /* + * We are running a method that exists in a 32-bit ACPI table. + * Truncate the value to 32 bits by zeroing out the upper 32-bit field + */ + obj_desc->integer.value &= (acpi_integer) ACPI_UINT32_MAX; + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_acquire_global_lock + * + * PARAMETERS: field_flags - Flags with Lock rule: + * always_lock or never_lock + * + * RETURN: TRUE/FALSE indicating whether the lock was actually acquired + * + * DESCRIPTION: Obtain the global lock and keep track of this fact via two + * methods. A global variable keeps the state of the lock, and + * the state is returned to the caller. + * + ******************************************************************************/ + +u8 +acpi_ex_acquire_global_lock ( + u32 field_flags) +{ + u8 locked = FALSE; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ex_acquire_global_lock"); + + + /* Only attempt lock if the always_lock bit is set */ + + if (field_flags & AML_FIELD_LOCK_RULE_MASK) { + /* We should attempt to get the lock, wait forever */ + + status = acpi_ev_acquire_global_lock (ACPI_WAIT_FOREVER); + if (ACPI_SUCCESS (status)) { + locked = TRUE; + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not acquire Global Lock, %s\n", + acpi_format_exception (status))); + } + } + + return_VALUE (locked); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_release_global_lock + * + * PARAMETERS: locked_by_me - Return value from corresponding call to + * acquire_global_lock. + * + * RETURN: Status + * + * DESCRIPTION: Release the global lock if it is locked. + * + ******************************************************************************/ + +void +acpi_ex_release_global_lock ( + u8 locked_by_me) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ex_release_global_lock"); + + + /* Only attempt unlock if the caller locked it */ + + if (locked_by_me) { + /* OK, now release the lock */ + + status = acpi_ev_release_global_lock (); + if (ACPI_FAILURE (status)) { + /* Report the error, but there isn't much else we can do */ + + ACPI_REPORT_ERROR (("Could not release ACPI Global Lock, %s\n", + acpi_format_exception (status))); + } + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_digits_needed + * + * PARAMETERS: Value - Value to be represented + * Base - Base of representation + * + * RETURN: the number of digits needed to represent Value in Base + * + ******************************************************************************/ + +u32 +acpi_ex_digits_needed ( + acpi_integer value, + u32 base) +{ + u32 num_digits; + acpi_integer current_value; + + + ACPI_FUNCTION_TRACE ("ex_digits_needed"); + + + /* acpi_integer is unsigned, so we don't worry about a '-' prefix */ + + if (value == 0) { + return_VALUE (1); + } + + current_value = value; + num_digits = 0; + + /* Count the digits in the requested base */ + + while (current_value) { + (void) acpi_ut_short_divide (current_value, base, ¤t_value, NULL); + num_digits++; + } + + return_VALUE (num_digits); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_eisa_id_to_string + * + * PARAMETERS: numeric_id - EISA ID to be converted + * out_string - Where to put the converted string (8 bytes) + * + * DESCRIPTION: Convert a numeric EISA ID to string representation + * + ******************************************************************************/ + +void +acpi_ex_eisa_id_to_string ( + u32 numeric_id, + char *out_string) +{ + u32 eisa_id; + + + ACPI_FUNCTION_ENTRY (); + + + /* Swap ID to big-endian to get contiguous bits */ + + eisa_id = acpi_ut_dword_byte_swap (numeric_id); + + out_string[0] = (char) ('@' + (((unsigned long) eisa_id >> 26) & 0x1f)); + out_string[1] = (char) ('@' + ((eisa_id >> 21) & 0x1f)); + out_string[2] = (char) ('@' + ((eisa_id >> 16) & 0x1f)); + out_string[3] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 12); + out_string[4] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 8); + out_string[5] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 4); + out_string[6] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 0); + out_string[7] = 0; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ex_unsigned_integer_to_string + * + * PARAMETERS: Value - Value to be converted + * out_string - Where to put the converted string (8 bytes) + * + * RETURN: Convert a number to string representation + * + ******************************************************************************/ + +void +acpi_ex_unsigned_integer_to_string ( + acpi_integer value, + char *out_string) +{ + u32 count; + u32 digits_needed; + u32 remainder; + + + ACPI_FUNCTION_ENTRY (); + + + digits_needed = acpi_ex_digits_needed (value, 10); + out_string[digits_needed] = 0; + + for (count = digits_needed; count > 0; count--) { + (void) acpi_ut_short_divide (value, 10, &value, &remainder); + out_string[count-1] = (char) ('0' + remainder);\ + } +} + +#endif |