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 - 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_EXECUTER |
18 | ACPI_MODULE_NAME("exresolv" ) |
19 | |
20 | /* Local prototypes */ |
21 | static acpi_status |
22 | acpi_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 | |
40 | acpi_status |
41 | acpi_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 | |
102 | static acpi_status |
103 | acpi_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(type: ref_type, |
130 | index: stack_desc-> |
131 | reference.value, |
132 | walk_state, |
133 | dest_desc: &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(object: 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(object: 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(object: *stack_ptr); |
233 | } |
234 | |
235 | acpi_ut_remove_reference(object: 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(obj_desc: stack_desc); |
251 | break; |
252 | |
253 | case ACPI_TYPE_PACKAGE: |
254 | |
255 | status = acpi_ds_get_package_arguments(obj_desc: 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, obj_desc: stack_desc, |
269 | ret_buffer_desc: &obj_desc); |
270 | |
271 | /* Remove a reference to the original operand, then override */ |
272 | |
273 | acpi_ut_remove_reference(object: *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 | |
301 | acpi_status |
302 | acpi_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(node: (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(type: obj_desc-> |
454 | reference. |
455 | class, |
456 | index: obj_desc-> |
457 | reference. |
458 | value, |
459 | walk_state, |
460 | dest_desc: &obj_desc); |
461 | if (ACPI_FAILURE(status)) { |
462 | return_ACPI_STATUS(status); |
463 | } |
464 | acpi_ut_remove_reference(object: obj_desc); |
465 | } else { |
466 | status = |
467 | acpi_ds_method_data_get_node(type: obj_desc-> |
468 | reference. |
469 | class, |
470 | index: obj_desc-> |
471 | reference. |
472 | value, |
473 | walk_state, |
474 | node: &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 | |
509 | exit: |
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 | |