590 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: exstore - AML Interpreter object store support5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "acdispat.h"13#include "acinterp.h"14#include "amlcode.h"15#include "acnamesp.h"16 17#define _COMPONENT ACPI_EXECUTER18ACPI_MODULE_NAME("exstore")19 20/* Local prototypes */21static acpi_status22acpi_ex_store_object_to_index(union acpi_operand_object *val_desc,23 union acpi_operand_object *dest_desc,24 struct acpi_walk_state *walk_state);25 26static acpi_status27acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc,28 struct acpi_namespace_node *node,29 struct acpi_walk_state *walk_state);30 31/*******************************************************************************32 *33 * FUNCTION: acpi_ex_store34 *35 * PARAMETERS: *source_desc - Value to be stored36 * *dest_desc - Where to store it. Must be an NS node37 * or union acpi_operand_object of type38 * Reference;39 * walk_state - Current walk state40 *41 * RETURN: Status42 *43 * DESCRIPTION: Store the value described by source_desc into the location44 * described by dest_desc. Called by various interpreter45 * functions to store the result of an operation into46 * the destination operand -- not just simply the actual "Store"47 * ASL operator.48 *49 ******************************************************************************/50 51acpi_status52acpi_ex_store(union acpi_operand_object *source_desc,53 union acpi_operand_object *dest_desc,54 struct acpi_walk_state *walk_state)55{56 acpi_status status = AE_OK;57 union acpi_operand_object *ref_desc = dest_desc;58 59 ACPI_FUNCTION_TRACE_PTR(ex_store, dest_desc);60 61 /* Validate parameters */62 63 if (!source_desc || !dest_desc) {64 ACPI_ERROR((AE_INFO, "Null parameter"));65 return_ACPI_STATUS(AE_AML_NO_OPERAND);66 }67 68 /* dest_desc can be either a namespace node or an ACPI object */69 70 if (ACPI_GET_DESCRIPTOR_TYPE(dest_desc) == ACPI_DESC_TYPE_NAMED) {71 /*72 * Dest is a namespace node,73 * Storing an object into a Named node.74 */75 status = acpi_ex_store_object_to_node(source_desc,76 (struct77 acpi_namespace_node *)78 dest_desc, walk_state,79 ACPI_IMPLICIT_CONVERSION);80 81 return_ACPI_STATUS(status);82 }83 84 /* Destination object must be a Reference or a Constant object */85 86 switch (dest_desc->common.type) {87 case ACPI_TYPE_LOCAL_REFERENCE:88 89 break;90 91 case ACPI_TYPE_INTEGER:92 93 /* Allow stores to Constants -- a Noop as per ACPI spec */94 95 if (dest_desc->common.flags & AOPOBJ_AML_CONSTANT) {96 return_ACPI_STATUS(AE_OK);97 }98 99 ACPI_FALLTHROUGH;100 101 default:102 103 /* Destination is not a Reference object */104 105 ACPI_ERROR((AE_INFO,106 "Target is not a Reference or Constant object - [%s] %p",107 acpi_ut_get_object_type_name(dest_desc),108 dest_desc));109 110 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);111 }112 113 /*114 * Examine the Reference class. These cases are handled:115 *116 * 1) Store to Name (Change the object associated with a name)117 * 2) Store to an indexed area of a Buffer or Package118 * 3) Store to a Method Local or Arg119 * 4) Store to the debug object120 */121 switch (ref_desc->reference.class) {122 case ACPI_REFCLASS_REFOF:123 124 /* Storing an object into a Name "container" */125 126 status = acpi_ex_store_object_to_node(source_desc,127 ref_desc->reference.128 object, walk_state,129 ACPI_IMPLICIT_CONVERSION);130 break;131 132 case ACPI_REFCLASS_INDEX:133 134 /* Storing to an Index (pointer into a packager or buffer) */135 136 status =137 acpi_ex_store_object_to_index(source_desc, ref_desc,138 walk_state);139 break;140 141 case ACPI_REFCLASS_LOCAL:142 case ACPI_REFCLASS_ARG:143 144 /* Store to a method local/arg */145 146 status =147 acpi_ds_store_object_to_local(ref_desc->reference.class,148 ref_desc->reference.value,149 source_desc, walk_state);150 break;151 152 case ACPI_REFCLASS_DEBUG:153 /*154 * Storing to the Debug object causes the value stored to be155 * displayed and otherwise has no effect -- see ACPI Specification156 */157 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,158 "**** Write to Debug Object: Object %p [%s] ****:\n\n",159 source_desc,160 acpi_ut_get_object_type_name(source_desc)));161 162 ACPI_DEBUG_OBJECT(source_desc, 0, 0);163 break;164 165 default:166 167 ACPI_ERROR((AE_INFO, "Unknown Reference Class 0x%2.2X",168 ref_desc->reference.class));169 ACPI_DUMP_ENTRY(ref_desc, ACPI_LV_INFO);170 171 status = AE_AML_INTERNAL;172 break;173 }174 175 return_ACPI_STATUS(status);176}177 178/*******************************************************************************179 *180 * FUNCTION: acpi_ex_store_object_to_index181 *182 * PARAMETERS: *source_desc - Value to be stored183 * *dest_desc - Named object to receive the value184 * walk_state - Current walk state185 *186 * RETURN: Status187 *188 * DESCRIPTION: Store the object to indexed Buffer or Package element189 *190 ******************************************************************************/191 192static acpi_status193acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,194 union acpi_operand_object *index_desc,195 struct acpi_walk_state *walk_state)196{197 acpi_status status = AE_OK;198 union acpi_operand_object *obj_desc;199 union acpi_operand_object *new_desc;200 u8 value = 0;201 u32 i;202 203 ACPI_FUNCTION_TRACE(ex_store_object_to_index);204 205 /*206 * Destination must be a reference pointer, and207 * must point to either a buffer or a package208 */209 switch (index_desc->reference.target_type) {210 case ACPI_TYPE_PACKAGE:211 /*212 * Storing to a package element. Copy the object and replace213 * any existing object with the new object. No implicit214 * conversion is performed.215 *216 * The object at *(index_desc->Reference.Where) is the217 * element within the package that is to be modified.218 * The parent package object is at index_desc->Reference.Object219 */220 obj_desc = *(index_desc->reference.where);221 222 if (source_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE &&223 source_desc->reference.class == ACPI_REFCLASS_TABLE) {224 225 /* This is a DDBHandle, just add a reference to it */226 227 acpi_ut_add_reference(source_desc);228 new_desc = source_desc;229 } else {230 /* Normal object, copy it */231 232 status =233 acpi_ut_copy_iobject_to_iobject(source_desc,234 &new_desc,235 walk_state);236 if (ACPI_FAILURE(status)) {237 return_ACPI_STATUS(status);238 }239 }240 241 if (obj_desc) {242 243 /* Decrement reference count by the ref count of the parent package */244 245 for (i = 0; i < ((union acpi_operand_object *)246 index_desc->reference.object)->common.247 reference_count; i++) {248 acpi_ut_remove_reference(obj_desc);249 }250 }251 252 *(index_desc->reference.where) = new_desc;253 254 /* Increment ref count by the ref count of the parent package-1 */255 256 for (i = 1; i < ((union acpi_operand_object *)257 index_desc->reference.object)->common.258 reference_count; i++) {259 acpi_ut_add_reference(new_desc);260 }261 262 break;263 264 case ACPI_TYPE_BUFFER_FIELD:265 /*266 * Store into a Buffer or String (not actually a real buffer_field)267 * at a location defined by an Index.268 *269 * The first 8-bit element of the source object is written to the270 * 8-bit Buffer location defined by the Index destination object,271 * according to the ACPI 2.0 specification.272 */273 274 /*275 * Make sure the target is a Buffer or String. An error should276 * not happen here, since the reference_object was constructed277 * by the INDEX_OP code.278 */279 obj_desc = index_desc->reference.object;280 if ((obj_desc->common.type != ACPI_TYPE_BUFFER) &&281 (obj_desc->common.type != ACPI_TYPE_STRING)) {282 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);283 }284 285 /*286 * The assignment of the individual elements will be slightly287 * different for each source type.288 */289 switch (source_desc->common.type) {290 case ACPI_TYPE_INTEGER:291 292 /* Use the least-significant byte of the integer */293 294 value = (u8) (source_desc->integer.value);295 break;296 297 case ACPI_TYPE_BUFFER:298 case ACPI_TYPE_STRING:299 300 /* Note: Takes advantage of common string/buffer fields */301 302 value = source_desc->buffer.pointer[0];303 break;304 305 default:306 307 /* All other types are invalid */308 309 ACPI_ERROR((AE_INFO,310 "Source must be type [Integer/Buffer/String], found [%s]",311 acpi_ut_get_object_type_name(source_desc)));312 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);313 }314 315 /* Store the source value into the target buffer byte */316 317 obj_desc->buffer.pointer[index_desc->reference.value] = value;318 break;319 320 default:321 ACPI_ERROR((AE_INFO,322 "Target is not of type [Package/BufferField]"));323 status = AE_AML_TARGET_TYPE;324 break;325 }326 327 return_ACPI_STATUS(status);328}329 330/*******************************************************************************331 *332 * FUNCTION: acpi_ex_store_object_to_node333 *334 * PARAMETERS: source_desc - Value to be stored335 * node - Named object to receive the value336 * walk_state - Current walk state337 * implicit_conversion - Perform implicit conversion (yes/no)338 *339 * RETURN: Status340 *341 * DESCRIPTION: Store the object to the named object.342 *343 * The assignment of an object to a named object is handled here.344 * The value passed in will replace the current value (if any)345 * with the input value.346 *347 * When storing into an object the data is converted to the348 * target object type then stored in the object. This means349 * that the target object type (for an initialized target) will350 * not be changed by a store operation. A copy_object can change351 * the target type, however.352 *353 * The implicit_conversion flag is set to NO/FALSE only when354 * storing to an arg_x -- as per the rules of the ACPI spec.355 *356 * Assumes parameters are already validated.357 *358 ******************************************************************************/359 360acpi_status361acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,362 struct acpi_namespace_node *node,363 struct acpi_walk_state *walk_state,364 u8 implicit_conversion)365{366 acpi_status status = AE_OK;367 union acpi_operand_object *target_desc;368 union acpi_operand_object *new_desc;369 acpi_object_type target_type;370 371 ACPI_FUNCTION_TRACE_PTR(ex_store_object_to_node, source_desc);372 373 /* Get current type of the node, and object attached to Node */374 375 target_type = acpi_ns_get_type(node);376 target_desc = acpi_ns_get_attached_object(node);377 378 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p [%s] to node %p [%s]\n",379 source_desc,380 acpi_ut_get_object_type_name(source_desc), node,381 acpi_ut_get_type_name(target_type)));382 383 /* Only limited target types possible for everything except copy_object */384 385 if (walk_state->opcode != AML_COPY_OBJECT_OP) {386 /*387 * Only copy_object allows all object types to be overwritten. For388 * target_ref(s), there are restrictions on the object types that389 * are allowed.390 *391 * Allowable operations/typing for Store:392 *393 * 1) Simple Store394 * Integer --> Integer (Named/Local/Arg)395 * String --> String (Named/Local/Arg)396 * Buffer --> Buffer (Named/Local/Arg)397 * Package --> Package (Named/Local/Arg)398 *399 * 2) Store with implicit conversion400 * Integer --> String or Buffer (Named)401 * String --> Integer or Buffer (Named)402 * Buffer --> Integer or String (Named)403 */404 switch (target_type) {405 case ACPI_TYPE_PACKAGE:406 /*407 * Here, can only store a package to an existing package.408 * Storing a package to a Local/Arg is OK, and handled409 * elsewhere.410 */411 if (walk_state->opcode == AML_STORE_OP) {412 if (source_desc->common.type !=413 ACPI_TYPE_PACKAGE) {414 ACPI_ERROR((AE_INFO,415 "Cannot assign type [%s] to [Package] "416 "(source must be type Pkg)",417 acpi_ut_get_object_type_name418 (source_desc)));419 420 return_ACPI_STATUS(AE_AML_TARGET_TYPE);421 }422 break;423 }424 425 ACPI_FALLTHROUGH;426 427 case ACPI_TYPE_DEVICE:428 case ACPI_TYPE_EVENT:429 case ACPI_TYPE_MUTEX:430 case ACPI_TYPE_REGION:431 case ACPI_TYPE_POWER:432 case ACPI_TYPE_PROCESSOR:433 case ACPI_TYPE_THERMAL:434 435 ACPI_ERROR((AE_INFO,436 "Target must be [Buffer/Integer/String/Reference]"437 ", found [%s] (%4.4s)",438 acpi_ut_get_type_name(node->type),439 node->name.ascii));440 441 return_ACPI_STATUS(AE_AML_TARGET_TYPE);442 443 default:444 break;445 }446 }447 448 /*449 * Resolve the source object to an actual value450 * (If it is a reference object)451 */452 status = acpi_ex_resolve_object(&source_desc, target_type, walk_state);453 if (ACPI_FAILURE(status)) {454 return_ACPI_STATUS(status);455 }456 457 /* Do the actual store operation */458 459 switch (target_type) {460 /*461 * The simple data types all support implicit source operand462 * conversion before the store.463 */464 case ACPI_TYPE_INTEGER:465 case ACPI_TYPE_STRING:466 case ACPI_TYPE_BUFFER:467 468 if ((walk_state->opcode == AML_COPY_OBJECT_OP) ||469 !implicit_conversion) {470 /*471 * However, copy_object and Stores to arg_x do not perform472 * an implicit conversion, as per the ACPI specification.473 * A direct store is performed instead.474 */475 status =476 acpi_ex_store_direct_to_node(source_desc, node,477 walk_state);478 break;479 }480 481 /* Store with implicit source operand conversion support */482 483 status =484 acpi_ex_store_object_to_object(source_desc, target_desc,485 &new_desc, walk_state);486 if (ACPI_FAILURE(status)) {487 return_ACPI_STATUS(status);488 }489 490 if (new_desc != target_desc) {491 /*492 * Store the new new_desc as the new value of the Name, and set493 * the Name's type to that of the value being stored in it.494 * source_desc reference count is incremented by attach_object.495 *496 * Note: This may change the type of the node if an explicit497 * store has been performed such that the node/object type498 * has been changed.499 */500 status =501 acpi_ns_attach_object(node, new_desc,502 new_desc->common.type);503 504 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,505 "Store type [%s] into [%s] via Convert/Attach\n",506 acpi_ut_get_object_type_name507 (source_desc),508 acpi_ut_get_object_type_name509 (new_desc)));510 }511 break;512 513 case ACPI_TYPE_BUFFER_FIELD:514 case ACPI_TYPE_LOCAL_REGION_FIELD:515 case ACPI_TYPE_LOCAL_BANK_FIELD:516 case ACPI_TYPE_LOCAL_INDEX_FIELD:517 /*518 * For all fields, always write the source data to the target519 * field. Any required implicit source operand conversion is520 * performed in the function below as necessary. Note, field521 * objects must retain their original type permanently.522 */523 status = acpi_ex_write_data_to_field(source_desc, target_desc,524 &walk_state->result_obj);525 break;526 527 default:528 /*529 * copy_object operator: No conversions for all other types.530 * Instead, directly store a copy of the source object.531 *532 * This is the ACPI spec-defined behavior for the copy_object533 * operator. (Note, for this default case, all normal534 * Store/Target operations exited above with an error).535 */536 status =537 acpi_ex_store_direct_to_node(source_desc, node, walk_state);538 break;539 }540 541 return_ACPI_STATUS(status);542}543 544/*******************************************************************************545 *546 * FUNCTION: acpi_ex_store_direct_to_node547 *548 * PARAMETERS: source_desc - Value to be stored549 * node - Named object to receive the value550 * walk_state - Current walk state551 *552 * RETURN: Status553 *554 * DESCRIPTION: "Store" an object directly to a node. This involves a copy555 * and an attach.556 *557 ******************************************************************************/558 559static acpi_status560acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc,561 struct acpi_namespace_node *node,562 struct acpi_walk_state *walk_state)563{564 acpi_status status;565 union acpi_operand_object *new_desc;566 567 ACPI_FUNCTION_TRACE(ex_store_direct_to_node);568 569 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,570 "Storing [%s] (%p) directly into node [%s] (%p)"571 " with no implicit conversion\n",572 acpi_ut_get_object_type_name(source_desc),573 source_desc, acpi_ut_get_type_name(node->type),574 node));575 576 /* Copy the source object to a new object */577 578 status =579 acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc, walk_state);580 if (ACPI_FAILURE(status)) {581 return_ACPI_STATUS(status);582 }583 584 /* Attach the new object to the node */585 586 status = acpi_ns_attach_object(node, new_desc, new_desc->common.type);587 acpi_ut_remove_reference(new_desc);588 return_ACPI_STATUS(status);589}590