162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: dsopcode - Dispatcher support for regions and fields 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acparser.h" 1362306a36Sopenharmony_ci#include "amlcode.h" 1462306a36Sopenharmony_ci#include "acdispat.h" 1562306a36Sopenharmony_ci#include "acinterp.h" 1662306a36Sopenharmony_ci#include "acnamesp.h" 1762306a36Sopenharmony_ci#include "acevents.h" 1862306a36Sopenharmony_ci#include "actables.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define _COMPONENT ACPI_DISPATCHER 2162306a36Sopenharmony_ciACPI_MODULE_NAME("dsopcode") 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Local prototypes */ 2462306a36Sopenharmony_cistatic acpi_status 2562306a36Sopenharmony_ciacpi_ds_init_buffer_field(u16 aml_opcode, 2662306a36Sopenharmony_ci union acpi_operand_object *obj_desc, 2762306a36Sopenharmony_ci union acpi_operand_object *buffer_desc, 2862306a36Sopenharmony_ci union acpi_operand_object *offset_desc, 2962306a36Sopenharmony_ci union acpi_operand_object *length_desc, 3062306a36Sopenharmony_ci union acpi_operand_object *result_desc); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/******************************************************************************* 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * FUNCTION: acpi_ds_initialize_region 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * PARAMETERS: obj_handle - Region namespace node 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * RETURN: Status 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * DESCRIPTION: Front end to ev_initialize_region 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci ******************************************************************************/ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciacpi_status acpi_ds_initialize_region(acpi_handle obj_handle) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 4762306a36Sopenharmony_ci acpi_status status; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(obj_handle); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* Namespace is NOT locked */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci status = acpi_ev_initialize_region(obj_desc); 5462306a36Sopenharmony_ci return (status); 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/******************************************************************************* 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * FUNCTION: acpi_ds_init_buffer_field 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * PARAMETERS: aml_opcode - create_xxx_field 6262306a36Sopenharmony_ci * obj_desc - buffer_field object 6362306a36Sopenharmony_ci * buffer_desc - Host Buffer 6462306a36Sopenharmony_ci * offset_desc - Offset into buffer 6562306a36Sopenharmony_ci * length_desc - Length of field (CREATE_FIELD_OP only) 6662306a36Sopenharmony_ci * result_desc - Where to store the result 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * RETURN: Status 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * DESCRIPTION: Perform actual initialization of a buffer field 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci ******************************************************************************/ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic acpi_status 7562306a36Sopenharmony_ciacpi_ds_init_buffer_field(u16 aml_opcode, 7662306a36Sopenharmony_ci union acpi_operand_object *obj_desc, 7762306a36Sopenharmony_ci union acpi_operand_object *buffer_desc, 7862306a36Sopenharmony_ci union acpi_operand_object *offset_desc, 7962306a36Sopenharmony_ci union acpi_operand_object *length_desc, 8062306a36Sopenharmony_ci union acpi_operand_object *result_desc) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci u32 offset; 8362306a36Sopenharmony_ci u32 bit_offset; 8462306a36Sopenharmony_ci u32 bit_count; 8562306a36Sopenharmony_ci u8 field_flags; 8662306a36Sopenharmony_ci acpi_status status; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_init_buffer_field, obj_desc); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* Host object must be a Buffer */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (buffer_desc->common.type != ACPI_TYPE_BUFFER) { 9362306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 9462306a36Sopenharmony_ci "Target of Create Field is not a Buffer object - %s", 9562306a36Sopenharmony_ci acpi_ut_get_object_type_name(buffer_desc))); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci status = AE_AML_OPERAND_TYPE; 9862306a36Sopenharmony_ci goto cleanup; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * The last parameter to all of these opcodes (result_desc) started 10362306a36Sopenharmony_ci * out as a name_string, and should therefore now be a NS node 10462306a36Sopenharmony_ci * after resolution in acpi_ex_resolve_operands(). 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci if (ACPI_GET_DESCRIPTOR_TYPE(result_desc) != ACPI_DESC_TYPE_NAMED) { 10762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 10862306a36Sopenharmony_ci "(%s) destination not a NS Node [%s]", 10962306a36Sopenharmony_ci acpi_ps_get_opcode_name(aml_opcode), 11062306a36Sopenharmony_ci acpi_ut_get_descriptor_name(result_desc))); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci status = AE_AML_OPERAND_TYPE; 11362306a36Sopenharmony_ci goto cleanup; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci offset = (u32) offset_desc->integer.value; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci /* 11962306a36Sopenharmony_ci * Setup the Bit offsets and counts, according to the opcode 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci switch (aml_opcode) { 12262306a36Sopenharmony_ci case AML_CREATE_FIELD_OP: 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Offset is in bits, count is in bits */ 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci field_flags = AML_FIELD_ACCESS_BYTE; 12762306a36Sopenharmony_ci bit_offset = offset; 12862306a36Sopenharmony_ci bit_count = (u32) length_desc->integer.value; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Must have a valid (>0) bit count */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (bit_count == 0) { 13362306a36Sopenharmony_ci ACPI_BIOS_ERROR((AE_INFO, 13462306a36Sopenharmony_ci "Attempt to CreateField of length zero")); 13562306a36Sopenharmony_ci status = AE_AML_OPERAND_VALUE; 13662306a36Sopenharmony_ci goto cleanup; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci case AML_CREATE_BIT_FIELD_OP: 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Offset is in bits, Field is one bit */ 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci bit_offset = offset; 14562306a36Sopenharmony_ci bit_count = 1; 14662306a36Sopenharmony_ci field_flags = AML_FIELD_ACCESS_BYTE; 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci case AML_CREATE_BYTE_FIELD_OP: 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Offset is in bytes, field is one byte */ 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci bit_offset = 8 * offset; 15462306a36Sopenharmony_ci bit_count = 8; 15562306a36Sopenharmony_ci field_flags = AML_FIELD_ACCESS_BYTE; 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci case AML_CREATE_WORD_FIELD_OP: 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Offset is in bytes, field is one word */ 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci bit_offset = 8 * offset; 16362306a36Sopenharmony_ci bit_count = 16; 16462306a36Sopenharmony_ci field_flags = AML_FIELD_ACCESS_WORD; 16562306a36Sopenharmony_ci break; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci case AML_CREATE_DWORD_FIELD_OP: 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci /* Offset is in bytes, field is one dword */ 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci bit_offset = 8 * offset; 17262306a36Sopenharmony_ci bit_count = 32; 17362306a36Sopenharmony_ci field_flags = AML_FIELD_ACCESS_DWORD; 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci case AML_CREATE_QWORD_FIELD_OP: 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Offset is in bytes, field is one qword */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci bit_offset = 8 * offset; 18162306a36Sopenharmony_ci bit_count = 64; 18262306a36Sopenharmony_ci field_flags = AML_FIELD_ACCESS_QWORD; 18362306a36Sopenharmony_ci break; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci default: 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 18862306a36Sopenharmony_ci "Unknown field creation opcode 0x%02X", 18962306a36Sopenharmony_ci aml_opcode)); 19062306a36Sopenharmony_ci status = AE_AML_BAD_OPCODE; 19162306a36Sopenharmony_ci goto cleanup; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* Entire field must fit within the current length of the buffer */ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if ((bit_offset + bit_count) > (8 * (u32)buffer_desc->buffer.length)) { 19762306a36Sopenharmony_ci status = AE_AML_BUFFER_LIMIT; 19862306a36Sopenharmony_ci ACPI_BIOS_EXCEPTION((AE_INFO, status, 19962306a36Sopenharmony_ci "Field [%4.4s] at bit offset/length %u/%u " 20062306a36Sopenharmony_ci "exceeds size of target Buffer (%u bits)", 20162306a36Sopenharmony_ci acpi_ut_get_node_name(result_desc), 20262306a36Sopenharmony_ci bit_offset, bit_count, 20362306a36Sopenharmony_ci 8 * (u32)buffer_desc->buffer.length)); 20462306a36Sopenharmony_ci goto cleanup; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * Initialize areas of the field object that are common to all fields 20962306a36Sopenharmony_ci * For field_flags, use LOCK_RULE = 0 (NO_LOCK), 21062306a36Sopenharmony_ci * UPDATE_RULE = 0 (UPDATE_PRESERVE) 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci status = 21362306a36Sopenharmony_ci acpi_ex_prep_common_field_object(obj_desc, field_flags, 0, 21462306a36Sopenharmony_ci bit_offset, bit_count); 21562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 21662306a36Sopenharmony_ci goto cleanup; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci obj_desc->buffer_field.buffer_obj = buffer_desc; 22062306a36Sopenharmony_ci obj_desc->buffer_field.is_create_field = 22162306a36Sopenharmony_ci aml_opcode == AML_CREATE_FIELD_OP; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Reference count for buffer_desc inherits obj_desc count */ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci buffer_desc->common.reference_count = (u16) 22662306a36Sopenharmony_ci (buffer_desc->common.reference_count + 22762306a36Sopenharmony_ci obj_desc->common.reference_count); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cicleanup: 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci /* Always delete the operands */ 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci acpi_ut_remove_reference(offset_desc); 23462306a36Sopenharmony_ci acpi_ut_remove_reference(buffer_desc); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (aml_opcode == AML_CREATE_FIELD_OP) { 23762306a36Sopenharmony_ci acpi_ut_remove_reference(length_desc); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* On failure, delete the result descriptor */ 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 24362306a36Sopenharmony_ci acpi_ut_remove_reference(result_desc); /* Result descriptor */ 24462306a36Sopenharmony_ci } else { 24562306a36Sopenharmony_ci /* Now the address and length are valid for this buffer_field */ 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci return_ACPI_STATUS(status); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/******************************************************************************* 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * FUNCTION: acpi_ds_eval_buffer_field_operands 25662306a36Sopenharmony_ci * 25762306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk 25862306a36Sopenharmony_ci * op - A valid buffer_field Op object 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * RETURN: Status 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * DESCRIPTION: Get buffer_field Buffer and Index 26362306a36Sopenharmony_ci * Called from acpi_ds_exec_end_op during buffer_field parse tree walk 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci ******************************************************************************/ 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ciacpi_status 26862306a36Sopenharmony_ciacpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, 26962306a36Sopenharmony_ci union acpi_parse_object *op) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci acpi_status status; 27262306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 27362306a36Sopenharmony_ci struct acpi_namespace_node *node; 27462306a36Sopenharmony_ci union acpi_parse_object *next_op; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_eval_buffer_field_operands, op); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * This is where we evaluate the address and length fields of the 28062306a36Sopenharmony_ci * create_xxx_field declaration 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci node = op->common.node; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* next_op points to the op that holds the Buffer */ 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci next_op = op->common.value.arg; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* Evaluate/create the address and length operands */ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci status = acpi_ds_create_operands(walk_state, next_op); 29162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 29262306a36Sopenharmony_ci return_ACPI_STATUS(status); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 29662306a36Sopenharmony_ci if (!obj_desc) { 29762306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_EXIST); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Resolve the operands */ 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci status = 30362306a36Sopenharmony_ci acpi_ex_resolve_operands(op->common.aml_opcode, ACPI_WALK_OPERANDS, 30462306a36Sopenharmony_ci walk_state); 30562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 30662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "(%s) bad operand(s), status 0x%X", 30762306a36Sopenharmony_ci acpi_ps_get_opcode_name(op->common.aml_opcode), 30862306a36Sopenharmony_ci status)); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci return_ACPI_STATUS(status); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* Initialize the Buffer Field */ 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (op->common.aml_opcode == AML_CREATE_FIELD_OP) { 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* NOTE: Slightly different operands for this opcode */ 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci status = 32062306a36Sopenharmony_ci acpi_ds_init_buffer_field(op->common.aml_opcode, obj_desc, 32162306a36Sopenharmony_ci walk_state->operands[0], 32262306a36Sopenharmony_ci walk_state->operands[1], 32362306a36Sopenharmony_ci walk_state->operands[2], 32462306a36Sopenharmony_ci walk_state->operands[3]); 32562306a36Sopenharmony_ci } else { 32662306a36Sopenharmony_ci /* All other, create_xxx_field opcodes */ 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci status = 32962306a36Sopenharmony_ci acpi_ds_init_buffer_field(op->common.aml_opcode, obj_desc, 33062306a36Sopenharmony_ci walk_state->operands[0], 33162306a36Sopenharmony_ci walk_state->operands[1], NULL, 33262306a36Sopenharmony_ci walk_state->operands[2]); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return_ACPI_STATUS(status); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci/******************************************************************************* 33962306a36Sopenharmony_ci * 34062306a36Sopenharmony_ci * FUNCTION: acpi_ds_eval_region_operands 34162306a36Sopenharmony_ci * 34262306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk 34362306a36Sopenharmony_ci * op - A valid region Op object 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * RETURN: Status 34662306a36Sopenharmony_ci * 34762306a36Sopenharmony_ci * DESCRIPTION: Get region address and length 34862306a36Sopenharmony_ci * Called from acpi_ds_exec_end_op during op_region parse tree walk 34962306a36Sopenharmony_ci * 35062306a36Sopenharmony_ci ******************************************************************************/ 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ciacpi_status 35362306a36Sopenharmony_ciacpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, 35462306a36Sopenharmony_ci union acpi_parse_object *op) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci acpi_status status; 35762306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 35862306a36Sopenharmony_ci union acpi_operand_object *operand_desc; 35962306a36Sopenharmony_ci struct acpi_namespace_node *node; 36062306a36Sopenharmony_ci union acpi_parse_object *next_op; 36162306a36Sopenharmony_ci acpi_adr_space_type space_id; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_eval_region_operands, op); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* 36662306a36Sopenharmony_ci * This is where we evaluate the address and length fields of the 36762306a36Sopenharmony_ci * op_region declaration 36862306a36Sopenharmony_ci */ 36962306a36Sopenharmony_ci node = op->common.node; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* next_op points to the op that holds the space_ID */ 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci next_op = op->common.value.arg; 37462306a36Sopenharmony_ci space_id = (acpi_adr_space_type)next_op->common.value.integer; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* next_op points to address op */ 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci next_op = next_op->common.next; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* Evaluate/create the address and length operands */ 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci status = acpi_ds_create_operands(walk_state, next_op); 38362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 38462306a36Sopenharmony_ci return_ACPI_STATUS(status); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* Resolve the length and address operands to numbers */ 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci status = 39062306a36Sopenharmony_ci acpi_ex_resolve_operands(op->common.aml_opcode, ACPI_WALK_OPERANDS, 39162306a36Sopenharmony_ci walk_state); 39262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 39362306a36Sopenharmony_ci return_ACPI_STATUS(status); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 39762306a36Sopenharmony_ci if (!obj_desc) { 39862306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_EXIST); 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* 40262306a36Sopenharmony_ci * Get the length operand and save it 40362306a36Sopenharmony_ci * (at Top of stack) 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_ci operand_desc = walk_state->operands[walk_state->num_operands - 1]; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci obj_desc->region.length = (u32) operand_desc->integer.value; 40862306a36Sopenharmony_ci acpi_ut_remove_reference(operand_desc); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* A zero-length operation region is unusable. Just warn */ 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (!obj_desc->region.length 41362306a36Sopenharmony_ci && (space_id < ACPI_NUM_PREDEFINED_REGIONS)) { 41462306a36Sopenharmony_ci ACPI_WARNING((AE_INFO, 41562306a36Sopenharmony_ci "Operation Region [%4.4s] has zero length (SpaceId %X)", 41662306a36Sopenharmony_ci node->name.ascii, space_id)); 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * Get the address and save it 42162306a36Sopenharmony_ci * (at top of stack - 1) 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_ci operand_desc = walk_state->operands[walk_state->num_operands - 2]; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci obj_desc->region.address = (acpi_physical_address) 42662306a36Sopenharmony_ci operand_desc->integer.value; 42762306a36Sopenharmony_ci acpi_ut_remove_reference(operand_desc); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", 43062306a36Sopenharmony_ci obj_desc, 43162306a36Sopenharmony_ci ACPI_FORMAT_UINT64(obj_desc->region.address), 43262306a36Sopenharmony_ci obj_desc->region.length)); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci status = acpi_ut_add_address_range(obj_desc->region.space_id, 43562306a36Sopenharmony_ci obj_desc->region.address, 43662306a36Sopenharmony_ci obj_desc->region.length, node); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Now the address and length are valid for this opregion */ 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci obj_desc->region.flags |= AOPOBJ_DATA_VALID; 44162306a36Sopenharmony_ci return_ACPI_STATUS(status); 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci/******************************************************************************* 44562306a36Sopenharmony_ci * 44662306a36Sopenharmony_ci * FUNCTION: acpi_ds_eval_table_region_operands 44762306a36Sopenharmony_ci * 44862306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk 44962306a36Sopenharmony_ci * op - A valid region Op object 45062306a36Sopenharmony_ci * 45162306a36Sopenharmony_ci * RETURN: Status 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci * DESCRIPTION: Get region address and length. 45462306a36Sopenharmony_ci * Called from acpi_ds_exec_end_op during data_table_region parse 45562306a36Sopenharmony_ci * tree walk. 45662306a36Sopenharmony_ci * 45762306a36Sopenharmony_ci ******************************************************************************/ 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ciacpi_status 46062306a36Sopenharmony_ciacpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, 46162306a36Sopenharmony_ci union acpi_parse_object *op) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci acpi_status status; 46462306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 46562306a36Sopenharmony_ci union acpi_operand_object **operand; 46662306a36Sopenharmony_ci struct acpi_namespace_node *node; 46762306a36Sopenharmony_ci union acpi_parse_object *next_op; 46862306a36Sopenharmony_ci struct acpi_table_header *table; 46962306a36Sopenharmony_ci u32 table_index; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* 47462306a36Sopenharmony_ci * This is where we evaluate the Signature string, oem_id string, 47562306a36Sopenharmony_ci * and oem_table_id string of the Data Table Region declaration 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci node = op->common.node; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* next_op points to Signature string op */ 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci next_op = op->common.value.arg; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* 48462306a36Sopenharmony_ci * Evaluate/create the Signature string, oem_id string, 48562306a36Sopenharmony_ci * and oem_table_id string operands 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_ci status = acpi_ds_create_operands(walk_state, next_op); 48862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 48962306a36Sopenharmony_ci return_ACPI_STATUS(status); 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci operand = &walk_state->operands[0]; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* 49562306a36Sopenharmony_ci * Resolve the Signature string, oem_id string, 49662306a36Sopenharmony_ci * and oem_table_id string operands 49762306a36Sopenharmony_ci */ 49862306a36Sopenharmony_ci status = 49962306a36Sopenharmony_ci acpi_ex_resolve_operands(op->common.aml_opcode, ACPI_WALK_OPERANDS, 50062306a36Sopenharmony_ci walk_state); 50162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 50262306a36Sopenharmony_ci goto cleanup; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* Find the ACPI table */ 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci status = acpi_tb_find_table(operand[0]->string.pointer, 50862306a36Sopenharmony_ci operand[1]->string.pointer, 50962306a36Sopenharmony_ci operand[2]->string.pointer, &table_index); 51062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 51162306a36Sopenharmony_ci if (status == AE_NOT_FOUND) { 51262306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 51362306a36Sopenharmony_ci "ACPI Table [%4.4s] OEM:(%s, %s) not found in RSDT/XSDT", 51462306a36Sopenharmony_ci operand[0]->string.pointer, 51562306a36Sopenharmony_ci operand[1]->string.pointer, 51662306a36Sopenharmony_ci operand[2]->string.pointer)); 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci goto cleanup; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci status = acpi_get_table_by_index(table_index, &table); 52262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 52362306a36Sopenharmony_ci goto cleanup; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 52762306a36Sopenharmony_ci if (!obj_desc) { 52862306a36Sopenharmony_ci status = AE_NOT_EXIST; 52962306a36Sopenharmony_ci goto cleanup; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci obj_desc->region.address = ACPI_PTR_TO_PHYSADDR(table); 53362306a36Sopenharmony_ci obj_desc->region.length = table->length; 53462306a36Sopenharmony_ci obj_desc->region.pointer = table; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n", 53762306a36Sopenharmony_ci obj_desc, 53862306a36Sopenharmony_ci ACPI_FORMAT_UINT64(obj_desc->region.address), 53962306a36Sopenharmony_ci obj_desc->region.length)); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* Now the address and length are valid for this opregion */ 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci obj_desc->region.flags |= AOPOBJ_DATA_VALID; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cicleanup: 54662306a36Sopenharmony_ci acpi_ut_remove_reference(operand[0]); 54762306a36Sopenharmony_ci acpi_ut_remove_reference(operand[1]); 54862306a36Sopenharmony_ci acpi_ut_remove_reference(operand[2]); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return_ACPI_STATUS(status); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/******************************************************************************* 55462306a36Sopenharmony_ci * 55562306a36Sopenharmony_ci * FUNCTION: acpi_ds_eval_data_object_operands 55662306a36Sopenharmony_ci * 55762306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk 55862306a36Sopenharmony_ci * op - A valid data_object Op object 55962306a36Sopenharmony_ci * obj_desc - data_object 56062306a36Sopenharmony_ci * 56162306a36Sopenharmony_ci * RETURN: Status 56262306a36Sopenharmony_ci * 56362306a36Sopenharmony_ci * DESCRIPTION: Get the operands and complete the following data object types: 56462306a36Sopenharmony_ci * Buffer, Package. 56562306a36Sopenharmony_ci * 56662306a36Sopenharmony_ci ******************************************************************************/ 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ciacpi_status 56962306a36Sopenharmony_ciacpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, 57062306a36Sopenharmony_ci union acpi_parse_object *op, 57162306a36Sopenharmony_ci union acpi_operand_object *obj_desc) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci acpi_status status; 57462306a36Sopenharmony_ci union acpi_operand_object *arg_desc; 57562306a36Sopenharmony_ci u32 length; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ds_eval_data_object_operands); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* The first operand (for all of these data objects) is the length */ 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* 58262306a36Sopenharmony_ci * Set proper index into operand stack for acpi_ds_obj_stack_push 58362306a36Sopenharmony_ci * invoked inside acpi_ds_create_operand. 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_ci walk_state->operand_index = walk_state->num_operands; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* Ignore if child is not valid */ 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (!op->common.value.arg) { 59062306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 59162306a36Sopenharmony_ci "Missing child while evaluating opcode %4.4X, Op %p", 59262306a36Sopenharmony_ci op->common.aml_opcode, op)); 59362306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci status = acpi_ds_create_operand(walk_state, op->common.value.arg, 1); 59762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 59862306a36Sopenharmony_ci return_ACPI_STATUS(status); 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci status = acpi_ex_resolve_operands(walk_state->opcode, 60262306a36Sopenharmony_ci &(walk_state-> 60362306a36Sopenharmony_ci operands[walk_state->num_operands - 60462306a36Sopenharmony_ci 1]), walk_state); 60562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 60662306a36Sopenharmony_ci return_ACPI_STATUS(status); 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* Extract length operand */ 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci arg_desc = walk_state->operands[walk_state->num_operands - 1]; 61262306a36Sopenharmony_ci length = (u32) arg_desc->integer.value; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* Cleanup for length operand */ 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci status = acpi_ds_obj_stack_pop(1, walk_state); 61762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 61862306a36Sopenharmony_ci return_ACPI_STATUS(status); 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci acpi_ut_remove_reference(arg_desc); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * Create the actual data object 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ci switch (op->common.aml_opcode) { 62762306a36Sopenharmony_ci case AML_BUFFER_OP: 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci status = 63062306a36Sopenharmony_ci acpi_ds_build_internal_buffer_obj(walk_state, op, length, 63162306a36Sopenharmony_ci &obj_desc); 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci case AML_PACKAGE_OP: 63562306a36Sopenharmony_ci case AML_VARIABLE_PACKAGE_OP: 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci status = 63862306a36Sopenharmony_ci acpi_ds_build_internal_package_obj(walk_state, op, length, 63962306a36Sopenharmony_ci &obj_desc); 64062306a36Sopenharmony_ci break; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci default: 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_BAD_OPCODE); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 64862306a36Sopenharmony_ci /* 64962306a36Sopenharmony_ci * Return the object in the walk_state, unless the parent is a package - 65062306a36Sopenharmony_ci * in this case, the return object will be stored in the parse tree 65162306a36Sopenharmony_ci * for the package. 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_ci if ((!op->common.parent) || 65462306a36Sopenharmony_ci ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) && 65562306a36Sopenharmony_ci (op->common.parent->common.aml_opcode != 65662306a36Sopenharmony_ci AML_VARIABLE_PACKAGE_OP) 65762306a36Sopenharmony_ci && (op->common.parent->common.aml_opcode != 65862306a36Sopenharmony_ci AML_NAME_OP))) { 65962306a36Sopenharmony_ci walk_state->result_obj = obj_desc; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci return_ACPI_STATUS(status); 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci/******************************************************************************* 66762306a36Sopenharmony_ci * 66862306a36Sopenharmony_ci * FUNCTION: acpi_ds_eval_bank_field_operands 66962306a36Sopenharmony_ci * 67062306a36Sopenharmony_ci * PARAMETERS: walk_state - Current walk 67162306a36Sopenharmony_ci * op - A valid bank_field Op object 67262306a36Sopenharmony_ci * 67362306a36Sopenharmony_ci * RETURN: Status 67462306a36Sopenharmony_ci * 67562306a36Sopenharmony_ci * DESCRIPTION: Get bank_field bank_value 67662306a36Sopenharmony_ci * Called from acpi_ds_exec_end_op during bank_field parse tree walk 67762306a36Sopenharmony_ci * 67862306a36Sopenharmony_ci ******************************************************************************/ 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ciacpi_status 68162306a36Sopenharmony_ciacpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state, 68262306a36Sopenharmony_ci union acpi_parse_object *op) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci acpi_status status; 68562306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 68662306a36Sopenharmony_ci union acpi_operand_object *operand_desc; 68762306a36Sopenharmony_ci struct acpi_namespace_node *node; 68862306a36Sopenharmony_ci union acpi_parse_object *next_op; 68962306a36Sopenharmony_ci union acpi_parse_object *arg; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ds_eval_bank_field_operands, op); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* 69462306a36Sopenharmony_ci * This is where we evaluate the bank_value field of the 69562306a36Sopenharmony_ci * bank_field declaration 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* next_op points to the op that holds the Region */ 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci next_op = op->common.value.arg; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* next_op points to the op that holds the Bank Register */ 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci next_op = next_op->common.next; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* next_op points to the op that holds the Bank Value */ 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci next_op = next_op->common.next; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* 71162306a36Sopenharmony_ci * Set proper index into operand stack for acpi_ds_obj_stack_push 71262306a36Sopenharmony_ci * invoked inside acpi_ds_create_operand. 71362306a36Sopenharmony_ci * 71462306a36Sopenharmony_ci * We use walk_state->Operands[0] to store the evaluated bank_value 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci walk_state->operand_index = 0; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci status = acpi_ds_create_operand(walk_state, next_op, 0); 71962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 72062306a36Sopenharmony_ci return_ACPI_STATUS(status); 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci status = acpi_ex_resolve_to_value(&walk_state->operands[0], walk_state); 72462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 72562306a36Sopenharmony_ci return_ACPI_STATUS(status); 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, 72962306a36Sopenharmony_ci acpi_ps_get_opcode_name(op->common.aml_opcode), 1); 73062306a36Sopenharmony_ci /* 73162306a36Sopenharmony_ci * Get the bank_value operand and save it 73262306a36Sopenharmony_ci * (at Top of stack) 73362306a36Sopenharmony_ci */ 73462306a36Sopenharmony_ci operand_desc = walk_state->operands[0]; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Arg points to the start Bank Field */ 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci arg = acpi_ps_get_arg(op, 4); 73962306a36Sopenharmony_ci while (arg) { 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* Ignore OFFSET and ACCESSAS terms here */ 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { 74462306a36Sopenharmony_ci node = arg->common.node; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci obj_desc = acpi_ns_get_attached_object(node); 74762306a36Sopenharmony_ci if (!obj_desc) { 74862306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_EXIST); 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci obj_desc->bank_field.value = 75262306a36Sopenharmony_ci (u32) operand_desc->integer.value; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* Move to next field in the list */ 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci arg = arg->common.next; 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci acpi_ut_remove_reference(operand_desc); 76162306a36Sopenharmony_ci return_ACPI_STATUS(status); 76262306a36Sopenharmony_ci} 763