exresolv.c (13411B)
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2/****************************************************************************** 3 * 4 * Module Name: exresolv - AML Interpreter object resolution 5 * 6 * Copyright (C) 2000 - 2022, 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_EXECUTER 18ACPI_MODULE_NAME("exresolv") 19 20/* Local prototypes */ 21static acpi_status 22acpi_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_value 28 * 29 * PARAMETERS: **stack_ptr - Points to entry on obj_stack, which can 30 * be either an (union acpi_operand_object *) 31 * or an acpi_handle. 32 * walk_state - Current method state 33 * 34 * RETURN: Status 35 * 36 * DESCRIPTION: Convert Reference objects to values 37 * 38 ******************************************************************************/ 39 40acpi_status 41acpi_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 either 55 * 1) A valid union acpi_operand_object, or 56 * 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_PTR 77 (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_value 91 * 92 * PARAMETERS: stack_ptr - Pointer to an internal object 93 * walk_state - Current method state 94 * 95 * RETURN: Status 96 * 97 * DESCRIPTION: Retrieve the value from an internal object. The Reference type 98 * uses the associated AML opcode to determine the value. 99 * 100 ******************************************************************************/ 101 102static acpi_status 103acpi_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 info 127 * Note: this increments the local's object reference count 128 */ 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 and 145 * replace it with the resolved value 146 */ 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 value 176 * (i.e., dereference the package index) 177 * Delete the ref object, increment the returned object 178 */ 179 acpi_ut_add_reference(obj_desc); 180 *stack_ptr = obj_desc; 181 } else { 182 /* 183 * A NULL object descriptor means an uninitialized element of 184 * the package, can't dereference it 185 */ 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_multiple 288 * 289 * PARAMETERS: walk_state - Current state (contains AML opcode) 290 * operand - Starting point for resolution 291 * return_type - Where the object type is returned 292 * return_desc - Where the resolved object is returned 293 * 294 * RETURN: Status 295 * 296 * DESCRIPTION: Return the base object and type. Traverse a reference list if 297 * necessary to get to the base object. 298 * 299 ******************************************************************************/ 300 301acpi_status 302acpi_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((struct 333 acpi_namespace_node 334 *)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_table 370 * operators, we need to get to the base object (as per the ACPI 371 * specification of the object_type and size_of operators). This means 372 * 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 type 428 * of the individual package element that is referenced by 429 * 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 created 505 * 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}