682 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/*******************************************************************************3 *4 * Module Name: dsmthdat - control method arguments and local variables5 *6 ******************************************************************************/7 8#include <acpi/acpi.h>9#include "accommon.h"10#include "acdispat.h"11#include "acnamesp.h"12#include "acinterp.h"13 14#define _COMPONENT ACPI_DISPATCHER15ACPI_MODULE_NAME("dsmthdat")16 17/* Local prototypes */18static void19acpi_ds_method_data_delete_value(u8 type,20 u32 index, struct acpi_walk_state *walk_state);21 22static acpi_status23acpi_ds_method_data_set_value(u8 type,24 u32 index,25 union acpi_operand_object *object,26 struct acpi_walk_state *walk_state);27 28#ifdef ACPI_OBSOLETE_FUNCTIONS29acpi_object_type30acpi_ds_method_data_get_type(u16 opcode,31 u32 index, struct acpi_walk_state *walk_state);32#endif33 34/*******************************************************************************35 *36 * FUNCTION: acpi_ds_method_data_init37 *38 * PARAMETERS: walk_state - Current walk state object39 *40 * RETURN: Status41 *42 * DESCRIPTION: Initialize the data structures that hold the method's arguments43 * and locals. The data struct is an array of namespace nodes for44 * each - this allows ref_of and de_ref_of to work properly for these45 * special data types.46 *47 * NOTES: walk_state fields are initialized to zero by the48 * ACPI_ALLOCATE_ZEROED().49 *50 * A pseudo-Namespace Node is assigned to each argument and local51 * so that ref_of() can return a pointer to the Node.52 *53 ******************************************************************************/54 55void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)56{57 u32 i;58 59 ACPI_FUNCTION_TRACE(ds_method_data_init);60 61 /* Init the method arguments */62 63 for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {64 ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name,65 NAMEOF_ARG_NTE);66 67 walk_state->arguments[i].name.integer |= (i << 24);68 walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;69 walk_state->arguments[i].type = ACPI_TYPE_ANY;70 walk_state->arguments[i].flags = ANOBJ_METHOD_ARG;71 }72 73 /* Init the method locals */74 75 for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {76 ACPI_MOVE_32_TO_32(&walk_state->local_variables[i].name,77 NAMEOF_LOCAL_NTE);78 79 walk_state->local_variables[i].name.integer |= (i << 24);80 walk_state->local_variables[i].descriptor_type =81 ACPI_DESC_TYPE_NAMED;82 walk_state->local_variables[i].type = ACPI_TYPE_ANY;83 walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL;84 }85 86 return_VOID;87}88 89/*******************************************************************************90 *91 * FUNCTION: acpi_ds_method_data_delete_all92 *93 * PARAMETERS: walk_state - Current walk state object94 *95 * RETURN: None96 *97 * DESCRIPTION: Delete method locals and arguments. Arguments are only98 * deleted if this method was called from another method.99 *100 ******************************************************************************/101 102void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)103{104 u32 index;105 106 ACPI_FUNCTION_TRACE(ds_method_data_delete_all);107 108 /* Detach the locals */109 110 for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) {111 if (walk_state->local_variables[index].object) {112 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%u=%p\n",113 index,114 walk_state->local_variables[index].115 object));116 117 /* Detach object (if present) and remove a reference */118 119 acpi_ns_detach_object(&walk_state->120 local_variables[index]);121 }122 }123 124 /* Detach the arguments */125 126 for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) {127 if (walk_state->arguments[index].object) {128 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%u=%p\n",129 index,130 walk_state->arguments[index].object));131 132 /* Detach object (if present) and remove a reference */133 134 acpi_ns_detach_object(&walk_state->arguments[index]);135 }136 }137 138 return_VOID;139}140 141/*******************************************************************************142 *143 * FUNCTION: acpi_ds_method_data_init_args144 *145 * PARAMETERS: *params - Pointer to a parameter list for the method146 * max_param_count - The arg count for this method147 * walk_state - Current walk state object148 *149 * RETURN: Status150 *151 * DESCRIPTION: Initialize arguments for a method. The parameter list is a list152 * of ACPI operand objects, either null terminated or whose length153 * is defined by max_param_count.154 *155 ******************************************************************************/156 157acpi_status158acpi_ds_method_data_init_args(union acpi_operand_object **params,159 u32 max_param_count,160 struct acpi_walk_state *walk_state)161{162 acpi_status status;163 u32 index = 0;164 165 ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params);166 167 if (!params) {168 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,169 "No parameter list passed to method\n"));170 return_ACPI_STATUS(AE_OK);171 }172 173 /* Copy passed parameters into the new method stack frame */174 175 while ((index < ACPI_METHOD_NUM_ARGS) &&176 (index < max_param_count) && params[index]) {177 /*178 * A valid parameter.179 * Store the argument in the method/walk descriptor.180 * Do not copy the arg in order to implement call by reference181 */182 status =183 acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index,184 params[index], walk_state);185 if (ACPI_FAILURE(status)) {186 return_ACPI_STATUS(status);187 }188 189 index++;190 }191 192 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%u args passed to method\n", index));193 return_ACPI_STATUS(AE_OK);194}195 196/*******************************************************************************197 *198 * FUNCTION: acpi_ds_method_data_get_node199 *200 * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or201 * ACPI_REFCLASS_ARG202 * index - Which Local or Arg whose type to get203 * walk_state - Current walk state object204 * node - Where the node is returned.205 *206 * RETURN: Status and node207 *208 * DESCRIPTION: Get the Node associated with a local or arg.209 *210 ******************************************************************************/211 212acpi_status213acpi_ds_method_data_get_node(u8 type,214 u32 index,215 struct acpi_walk_state *walk_state,216 struct acpi_namespace_node **node)217{218 ACPI_FUNCTION_TRACE(ds_method_data_get_node);219 220 /*221 * Method Locals and Arguments are supported222 */223 switch (type) {224 case ACPI_REFCLASS_LOCAL:225 226 if (index > ACPI_METHOD_MAX_LOCAL) {227 ACPI_ERROR((AE_INFO,228 "Local index %u is invalid (max %u)",229 index, ACPI_METHOD_MAX_LOCAL));230 return_ACPI_STATUS(AE_AML_INVALID_INDEX);231 }232 233 /* Return a pointer to the pseudo-node */234 235 *node = &walk_state->local_variables[index];236 break;237 238 case ACPI_REFCLASS_ARG:239 240 if (index > ACPI_METHOD_MAX_ARG) {241 ACPI_ERROR((AE_INFO,242 "Arg index %u is invalid (max %u)",243 index, ACPI_METHOD_MAX_ARG));244 return_ACPI_STATUS(AE_AML_INVALID_INDEX);245 }246 247 /* Return a pointer to the pseudo-node */248 249 *node = &walk_state->arguments[index];250 break;251 252 default:253 254 ACPI_ERROR((AE_INFO, "Type %u is invalid", type));255 return_ACPI_STATUS(AE_TYPE);256 }257 258 return_ACPI_STATUS(AE_OK);259}260 261/*******************************************************************************262 *263 * FUNCTION: acpi_ds_method_data_set_value264 *265 * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or266 * ACPI_REFCLASS_ARG267 * index - Which Local or Arg to get268 * object - Object to be inserted into the stack entry269 * walk_state - Current walk state object270 *271 * RETURN: Status272 *273 * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index.274 * Note: There is no "implicit conversion" for locals.275 *276 ******************************************************************************/277 278static acpi_status279acpi_ds_method_data_set_value(u8 type,280 u32 index,281 union acpi_operand_object *object,282 struct acpi_walk_state *walk_state)283{284 acpi_status status;285 struct acpi_namespace_node *node;286 287 ACPI_FUNCTION_TRACE(ds_method_data_set_value);288 289 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,290 "NewObj %p Type %2.2X, Refs=%u [%s]\n", object,291 type, object->common.reference_count,292 acpi_ut_get_type_name(object->common.type)));293 294 /* Get the namespace node for the arg/local */295 296 status = acpi_ds_method_data_get_node(type, index, walk_state, &node);297 if (ACPI_FAILURE(status)) {298 return_ACPI_STATUS(status);299 }300 301 /*302 * Increment ref count so object can't be deleted while installed.303 * NOTE: We do not copy the object in order to preserve the call by304 * reference semantics of ACPI Control Method invocation.305 * (See ACPI Specification 2.0C)306 */307 acpi_ut_add_reference(object);308 309 /* Install the object */310 311 node->object = object;312 return_ACPI_STATUS(status);313}314 315/*******************************************************************************316 *317 * FUNCTION: acpi_ds_method_data_get_value318 *319 * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or320 * ACPI_REFCLASS_ARG321 * index - Which localVar or argument to get322 * walk_state - Current walk state object323 * dest_desc - Where Arg or Local value is returned324 *325 * RETURN: Status326 *327 * DESCRIPTION: Retrieve value of selected Arg or Local for this method328 * Used only in acpi_ex_resolve_to_value().329 *330 ******************************************************************************/331 332acpi_status333acpi_ds_method_data_get_value(u8 type,334 u32 index,335 struct acpi_walk_state *walk_state,336 union acpi_operand_object **dest_desc)337{338 acpi_status status;339 struct acpi_namespace_node *node;340 union acpi_operand_object *object;341 342 ACPI_FUNCTION_TRACE(ds_method_data_get_value);343 344 /* Validate the object descriptor */345 346 if (!dest_desc) {347 ACPI_ERROR((AE_INFO, "Null object descriptor pointer"));348 return_ACPI_STATUS(AE_BAD_PARAMETER);349 }350 351 /* Get the namespace node for the arg/local */352 353 status = acpi_ds_method_data_get_node(type, index, walk_state, &node);354 if (ACPI_FAILURE(status)) {355 return_ACPI_STATUS(status);356 }357 358 /* Get the object from the node */359 360 object = node->object;361 362 /* Examine the returned object, it must be valid. */363 364 if (!object) {365 /*366 * Index points to uninitialized object.367 * This means that either 1) The expected argument was368 * not passed to the method, or 2) A local variable369 * was referenced by the method (via the ASL)370 * before it was initialized. Either case is an error.371 */372 373 /* If slack enabled, init the local_x/arg_x to an Integer of value zero */374 375 if (acpi_gbl_enable_interpreter_slack) {376 object = acpi_ut_create_integer_object((u64) 0);377 if (!object) {378 return_ACPI_STATUS(AE_NO_MEMORY);379 }380 381 node->object = object;382 }383 384 /* Otherwise, return the error */385 386 else387 switch (type) {388 case ACPI_REFCLASS_ARG:389 390 ACPI_ERROR((AE_INFO,391 "Uninitialized Arg[%u] at node %p",392 index, node));393 394 return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);395 396 case ACPI_REFCLASS_LOCAL:397 /*398 * No error message for this case, will be trapped again later to399 * detect and ignore cases of Store(local_x,local_x)400 */401 return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);402 403 default:404 405 ACPI_ERROR((AE_INFO,406 "Not a Arg/Local opcode: 0x%X",407 type));408 return_ACPI_STATUS(AE_AML_INTERNAL);409 }410 }411 412 /*413 * The Index points to an initialized and valid object.414 * Return an additional reference to the object415 */416 *dest_desc = object;417 acpi_ut_add_reference(object);418 419 return_ACPI_STATUS(AE_OK);420}421 422/*******************************************************************************423 *424 * FUNCTION: acpi_ds_method_data_delete_value425 *426 * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or427 * ACPI_REFCLASS_ARG428 * index - Which localVar or argument to delete429 * walk_state - Current walk state object430 *431 * RETURN: None432 *433 * DESCRIPTION: Delete the entry at Opcode:Index. Inserts434 * a null into the stack slot after the object is deleted.435 *436 ******************************************************************************/437 438static void439acpi_ds_method_data_delete_value(u8 type,440 u32 index, struct acpi_walk_state *walk_state)441{442 acpi_status status;443 struct acpi_namespace_node *node;444 union acpi_operand_object *object;445 446 ACPI_FUNCTION_TRACE(ds_method_data_delete_value);447 448 /* Get the namespace node for the arg/local */449 450 status = acpi_ds_method_data_get_node(type, index, walk_state, &node);451 if (ACPI_FAILURE(status)) {452 return_VOID;453 }454 455 /* Get the associated object */456 457 object = acpi_ns_get_attached_object(node);458 459 /*460 * Undefine the Arg or Local by setting its descriptor461 * pointer to NULL. Locals/Args can contain both462 * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs463 */464 node->object = NULL;465 466 if ((object) &&467 (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_OPERAND)) {468 /*469 * There is a valid object.470 * Decrement the reference count by one to balance the471 * increment when the object was stored.472 */473 acpi_ut_remove_reference(object);474 }475 476 return_VOID;477}478 479/*******************************************************************************480 *481 * FUNCTION: acpi_ds_store_object_to_local482 *483 * PARAMETERS: type - Either ACPI_REFCLASS_LOCAL or484 * ACPI_REFCLASS_ARG485 * index - Which Local or Arg to set486 * obj_desc - Value to be stored487 * walk_state - Current walk state488 *489 * RETURN: Status490 *491 * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed492 * as the new value for the Arg or Local and the reference count493 * for obj_desc is incremented.494 *495 ******************************************************************************/496 497acpi_status498acpi_ds_store_object_to_local(u8 type,499 u32 index,500 union acpi_operand_object *obj_desc,501 struct acpi_walk_state *walk_state)502{503 acpi_status status;504 struct acpi_namespace_node *node;505 union acpi_operand_object *current_obj_desc;506 union acpi_operand_object *new_obj_desc;507 508 ACPI_FUNCTION_TRACE(ds_store_object_to_local);509 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n",510 type, index, obj_desc));511 512 /* Parameter validation */513 514 if (!obj_desc) {515 return_ACPI_STATUS(AE_BAD_PARAMETER);516 }517 518 /* Get the namespace node for the arg/local */519 520 status = acpi_ds_method_data_get_node(type, index, walk_state, &node);521 if (ACPI_FAILURE(status)) {522 return_ACPI_STATUS(status);523 }524 525 current_obj_desc = acpi_ns_get_attached_object(node);526 if (current_obj_desc == obj_desc) {527 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n",528 obj_desc));529 return_ACPI_STATUS(status);530 }531 532 /*533 * If the reference count on the object is more than one, we must534 * take a copy of the object before we store. A reference count535 * of exactly 1 means that the object was just created during the536 * evaluation of an expression, and we can safely use it since it537 * is not used anywhere else.538 */539 new_obj_desc = obj_desc;540 if (obj_desc->common.reference_count > 1) {541 status =542 acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc,543 walk_state);544 if (ACPI_FAILURE(status)) {545 return_ACPI_STATUS(status);546 }547 }548 549 /*550 * If there is an object already in this slot, we either551 * have to delete it, or if this is an argument and there552 * is an object reference stored there, we have to do553 * an indirect store!554 */555 if (current_obj_desc) {556 /*557 * Check for an indirect store if an argument558 * contains an object reference (stored as an Node).559 * We don't allow this automatic dereferencing for560 * locals, since a store to a local should overwrite561 * anything there, including an object reference.562 *563 * If both Arg0 and Local0 contain ref_of (Local4):564 *565 * Store (1, Arg0) - Causes indirect store to local4566 * Store (1, Local0) - Stores 1 in local0, overwriting567 * the reference to local4568 * Store (1, de_refof (Local0)) - Causes indirect store to local4569 *570 * Weird, but true.571 */572 if (type == ACPI_REFCLASS_ARG) {573 /*574 * If we have a valid reference object that came from ref_of(),575 * do the indirect store576 */577 if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) ==578 ACPI_DESC_TYPE_OPERAND) &&579 (current_obj_desc->common.type ==580 ACPI_TYPE_LOCAL_REFERENCE) &&581 (current_obj_desc->reference.class ==582 ACPI_REFCLASS_REFOF)) {583 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,584 "Arg (%p) is an ObjRef(Node), storing in node %p\n",585 new_obj_desc,586 current_obj_desc));587 588 /*589 * Store this object to the Node (perform the indirect store)590 * NOTE: No implicit conversion is performed, as per the ACPI591 * specification rules on storing to Locals/Args.592 */593 status =594 acpi_ex_store_object_to_node(new_obj_desc,595 current_obj_desc->596 reference.597 object,598 walk_state,599 ACPI_NO_IMPLICIT_CONVERSION);600 601 /* Remove local reference if we copied the object above */602 603 if (new_obj_desc != obj_desc) {604 acpi_ut_remove_reference(new_obj_desc);605 }606 607 return_ACPI_STATUS(status);608 }609 }610 611 /* Delete the existing object before storing the new one */612 613 acpi_ds_method_data_delete_value(type, index, walk_state);614 }615 616 /*617 * Install the Obj descriptor (*new_obj_desc) into618 * the descriptor for the Arg or Local.619 * (increments the object reference count by one)620 */621 status =622 acpi_ds_method_data_set_value(type, index, new_obj_desc,623 walk_state);624 625 /* Remove local reference if we copied the object above */626 627 if (new_obj_desc != obj_desc) {628 acpi_ut_remove_reference(new_obj_desc);629 }630 631 return_ACPI_STATUS(status);632}633 634#ifdef ACPI_OBSOLETE_FUNCTIONS635/*******************************************************************************636 *637 * FUNCTION: acpi_ds_method_data_get_type638 *639 * PARAMETERS: opcode - Either AML_FIRST LOCAL_OP or640 * AML_FIRST_ARG_OP641 * index - Which Local or Arg whose type to get642 * walk_state - Current walk state object643 *644 * RETURN: Data type of current value of the selected Arg or Local645 *646 * DESCRIPTION: Get the type of the object stored in the Local or Arg647 *648 ******************************************************************************/649 650acpi_object_type651acpi_ds_method_data_get_type(u16 opcode,652 u32 index, struct acpi_walk_state *walk_state)653{654 acpi_status status;655 struct acpi_namespace_node *node;656 union acpi_operand_object *object;657 658 ACPI_FUNCTION_TRACE(ds_method_data_get_type);659 660 /* Get the namespace node for the arg/local */661 662 status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);663 if (ACPI_FAILURE(status)) {664 return_VALUE((ACPI_TYPE_NOT_FOUND));665 }666 667 /* Get the object */668 669 object = acpi_ns_get_attached_object(node);670 if (!object) {671 672 /* Uninitialized local/arg, return TYPE_ANY */673 674 return_VALUE(ACPI_TYPE_ANY);675 }676 677 /* Get the object type */678 679 return_VALUE(object->type);680}681#endif682