/******************************************************************************1*2* Module Name: dsfield - Dispatcher field routines3*4*****************************************************************************/56/*7* Copyright (C) 2000 - 2011, Intel Corp.8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions, and the following disclaimer,15* without modification.16* 2. Redistributions in binary form must reproduce at minimum a disclaimer17* substantially similar to the "NO WARRANTY" disclaimer below18* ("Disclaimer") and any redistribution must be conditioned upon19* including a substantially similar Disclaimer requirement for further20* binary redistribution.21* 3. Neither the names of the above-listed copyright holders nor the names22* of any contributors may be used to endorse or promote products derived23* from this software without specific prior written permission.24*25* Alternatively, this software may be distributed under the terms of the26* GNU General Public License ("GPL") version 2 as published by the Free27* Software Foundation.28*29* NO WARRANTY30* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS31* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT32* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR33* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT34* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL35* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS36* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)37* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,38* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING39* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE40* POSSIBILITY OF SUCH DAMAGES.41*/4243#include <acpi/acpi.h>44#include "accommon.h"45#include "amlcode.h"46#include "acdispat.h"47#include "acinterp.h"48#include "acnamesp.h"49#include "acparser.h"5051#define _COMPONENT ACPI_DISPATCHER52ACPI_MODULE_NAME("dsfield")5354/* Local prototypes */55static acpi_status56acpi_ds_get_field_names(struct acpi_create_field_info *info,57struct acpi_walk_state *walk_state,58union acpi_parse_object *arg);5960/*******************************************************************************61*62* FUNCTION: acpi_ds_create_buffer_field63*64* PARAMETERS: Op - Current parse op (create_xXField)65* walk_state - Current state66*67* RETURN: Status68*69* DESCRIPTION: Execute the create_field operators:70* create_bit_field_op,71* create_byte_field_op,72* create_word_field_op,73* create_dword_field_op,74* create_qword_field_op,75* create_field_op (all of which define a field in a buffer)76*77******************************************************************************/7879acpi_status80acpi_ds_create_buffer_field(union acpi_parse_object *op,81struct acpi_walk_state *walk_state)82{83union acpi_parse_object *arg;84struct acpi_namespace_node *node;85acpi_status status;86union acpi_operand_object *obj_desc;87union acpi_operand_object *second_desc = NULL;88u32 flags;8990ACPI_FUNCTION_TRACE(ds_create_buffer_field);9192/*93* Get the name_string argument (name of the new buffer_field)94*/95if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {9697/* For create_field, name is the 4th argument */9899arg = acpi_ps_get_arg(op, 3);100} else {101/* For all other create_xXXField operators, name is the 3rd argument */102103arg = acpi_ps_get_arg(op, 2);104}105106if (!arg) {107return_ACPI_STATUS(AE_AML_NO_OPERAND);108}109110if (walk_state->deferred_node) {111node = walk_state->deferred_node;112status = AE_OK;113} else {114/* Execute flag should always be set when this function is entered */115116if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {117return_ACPI_STATUS(AE_AML_INTERNAL);118}119120/* Creating new namespace node, should not already exist */121122flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |123ACPI_NS_ERROR_IF_FOUND;124125/*126* Mark node temporary if we are executing a normal control127* method. (Don't mark if this is a module-level code method)128*/129if (walk_state->method_node &&130!(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) {131flags |= ACPI_NS_TEMPORARY;132}133134/* Enter the name_string into the namespace */135136status =137acpi_ns_lookup(walk_state->scope_info,138arg->common.value.string, ACPI_TYPE_ANY,139ACPI_IMODE_LOAD_PASS1, flags, walk_state,140&node);141if (ACPI_FAILURE(status)) {142ACPI_ERROR_NAMESPACE(arg->common.value.string, status);143return_ACPI_STATUS(status);144}145}146147/*148* We could put the returned object (Node) on the object stack for later,149* but for now, we will put it in the "op" object that the parser uses,150* so we can get it again at the end of this scope.151*/152op->common.node = node;153154/*155* If there is no object attached to the node, this node was just created156* and we need to create the field object. Otherwise, this was a lookup157* of an existing node and we don't want to create the field object again.158*/159obj_desc = acpi_ns_get_attached_object(node);160if (obj_desc) {161return_ACPI_STATUS(AE_OK);162}163164/*165* The Field definition is not fully parsed at this time.166* (We must save the address of the AML for the buffer and index operands)167*/168169/* Create the buffer field object */170171obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER_FIELD);172if (!obj_desc) {173status = AE_NO_MEMORY;174goto cleanup;175}176177/*178* Remember location in AML stream of the field unit opcode and operands --179* since the buffer and index operands must be evaluated.180*/181second_desc = obj_desc->common.next_object;182second_desc->extra.aml_start = op->named.data;183second_desc->extra.aml_length = op->named.length;184obj_desc->buffer_field.node = node;185186/* Attach constructed field descriptors to parent node */187188status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_BUFFER_FIELD);189if (ACPI_FAILURE(status)) {190goto cleanup;191}192193cleanup:194195/* Remove local reference to the object */196197acpi_ut_remove_reference(obj_desc);198return_ACPI_STATUS(status);199}200201/*******************************************************************************202*203* FUNCTION: acpi_ds_get_field_names204*205* PARAMETERS: Info - create_field info structure206* ` walk_state - Current method state207* Arg - First parser arg for the field name list208*209* RETURN: Status210*211* DESCRIPTION: Process all named fields in a field declaration. Names are212* entered into the namespace.213*214******************************************************************************/215216static acpi_status217acpi_ds_get_field_names(struct acpi_create_field_info *info,218struct acpi_walk_state *walk_state,219union acpi_parse_object *arg)220{221acpi_status status;222u64 position;223224ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info);225226/* First field starts at bit zero */227228info->field_bit_position = 0;229230/* Process all elements in the field list (of parse nodes) */231232while (arg) {233/*234* Three types of field elements are handled:235* 1) Offset - specifies a bit offset236* 2) access_as - changes the access mode237* 3) Name - Enters a new named field into the namespace238*/239switch (arg->common.aml_opcode) {240case AML_INT_RESERVEDFIELD_OP:241242position = (u64) info->field_bit_position243+ (u64) arg->common.value.size;244245if (position > ACPI_UINT32_MAX) {246ACPI_ERROR((AE_INFO,247"Bit offset within field too large (> 0xFFFFFFFF)"));248return_ACPI_STATUS(AE_SUPPORT);249}250251info->field_bit_position = (u32) position;252break;253254case AML_INT_ACCESSFIELD_OP:255256/*257* Get a new access_type and access_attribute -- to be used for all258* field units that follow, until field end or another access_as259* keyword.260*261* In field_flags, preserve the flag bits other than the262* ACCESS_TYPE bits263*/264info->field_flags = (u8)265((info->266field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) |267((u8) ((u32) arg->common.value.integer >> 8)));268269info->attribute = (u8) (arg->common.value.integer);270break;271272case AML_INT_NAMEDFIELD_OP:273274/* Lookup the name, it should already exist */275276status = acpi_ns_lookup(walk_state->scope_info,277(char *)&arg->named.name,278info->field_type,279ACPI_IMODE_EXECUTE,280ACPI_NS_DONT_OPEN_SCOPE,281walk_state, &info->field_node);282if (ACPI_FAILURE(status)) {283ACPI_ERROR_NAMESPACE((char *)&arg->named.name,284status);285return_ACPI_STATUS(status);286} else {287arg->common.node = info->field_node;288info->field_bit_length = arg->common.value.size;289290/*291* If there is no object attached to the node, this node was292* just created and we need to create the field object.293* Otherwise, this was a lookup of an existing node and we294* don't want to create the field object again.295*/296if (!acpi_ns_get_attached_object297(info->field_node)) {298status = acpi_ex_prep_field_value(info);299if (ACPI_FAILURE(status)) {300return_ACPI_STATUS(status);301}302}303}304305/* Keep track of bit position for the next field */306307position = (u64) info->field_bit_position308+ (u64) arg->common.value.size;309310if (position > ACPI_UINT32_MAX) {311ACPI_ERROR((AE_INFO,312"Field [%4.4s] bit offset too large (> 0xFFFFFFFF)",313ACPI_CAST_PTR(char,314&info->field_node->315name)));316return_ACPI_STATUS(AE_SUPPORT);317}318319info->field_bit_position += info->field_bit_length;320break;321322default:323324ACPI_ERROR((AE_INFO,325"Invalid opcode in field list: 0x%X",326arg->common.aml_opcode));327return_ACPI_STATUS(AE_AML_BAD_OPCODE);328}329330arg = arg->common.next;331}332333return_ACPI_STATUS(AE_OK);334}335336/*******************************************************************************337*338* FUNCTION: acpi_ds_create_field339*340* PARAMETERS: Op - Op containing the Field definition and args341* region_node - Object for the containing Operation Region342* ` walk_state - Current method state343*344* RETURN: Status345*346* DESCRIPTION: Create a new field in the specified operation region347*348******************************************************************************/349350acpi_status351acpi_ds_create_field(union acpi_parse_object *op,352struct acpi_namespace_node *region_node,353struct acpi_walk_state *walk_state)354{355acpi_status status;356union acpi_parse_object *arg;357struct acpi_create_field_info info;358359ACPI_FUNCTION_TRACE_PTR(ds_create_field, op);360361/* First arg is the name of the parent op_region (must already exist) */362363arg = op->common.value.arg;364if (!region_node) {365status =366acpi_ns_lookup(walk_state->scope_info,367arg->common.value.name, ACPI_TYPE_REGION,368ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,369walk_state, ®ion_node);370if (ACPI_FAILURE(status)) {371ACPI_ERROR_NAMESPACE(arg->common.value.name, status);372return_ACPI_STATUS(status);373}374}375376/* Second arg is the field flags */377378arg = arg->common.next;379info.field_flags = (u8) arg->common.value.integer;380info.attribute = 0;381382/* Each remaining arg is a Named Field */383384info.field_type = ACPI_TYPE_LOCAL_REGION_FIELD;385info.region_node = region_node;386387status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);388389return_ACPI_STATUS(status);390}391392/*******************************************************************************393*394* FUNCTION: acpi_ds_init_field_objects395*396* PARAMETERS: Op - Op containing the Field definition and args397* ` walk_state - Current method state398*399* RETURN: Status400*401* DESCRIPTION: For each "Field Unit" name in the argument list that is402* part of the field declaration, enter the name into the403* namespace.404*405******************************************************************************/406407acpi_status408acpi_ds_init_field_objects(union acpi_parse_object *op,409struct acpi_walk_state *walk_state)410{411acpi_status status;412union acpi_parse_object *arg = NULL;413struct acpi_namespace_node *node;414u8 type = 0;415u32 flags;416417ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op);418419/* Execute flag should always be set when this function is entered */420421if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {422if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) {423424/* bank_field Op is deferred, just return OK */425426return_ACPI_STATUS(AE_OK);427}428429return_ACPI_STATUS(AE_AML_INTERNAL);430}431432/*433* Get the field_list argument for this opcode. This is the start of the434* list of field elements.435*/436switch (walk_state->opcode) {437case AML_FIELD_OP:438arg = acpi_ps_get_arg(op, 2);439type = ACPI_TYPE_LOCAL_REGION_FIELD;440break;441442case AML_BANK_FIELD_OP:443arg = acpi_ps_get_arg(op, 4);444type = ACPI_TYPE_LOCAL_BANK_FIELD;445break;446447case AML_INDEX_FIELD_OP:448arg = acpi_ps_get_arg(op, 3);449type = ACPI_TYPE_LOCAL_INDEX_FIELD;450break;451452default:453return_ACPI_STATUS(AE_BAD_PARAMETER);454}455456/* Creating new namespace node(s), should not already exist */457458flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |459ACPI_NS_ERROR_IF_FOUND;460461/*462* Mark node(s) temporary if we are executing a normal control463* method. (Don't mark if this is a module-level code method)464*/465if (walk_state->method_node &&466!(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) {467flags |= ACPI_NS_TEMPORARY;468}469470/*471* Walk the list of entries in the field_list472* Note: field_list can be of zero length. In this case, Arg will be NULL.473*/474while (arg) {475/*476* Ignore OFFSET and ACCESSAS terms here; we are only interested in the477* field names in order to enter them into the namespace.478*/479if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {480status = acpi_ns_lookup(walk_state->scope_info,481(char *)&arg->named.name, type,482ACPI_IMODE_LOAD_PASS1, flags,483walk_state, &node);484if (ACPI_FAILURE(status)) {485ACPI_ERROR_NAMESPACE((char *)&arg->named.name,486status);487if (status != AE_ALREADY_EXISTS) {488return_ACPI_STATUS(status);489}490491/* Name already exists, just ignore this error */492493status = AE_OK;494}495496arg->common.node = node;497}498499/* Get the next field element in the list */500501arg = arg->common.next;502}503504return_ACPI_STATUS(AE_OK);505}506507/*******************************************************************************508*509* FUNCTION: acpi_ds_create_bank_field510*511* PARAMETERS: Op - Op containing the Field definition and args512* region_node - Object for the containing Operation Region513* walk_state - Current method state514*515* RETURN: Status516*517* DESCRIPTION: Create a new bank field in the specified operation region518*519******************************************************************************/520521acpi_status522acpi_ds_create_bank_field(union acpi_parse_object *op,523struct acpi_namespace_node *region_node,524struct acpi_walk_state *walk_state)525{526acpi_status status;527union acpi_parse_object *arg;528struct acpi_create_field_info info;529530ACPI_FUNCTION_TRACE_PTR(ds_create_bank_field, op);531532/* First arg is the name of the parent op_region (must already exist) */533534arg = op->common.value.arg;535if (!region_node) {536status =537acpi_ns_lookup(walk_state->scope_info,538arg->common.value.name, ACPI_TYPE_REGION,539ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,540walk_state, ®ion_node);541if (ACPI_FAILURE(status)) {542ACPI_ERROR_NAMESPACE(arg->common.value.name, status);543return_ACPI_STATUS(status);544}545}546547/* Second arg is the Bank Register (Field) (must already exist) */548549arg = arg->common.next;550status =551acpi_ns_lookup(walk_state->scope_info, arg->common.value.string,552ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,553ACPI_NS_SEARCH_PARENT, walk_state,554&info.register_node);555if (ACPI_FAILURE(status)) {556ACPI_ERROR_NAMESPACE(arg->common.value.string, status);557return_ACPI_STATUS(status);558}559560/*561* Third arg is the bank_value562* This arg is a term_arg, not a constant563* It will be evaluated later, by acpi_ds_eval_bank_field_operands564*/565arg = arg->common.next;566567/* Fourth arg is the field flags */568569arg = arg->common.next;570info.field_flags = (u8) arg->common.value.integer;571572/* Each remaining arg is a Named Field */573574info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD;575info.region_node = region_node;576577/*578* Use Info.data_register_node to store bank_field Op579* It's safe because data_register_node will never be used when create bank field580* We store aml_start and aml_length in the bank_field Op for late evaluation581* Used in acpi_ex_prep_field_value(Info)582*583* TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"?584*/585info.data_register_node = (struct acpi_namespace_node *)op;586587status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);588return_ACPI_STATUS(status);589}590591/*******************************************************************************592*593* FUNCTION: acpi_ds_create_index_field594*595* PARAMETERS: Op - Op containing the Field definition and args596* region_node - Object for the containing Operation Region597* ` walk_state - Current method state598*599* RETURN: Status600*601* DESCRIPTION: Create a new index field in the specified operation region602*603******************************************************************************/604605acpi_status606acpi_ds_create_index_field(union acpi_parse_object *op,607struct acpi_namespace_node *region_node,608struct acpi_walk_state *walk_state)609{610acpi_status status;611union acpi_parse_object *arg;612struct acpi_create_field_info info;613614ACPI_FUNCTION_TRACE_PTR(ds_create_index_field, op);615616/* First arg is the name of the Index register (must already exist) */617618arg = op->common.value.arg;619status =620acpi_ns_lookup(walk_state->scope_info, arg->common.value.string,621ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,622ACPI_NS_SEARCH_PARENT, walk_state,623&info.register_node);624if (ACPI_FAILURE(status)) {625ACPI_ERROR_NAMESPACE(arg->common.value.string, status);626return_ACPI_STATUS(status);627}628629/* Second arg is the data register (must already exist) */630631arg = arg->common.next;632status =633acpi_ns_lookup(walk_state->scope_info, arg->common.value.string,634ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,635ACPI_NS_SEARCH_PARENT, walk_state,636&info.data_register_node);637if (ACPI_FAILURE(status)) {638ACPI_ERROR_NAMESPACE(arg->common.value.string, status);639return_ACPI_STATUS(status);640}641642/* Next arg is the field flags */643644arg = arg->common.next;645info.field_flags = (u8) arg->common.value.integer;646647/* Each remaining arg is a Named Field */648649info.field_type = ACPI_TYPE_LOCAL_INDEX_FIELD;650info.region_node = region_node;651652status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);653654return_ACPI_STATUS(status);655}656657658