540 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: exresolv - AML Interpreter object resolution5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "amlcode.h"13#include "acdispat.h"14#include "acinterp.h"15#include "acnamesp.h"16 17#define _COMPONENT ACPI_EXECUTER18ACPI_MODULE_NAME("exresolv")19 20/* Local prototypes */21static acpi_status22acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,23 struct acpi_walk_state *walk_state);24 25/*******************************************************************************26 *27 * FUNCTION: acpi_ex_resolve_to_value28 *29 * PARAMETERS: **stack_ptr - Points to entry on obj_stack, which can30 * be either an (union acpi_operand_object *)31 * or an acpi_handle.32 * walk_state - Current method state33 *34 * RETURN: Status35 *36 * DESCRIPTION: Convert Reference objects to values37 *38 ******************************************************************************/39 40acpi_status41acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr,42 struct acpi_walk_state *walk_state)43{44 acpi_status status;45 46 ACPI_FUNCTION_TRACE_PTR(ex_resolve_to_value, stack_ptr);47 48 if (!stack_ptr || !*stack_ptr) {49 ACPI_ERROR((AE_INFO, "Internal - null pointer"));50 return_ACPI_STATUS(AE_AML_NO_OPERAND);51 }52 53 /*54 * The entity pointed to by the stack_ptr can be either55 * 1) A valid union acpi_operand_object, or56 * 2) A struct acpi_namespace_node (named_obj)57 */58 if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_OPERAND) {59 status = acpi_ex_resolve_object_to_value(stack_ptr, walk_state);60 if (ACPI_FAILURE(status)) {61 return_ACPI_STATUS(status);62 }63 64 if (!*stack_ptr) {65 ACPI_ERROR((AE_INFO, "Internal - null pointer"));66 return_ACPI_STATUS(AE_AML_NO_OPERAND);67 }68 }69 70 /*71 * Object on the stack may have changed if acpi_ex_resolve_object_to_value()72 * was called (i.e., we can't use an _else_ here.)73 */74 if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_NAMED) {75 status =76 acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR77 (struct acpi_namespace_node,78 stack_ptr), walk_state);79 if (ACPI_FAILURE(status)) {80 return_ACPI_STATUS(status);81 }82 }83 84 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr));85 return_ACPI_STATUS(AE_OK);86}87 88/*******************************************************************************89 *90 * FUNCTION: acpi_ex_resolve_object_to_value91 *92 * PARAMETERS: stack_ptr - Pointer to an internal object93 * walk_state - Current method state94 *95 * RETURN: Status96 *97 * DESCRIPTION: Retrieve the value from an internal object. The Reference type98 * uses the associated AML opcode to determine the value.99 *100 ******************************************************************************/101 102static acpi_status103acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,104 struct acpi_walk_state *walk_state)105{106 acpi_status status = AE_OK;107 union acpi_operand_object *stack_desc;108 union acpi_operand_object *obj_desc = NULL;109 u8 ref_type;110 111 ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);112 113 stack_desc = *stack_ptr;114 115 /* This is an object of type union acpi_operand_object */116 117 switch (stack_desc->common.type) {118 case ACPI_TYPE_LOCAL_REFERENCE:119 120 ref_type = stack_desc->reference.class;121 122 switch (ref_type) {123 case ACPI_REFCLASS_LOCAL:124 case ACPI_REFCLASS_ARG:125 /*126 * Get the local from the method's state info127 * Note: this increments the local's object reference count128 */129 status = acpi_ds_method_data_get_value(ref_type,130 stack_desc->131 reference.value,132 walk_state,133 &obj_desc);134 if (ACPI_FAILURE(status)) {135 return_ACPI_STATUS(status);136 }137 138 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,139 "[Arg/Local %X] ValueObj is %p\n",140 stack_desc->reference.value,141 obj_desc));142 143 /*144 * Now we can delete the original Reference Object and145 * replace it with the resolved value146 */147 acpi_ut_remove_reference(stack_desc);148 *stack_ptr = obj_desc;149 break;150 151 case ACPI_REFCLASS_INDEX:152 153 switch (stack_desc->reference.target_type) {154 case ACPI_TYPE_BUFFER_FIELD:155 156 /* Just return - do not dereference */157 break;158 159 case ACPI_TYPE_PACKAGE:160 161 /* If method call or copy_object - do not dereference */162 163 if ((walk_state->opcode ==164 AML_INT_METHODCALL_OP)165 || (walk_state->opcode ==166 AML_COPY_OBJECT_OP)) {167 break;168 }169 170 /* Otherwise, dereference the package_index to a package element */171 172 obj_desc = *stack_desc->reference.where;173 if (obj_desc) {174 /*175 * Valid object descriptor, copy pointer to return value176 * (i.e., dereference the package index)177 * Delete the ref object, increment the returned object178 */179 acpi_ut_add_reference(obj_desc);180 *stack_ptr = obj_desc;181 } else {182 /*183 * A NULL object descriptor means an uninitialized element of184 * the package, can't dereference it185 */186 ACPI_ERROR((AE_INFO,187 "Attempt to dereference an Index to "188 "NULL package element Idx=%p",189 stack_desc));190 status = AE_AML_UNINITIALIZED_ELEMENT;191 }192 break;193 194 default:195 196 /* Invalid reference object */197 198 ACPI_ERROR((AE_INFO,199 "Unknown TargetType 0x%X in Index/Reference object %p",200 stack_desc->reference.target_type,201 stack_desc));202 status = AE_AML_INTERNAL;203 break;204 }205 break;206 207 case ACPI_REFCLASS_REFOF:208 case ACPI_REFCLASS_DEBUG:209 case ACPI_REFCLASS_TABLE:210 211 /* Just leave the object as-is, do not dereference */212 213 break;214 215 case ACPI_REFCLASS_NAME: /* Reference to a named object */216 217 /* Dereference the name */218 219 if ((stack_desc->reference.node->type ==220 ACPI_TYPE_DEVICE)221 || (stack_desc->reference.node->type ==222 ACPI_TYPE_THERMAL)) {223 224 /* These node types do not have 'real' subobjects */225 226 *stack_ptr = (void *)stack_desc->reference.node;227 } else {228 /* Get the object pointed to by the namespace node */229 230 *stack_ptr =231 (stack_desc->reference.node)->object;232 acpi_ut_add_reference(*stack_ptr);233 }234 235 acpi_ut_remove_reference(stack_desc);236 break;237 238 default:239 240 ACPI_ERROR((AE_INFO,241 "Unknown Reference type 0x%X in %p",242 ref_type, stack_desc));243 status = AE_AML_INTERNAL;244 break;245 }246 break;247 248 case ACPI_TYPE_BUFFER:249 250 status = acpi_ds_get_buffer_arguments(stack_desc);251 break;252 253 case ACPI_TYPE_PACKAGE:254 255 status = acpi_ds_get_package_arguments(stack_desc);256 break;257 258 case ACPI_TYPE_BUFFER_FIELD:259 case ACPI_TYPE_LOCAL_REGION_FIELD:260 case ACPI_TYPE_LOCAL_BANK_FIELD:261 case ACPI_TYPE_LOCAL_INDEX_FIELD:262 263 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,264 "FieldRead SourceDesc=%p Type=%X\n",265 stack_desc, stack_desc->common.type));266 267 status =268 acpi_ex_read_data_from_field(walk_state, stack_desc,269 &obj_desc);270 271 /* Remove a reference to the original operand, then override */272 273 acpi_ut_remove_reference(*stack_ptr);274 *stack_ptr = (void *)obj_desc;275 break;276 277 default:278 279 break;280 }281 282 return_ACPI_STATUS(status);283}284 285/*******************************************************************************286 *287 * FUNCTION: acpi_ex_resolve_multiple288 *289 * PARAMETERS: walk_state - Current state (contains AML opcode)290 * operand - Starting point for resolution291 * return_type - Where the object type is returned292 * return_desc - Where the resolved object is returned293 *294 * RETURN: Status295 *296 * DESCRIPTION: Return the base object and type. Traverse a reference list if297 * necessary to get to the base object.298 *299 ******************************************************************************/300 301acpi_status302acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state,303 union acpi_operand_object *operand,304 acpi_object_type *return_type,305 union acpi_operand_object **return_desc)306{307 union acpi_operand_object *obj_desc = ACPI_CAST_PTR(void, operand);308 struct acpi_namespace_node *node =309 ACPI_CAST_PTR(struct acpi_namespace_node, operand);310 acpi_object_type type;311 acpi_status status;312 313 ACPI_FUNCTION_TRACE(acpi_ex_resolve_multiple);314 315 /* Operand can be either a namespace node or an operand descriptor */316 317 switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {318 case ACPI_DESC_TYPE_OPERAND:319 320 type = obj_desc->common.type;321 break;322 323 case ACPI_DESC_TYPE_NAMED:324 325 type = ((struct acpi_namespace_node *)obj_desc)->type;326 obj_desc = acpi_ns_get_attached_object(node);327 328 /* If we had an Alias node, use the attached object for type info */329 330 if (type == ACPI_TYPE_LOCAL_ALIAS) {331 type = ((struct acpi_namespace_node *)obj_desc)->type;332 obj_desc = acpi_ns_get_attached_object((struct333 acpi_namespace_node334 *)obj_desc);335 }336 337 switch (type) {338 case ACPI_TYPE_DEVICE:339 case ACPI_TYPE_THERMAL:340 341 /* These types have no attached subobject */342 break;343 344 default:345 346 /* All other types require a subobject */347 348 if (!obj_desc) {349 ACPI_ERROR((AE_INFO,350 "[%4.4s] Node is unresolved or uninitialized",351 acpi_ut_get_node_name(node)));352 return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE);353 }354 break;355 }356 break;357 358 default:359 return_ACPI_STATUS(AE_AML_OPERAND_TYPE);360 }361 362 /* If type is anything other than a reference, we are done */363 364 if (type != ACPI_TYPE_LOCAL_REFERENCE) {365 goto exit;366 }367 368 /*369 * For reference objects created via the ref_of, Index, or Load/load_table370 * operators, we need to get to the base object (as per the ACPI371 * specification of the object_type and size_of operators). This means372 * traversing the list of possibly many nested references.373 */374 while (obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) {375 switch (obj_desc->reference.class) {376 case ACPI_REFCLASS_REFOF:377 case ACPI_REFCLASS_NAME:378 379 /* Dereference the reference pointer */380 381 if (obj_desc->reference.class == ACPI_REFCLASS_REFOF) {382 node = obj_desc->reference.object;383 } else { /* AML_INT_NAMEPATH_OP */384 385 node = obj_desc->reference.node;386 }387 388 /* All "References" point to a NS node */389 390 if (ACPI_GET_DESCRIPTOR_TYPE(node) !=391 ACPI_DESC_TYPE_NAMED) {392 ACPI_ERROR((AE_INFO,393 "Not a namespace node %p [%s]",394 node,395 acpi_ut_get_descriptor_name(node)));396 return_ACPI_STATUS(AE_AML_INTERNAL);397 }398 399 /* Get the attached object */400 401 obj_desc = acpi_ns_get_attached_object(node);402 if (!obj_desc) {403 404 /* No object, use the NS node type */405 406 type = acpi_ns_get_type(node);407 goto exit;408 }409 410 /* Check for circular references */411 412 if (obj_desc == operand) {413 return_ACPI_STATUS(AE_AML_CIRCULAR_REFERENCE);414 }415 break;416 417 case ACPI_REFCLASS_INDEX:418 419 /* Get the type of this reference (index into another object) */420 421 type = obj_desc->reference.target_type;422 if (type != ACPI_TYPE_PACKAGE) {423 goto exit;424 }425 426 /*427 * The main object is a package, we want to get the type428 * of the individual package element that is referenced by429 * the index.430 *431 * This could of course in turn be another reference object.432 */433 obj_desc = *(obj_desc->reference.where);434 if (!obj_desc) {435 436 /* NULL package elements are allowed */437 438 type = 0; /* Uninitialized */439 goto exit;440 }441 break;442 443 case ACPI_REFCLASS_TABLE:444 445 type = ACPI_TYPE_DDB_HANDLE;446 goto exit;447 448 case ACPI_REFCLASS_LOCAL:449 case ACPI_REFCLASS_ARG:450 451 if (return_desc) {452 status =453 acpi_ds_method_data_get_value(obj_desc->454 reference.455 class,456 obj_desc->457 reference.458 value,459 walk_state,460 &obj_desc);461 if (ACPI_FAILURE(status)) {462 return_ACPI_STATUS(status);463 }464 acpi_ut_remove_reference(obj_desc);465 } else {466 status =467 acpi_ds_method_data_get_node(obj_desc->468 reference.469 class,470 obj_desc->471 reference.472 value,473 walk_state,474 &node);475 if (ACPI_FAILURE(status)) {476 return_ACPI_STATUS(status);477 }478 479 obj_desc = acpi_ns_get_attached_object(node);480 if (!obj_desc) {481 type = ACPI_TYPE_ANY;482 goto exit;483 }484 }485 break;486 487 case ACPI_REFCLASS_DEBUG:488 489 /* The Debug Object is of type "DebugObject" */490 491 type = ACPI_TYPE_DEBUG_OBJECT;492 goto exit;493 494 default:495 496 ACPI_ERROR((AE_INFO,497 "Unknown Reference Class 0x%2.2X",498 obj_desc->reference.class));499 return_ACPI_STATUS(AE_AML_INTERNAL);500 }501 }502 503 /*504 * Now we are guaranteed to have an object that has not been created505 * via the ref_of or Index operators.506 */507 type = obj_desc->common.type;508 509exit:510 /* Convert internal types to external types */511 512 switch (type) {513 case ACPI_TYPE_LOCAL_REGION_FIELD:514 case ACPI_TYPE_LOCAL_BANK_FIELD:515 case ACPI_TYPE_LOCAL_INDEX_FIELD:516 517 type = ACPI_TYPE_FIELD_UNIT;518 break;519 520 case ACPI_TYPE_LOCAL_SCOPE:521 522 /* Per ACPI Specification, Scope is untyped */523 524 type = ACPI_TYPE_ANY;525 break;526 527 default:528 529 /* No change to Type required */530 531 break;532 }533 534 *return_type = type;535 if (return_desc) {536 *return_desc = obj_desc;537 }538 return_ACPI_STATUS(AE_OK);539}540