Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6595 | serge | 1 | /****************************************************************************** |
2 | * |
||
3 | * Module Name: exresolv - AML Interpreter object resolution |
||
4 | * |
||
5 | *****************************************************************************/ |
||
6 | |||
7 | /* |
||
8 | * Copyright (C) 2000 - 2015, Intel Corp. |
||
9 | * All rights reserved. |
||
10 | * |
||
11 | * Redistribution and use in source and binary forms, with or without |
||
12 | * modification, are permitted provided that the following conditions |
||
13 | * are met: |
||
14 | * 1. Redistributions of source code must retain the above copyright |
||
15 | * notice, this list of conditions, and the following disclaimer, |
||
16 | * without modification. |
||
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
||
18 | * substantially similar to the "NO WARRANTY" disclaimer below |
||
19 | * ("Disclaimer") and any redistribution must be conditioned upon |
||
20 | * including a substantially similar Disclaimer requirement for further |
||
21 | * binary redistribution. |
||
22 | * 3. Neither the names of the above-listed copyright holders nor the names |
||
23 | * of any contributors may be used to endorse or promote products derived |
||
24 | * from this software without specific prior written permission. |
||
25 | * |
||
26 | * Alternatively, this software may be distributed under the terms of the |
||
27 | * GNU General Public License ("GPL") version 2 as published by the Free |
||
28 | * Software Foundation. |
||
29 | * |
||
30 | * NO WARRANTY |
||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
||
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
41 | * POSSIBILITY OF SUCH DAMAGES. |
||
42 | */ |
||
43 | |||
44 | #include |
||
45 | #include "accommon.h" |
||
46 | #include "amlcode.h" |
||
47 | #include "acdispat.h" |
||
48 | #include "acinterp.h" |
||
49 | #include "acnamesp.h" |
||
50 | |||
51 | #define _COMPONENT ACPI_EXECUTER |
||
52 | ACPI_MODULE_NAME("exresolv") |
||
53 | |||
54 | /* Local prototypes */ |
||
55 | static acpi_status |
||
56 | acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, |
||
57 | struct acpi_walk_state *walk_state); |
||
58 | |||
59 | /******************************************************************************* |
||
60 | * |
||
61 | * FUNCTION: acpi_ex_resolve_to_value |
||
62 | * |
||
63 | * PARAMETERS: **stack_ptr - Points to entry on obj_stack, which can |
||
64 | * be either an (union acpi_operand_object *) |
||
65 | * or an acpi_handle. |
||
66 | * walk_state - Current method state |
||
67 | * |
||
68 | * RETURN: Status |
||
69 | * |
||
70 | * DESCRIPTION: Convert Reference objects to values |
||
71 | * |
||
72 | ******************************************************************************/ |
||
73 | |||
74 | acpi_status |
||
75 | acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr, |
||
76 | struct acpi_walk_state *walk_state) |
||
77 | { |
||
78 | acpi_status status; |
||
79 | |||
80 | ACPI_FUNCTION_TRACE_PTR(ex_resolve_to_value, stack_ptr); |
||
81 | |||
82 | if (!stack_ptr || !*stack_ptr) { |
||
83 | ACPI_ERROR((AE_INFO, "Internal - null pointer")); |
||
84 | return_ACPI_STATUS(AE_AML_NO_OPERAND); |
||
85 | } |
||
86 | |||
87 | /* |
||
88 | * The entity pointed to by the stack_ptr can be either |
||
89 | * 1) A valid union acpi_operand_object, or |
||
90 | * 2) A struct acpi_namespace_node (named_obj) |
||
91 | */ |
||
92 | if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_OPERAND) { |
||
93 | status = acpi_ex_resolve_object_to_value(stack_ptr, walk_state); |
||
94 | if (ACPI_FAILURE(status)) { |
||
95 | return_ACPI_STATUS(status); |
||
96 | } |
||
97 | |||
98 | if (!*stack_ptr) { |
||
99 | ACPI_ERROR((AE_INFO, "Internal - null pointer")); |
||
100 | return_ACPI_STATUS(AE_AML_NO_OPERAND); |
||
101 | } |
||
102 | } |
||
103 | |||
104 | /* |
||
105 | * Object on the stack may have changed if acpi_ex_resolve_object_to_value() |
||
106 | * was called (i.e., we can't use an _else_ here.) |
||
107 | */ |
||
108 | if (ACPI_GET_DESCRIPTOR_TYPE(*stack_ptr) == ACPI_DESC_TYPE_NAMED) { |
||
109 | status = |
||
110 | acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR |
||
111 | (struct acpi_namespace_node, |
||
112 | stack_ptr), walk_state); |
||
113 | if (ACPI_FAILURE(status)) { |
||
114 | return_ACPI_STATUS(status); |
||
115 | } |
||
116 | } |
||
117 | |||
118 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr)); |
||
119 | return_ACPI_STATUS(AE_OK); |
||
120 | } |
||
121 | |||
122 | /******************************************************************************* |
||
123 | * |
||
124 | * FUNCTION: acpi_ex_resolve_object_to_value |
||
125 | * |
||
126 | * PARAMETERS: stack_ptr - Pointer to an internal object |
||
127 | * walk_state - Current method state |
||
128 | * |
||
129 | * RETURN: Status |
||
130 | * |
||
131 | * DESCRIPTION: Retrieve the value from an internal object. The Reference type |
||
132 | * uses the associated AML opcode to determine the value. |
||
133 | * |
||
134 | ******************************************************************************/ |
||
135 | |||
136 | static acpi_status |
||
137 | acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, |
||
138 | struct acpi_walk_state *walk_state) |
||
139 | { |
||
140 | acpi_status status = AE_OK; |
||
141 | union acpi_operand_object *stack_desc; |
||
142 | union acpi_operand_object *obj_desc = NULL; |
||
143 | u8 ref_type; |
||
144 | |||
145 | ACPI_FUNCTION_TRACE(ex_resolve_object_to_value); |
||
146 | |||
147 | stack_desc = *stack_ptr; |
||
148 | |||
149 | /* This is an object of type union acpi_operand_object */ |
||
150 | |||
151 | switch (stack_desc->common.type) { |
||
152 | case ACPI_TYPE_LOCAL_REFERENCE: |
||
153 | |||
154 | ref_type = stack_desc->reference.class; |
||
155 | |||
156 | switch (ref_type) { |
||
157 | case ACPI_REFCLASS_LOCAL: |
||
158 | case ACPI_REFCLASS_ARG: |
||
159 | /* |
||
160 | * Get the local from the method's state info |
||
161 | * Note: this increments the local's object reference count |
||
162 | */ |
||
163 | status = acpi_ds_method_data_get_value(ref_type, |
||
164 | stack_desc-> |
||
165 | reference.value, |
||
166 | walk_state, |
||
167 | &obj_desc); |
||
168 | if (ACPI_FAILURE(status)) { |
||
169 | return_ACPI_STATUS(status); |
||
170 | } |
||
171 | |||
172 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
||
173 | "[Arg/Local %X] ValueObj is %p\n", |
||
174 | stack_desc->reference.value, |
||
175 | obj_desc)); |
||
176 | |||
177 | /* |
||
178 | * Now we can delete the original Reference Object and |
||
179 | * replace it with the resolved value |
||
180 | */ |
||
181 | acpi_ut_remove_reference(stack_desc); |
||
182 | *stack_ptr = obj_desc; |
||
183 | break; |
||
184 | |||
185 | case ACPI_REFCLASS_INDEX: |
||
186 | |||
187 | switch (stack_desc->reference.target_type) { |
||
188 | case ACPI_TYPE_BUFFER_FIELD: |
||
189 | |||
190 | /* Just return - do not dereference */ |
||
191 | break; |
||
192 | |||
193 | case ACPI_TYPE_PACKAGE: |
||
194 | |||
195 | /* If method call or copy_object - do not dereference */ |
||
196 | |||
197 | if ((walk_state->opcode == |
||
198 | AML_INT_METHODCALL_OP) |
||
199 | || (walk_state->opcode == AML_COPY_OP)) { |
||
200 | break; |
||
201 | } |
||
202 | |||
203 | /* Otherwise, dereference the package_index to a package element */ |
||
204 | |||
205 | obj_desc = *stack_desc->reference.where; |
||
206 | if (obj_desc) { |
||
207 | /* |
||
208 | * Valid object descriptor, copy pointer to return value |
||
209 | * (i.e., dereference the package index) |
||
210 | * Delete the ref object, increment the returned object |
||
211 | */ |
||
212 | acpi_ut_add_reference(obj_desc); |
||
213 | *stack_ptr = obj_desc; |
||
214 | } else { |
||
215 | /* |
||
216 | * A NULL object descriptor means an uninitialized element of |
||
217 | * the package, can't dereference it |
||
218 | */ |
||
219 | ACPI_ERROR((AE_INFO, |
||
220 | "Attempt to dereference an Index to NULL package element Idx=%p", |
||
221 | stack_desc)); |
||
222 | status = AE_AML_UNINITIALIZED_ELEMENT; |
||
223 | } |
||
224 | break; |
||
225 | |||
226 | default: |
||
227 | |||
228 | /* Invalid reference object */ |
||
229 | |||
230 | ACPI_ERROR((AE_INFO, |
||
231 | "Unknown TargetType 0x%X in Index/Reference object %p", |
||
232 | stack_desc->reference.target_type, |
||
233 | stack_desc)); |
||
234 | status = AE_AML_INTERNAL; |
||
235 | break; |
||
236 | } |
||
237 | break; |
||
238 | |||
239 | case ACPI_REFCLASS_REFOF: |
||
240 | case ACPI_REFCLASS_DEBUG: |
||
241 | case ACPI_REFCLASS_TABLE: |
||
242 | |||
243 | /* Just leave the object as-is, do not dereference */ |
||
244 | |||
245 | break; |
||
246 | |||
247 | case ACPI_REFCLASS_NAME: /* Reference to a named object */ |
||
248 | |||
249 | /* Dereference the name */ |
||
250 | |||
251 | if ((stack_desc->reference.node->type == |
||
252 | ACPI_TYPE_DEVICE) |
||
253 | || (stack_desc->reference.node->type == |
||
254 | ACPI_TYPE_THERMAL)) { |
||
255 | |||
256 | /* These node types do not have 'real' subobjects */ |
||
257 | |||
258 | *stack_ptr = (void *)stack_desc->reference.node; |
||
259 | } else { |
||
260 | /* Get the object pointed to by the namespace node */ |
||
261 | |||
262 | *stack_ptr = |
||
263 | (stack_desc->reference.node)->object; |
||
264 | acpi_ut_add_reference(*stack_ptr); |
||
265 | } |
||
266 | |||
267 | acpi_ut_remove_reference(stack_desc); |
||
268 | break; |
||
269 | |||
270 | default: |
||
271 | |||
272 | ACPI_ERROR((AE_INFO, |
||
273 | "Unknown Reference type 0x%X in %p", |
||
274 | ref_type, stack_desc)); |
||
275 | status = AE_AML_INTERNAL; |
||
276 | break; |
||
277 | } |
||
278 | break; |
||
279 | |||
280 | case ACPI_TYPE_BUFFER: |
||
281 | |||
282 | status = acpi_ds_get_buffer_arguments(stack_desc); |
||
283 | break; |
||
284 | |||
285 | case ACPI_TYPE_PACKAGE: |
||
286 | |||
287 | status = acpi_ds_get_package_arguments(stack_desc); |
||
288 | break; |
||
289 | |||
290 | case ACPI_TYPE_BUFFER_FIELD: |
||
291 | case ACPI_TYPE_LOCAL_REGION_FIELD: |
||
292 | case ACPI_TYPE_LOCAL_BANK_FIELD: |
||
293 | case ACPI_TYPE_LOCAL_INDEX_FIELD: |
||
294 | |||
295 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
||
296 | "FieldRead SourceDesc=%p Type=%X\n", |
||
297 | stack_desc, stack_desc->common.type)); |
||
298 | |||
299 | status = |
||
300 | acpi_ex_read_data_from_field(walk_state, stack_desc, |
||
301 | &obj_desc); |
||
302 | |||
303 | /* Remove a reference to the original operand, then override */ |
||
304 | |||
305 | acpi_ut_remove_reference(*stack_ptr); |
||
306 | *stack_ptr = (void *)obj_desc; |
||
307 | break; |
||
308 | |||
309 | default: |
||
310 | |||
311 | break; |
||
312 | } |
||
313 | |||
314 | return_ACPI_STATUS(status); |
||
315 | } |
||
316 | |||
317 | /******************************************************************************* |
||
318 | * |
||
319 | * FUNCTION: acpi_ex_resolve_multiple |
||
320 | * |
||
321 | * PARAMETERS: walk_state - Current state (contains AML opcode) |
||
322 | * operand - Starting point for resolution |
||
323 | * return_type - Where the object type is returned |
||
324 | * return_desc - Where the resolved object is returned |
||
325 | * |
||
326 | * RETURN: Status |
||
327 | * |
||
328 | * DESCRIPTION: Return the base object and type. Traverse a reference list if |
||
329 | * necessary to get to the base object. |
||
330 | * |
||
331 | ******************************************************************************/ |
||
332 | |||
333 | acpi_status |
||
334 | acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, |
||
335 | union acpi_operand_object *operand, |
||
336 | acpi_object_type * return_type, |
||
337 | union acpi_operand_object **return_desc) |
||
338 | { |
||
339 | union acpi_operand_object *obj_desc = ACPI_CAST_PTR(void, operand); |
||
340 | struct acpi_namespace_node *node = |
||
341 | ACPI_CAST_PTR(struct acpi_namespace_node, operand); |
||
342 | acpi_object_type type; |
||
343 | acpi_status status; |
||
344 | |||
345 | ACPI_FUNCTION_TRACE(acpi_ex_resolve_multiple); |
||
346 | |||
347 | /* Operand can be either a namespace node or an operand descriptor */ |
||
348 | |||
349 | switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) { |
||
350 | case ACPI_DESC_TYPE_OPERAND: |
||
351 | |||
352 | type = obj_desc->common.type; |
||
353 | break; |
||
354 | |||
355 | case ACPI_DESC_TYPE_NAMED: |
||
356 | |||
357 | type = ((struct acpi_namespace_node *)obj_desc)->type; |
||
358 | obj_desc = acpi_ns_get_attached_object(node); |
||
359 | |||
360 | /* If we had an Alias node, use the attached object for type info */ |
||
361 | |||
362 | if (type == ACPI_TYPE_LOCAL_ALIAS) { |
||
363 | type = ((struct acpi_namespace_node *)obj_desc)->type; |
||
364 | obj_desc = |
||
365 | acpi_ns_get_attached_object((struct |
||
366 | acpi_namespace_node *) |
||
367 | obj_desc); |
||
368 | } |
||
369 | |||
370 | if (!obj_desc) { |
||
371 | ACPI_ERROR((AE_INFO, |
||
372 | "[%4.4s] Node is unresolved or uninitialized", |
||
373 | acpi_ut_get_node_name(node))); |
||
374 | return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE); |
||
375 | } |
||
376 | break; |
||
377 | |||
378 | default: |
||
379 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
||
380 | } |
||
381 | |||
382 | /* If type is anything other than a reference, we are done */ |
||
383 | |||
384 | if (type != ACPI_TYPE_LOCAL_REFERENCE) { |
||
385 | goto exit; |
||
386 | } |
||
387 | |||
388 | /* |
||
389 | * For reference objects created via the ref_of, Index, or Load/load_table |
||
390 | * operators, we need to get to the base object (as per the ACPI |
||
391 | * specification of the object_type and size_of operators). This means |
||
392 | * traversing the list of possibly many nested references. |
||
393 | */ |
||
394 | while (obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) { |
||
395 | switch (obj_desc->reference.class) { |
||
396 | case ACPI_REFCLASS_REFOF: |
||
397 | case ACPI_REFCLASS_NAME: |
||
398 | |||
399 | /* Dereference the reference pointer */ |
||
400 | |||
401 | if (obj_desc->reference.class == ACPI_REFCLASS_REFOF) { |
||
402 | node = obj_desc->reference.object; |
||
403 | } else { /* AML_INT_NAMEPATH_OP */ |
||
404 | |||
405 | node = obj_desc->reference.node; |
||
406 | } |
||
407 | |||
408 | /* All "References" point to a NS node */ |
||
409 | |||
410 | if (ACPI_GET_DESCRIPTOR_TYPE(node) != |
||
411 | ACPI_DESC_TYPE_NAMED) { |
||
412 | ACPI_ERROR((AE_INFO, |
||
413 | "Not a namespace node %p [%s]", |
||
414 | node, |
||
415 | acpi_ut_get_descriptor_name(node))); |
||
416 | return_ACPI_STATUS(AE_AML_INTERNAL); |
||
417 | } |
||
418 | |||
419 | /* Get the attached object */ |
||
420 | |||
421 | obj_desc = acpi_ns_get_attached_object(node); |
||
422 | if (!obj_desc) { |
||
423 | |||
424 | /* No object, use the NS node type */ |
||
425 | |||
426 | type = acpi_ns_get_type(node); |
||
427 | goto exit; |
||
428 | } |
||
429 | |||
430 | /* Check for circular references */ |
||
431 | |||
432 | if (obj_desc == operand) { |
||
433 | return_ACPI_STATUS(AE_AML_CIRCULAR_REFERENCE); |
||
434 | } |
||
435 | break; |
||
436 | |||
437 | case ACPI_REFCLASS_INDEX: |
||
438 | |||
439 | /* Get the type of this reference (index into another object) */ |
||
440 | |||
441 | type = obj_desc->reference.target_type; |
||
442 | if (type != ACPI_TYPE_PACKAGE) { |
||
443 | goto exit; |
||
444 | } |
||
445 | |||
446 | /* |
||
447 | * The main object is a package, we want to get the type |
||
448 | * of the individual package element that is referenced by |
||
449 | * the index. |
||
450 | * |
||
451 | * This could of course in turn be another reference object. |
||
452 | */ |
||
453 | obj_desc = *(obj_desc->reference.where); |
||
454 | if (!obj_desc) { |
||
455 | |||
456 | /* NULL package elements are allowed */ |
||
457 | |||
458 | type = 0; /* Uninitialized */ |
||
459 | goto exit; |
||
460 | } |
||
461 | break; |
||
462 | |||
463 | case ACPI_REFCLASS_TABLE: |
||
464 | |||
465 | type = ACPI_TYPE_DDB_HANDLE; |
||
466 | goto exit; |
||
467 | |||
468 | case ACPI_REFCLASS_LOCAL: |
||
469 | case ACPI_REFCLASS_ARG: |
||
470 | |||
471 | if (return_desc) { |
||
472 | status = |
||
473 | acpi_ds_method_data_get_value(obj_desc-> |
||
474 | reference. |
||
475 | class, |
||
476 | obj_desc-> |
||
477 | reference. |
||
478 | value, |
||
479 | walk_state, |
||
480 | &obj_desc); |
||
481 | if (ACPI_FAILURE(status)) { |
||
482 | return_ACPI_STATUS(status); |
||
483 | } |
||
484 | acpi_ut_remove_reference(obj_desc); |
||
485 | } else { |
||
486 | status = |
||
487 | acpi_ds_method_data_get_node(obj_desc-> |
||
488 | reference. |
||
489 | class, |
||
490 | obj_desc-> |
||
491 | reference. |
||
492 | value, |
||
493 | walk_state, |
||
494 | &node); |
||
495 | if (ACPI_FAILURE(status)) { |
||
496 | return_ACPI_STATUS(status); |
||
497 | } |
||
498 | |||
499 | obj_desc = acpi_ns_get_attached_object(node); |
||
500 | if (!obj_desc) { |
||
501 | type = ACPI_TYPE_ANY; |
||
502 | goto exit; |
||
503 | } |
||
504 | } |
||
505 | break; |
||
506 | |||
507 | case ACPI_REFCLASS_DEBUG: |
||
508 | |||
509 | /* The Debug Object is of type "DebugObject" */ |
||
510 | |||
511 | type = ACPI_TYPE_DEBUG_OBJECT; |
||
512 | goto exit; |
||
513 | |||
514 | default: |
||
515 | |||
516 | ACPI_ERROR((AE_INFO, |
||
517 | "Unknown Reference Class 0x%2.2X", |
||
518 | obj_desc->reference.class)); |
||
519 | return_ACPI_STATUS(AE_AML_INTERNAL); |
||
520 | } |
||
521 | } |
||
522 | |||
523 | /* |
||
524 | * Now we are guaranteed to have an object that has not been created |
||
525 | * via the ref_of or Index operators. |
||
526 | */ |
||
527 | type = obj_desc->common.type; |
||
528 | |||
529 | exit: |
||
530 | /* Convert internal types to external types */ |
||
531 | |||
532 | switch (type) { |
||
533 | case ACPI_TYPE_LOCAL_REGION_FIELD: |
||
534 | case ACPI_TYPE_LOCAL_BANK_FIELD: |
||
535 | case ACPI_TYPE_LOCAL_INDEX_FIELD: |
||
536 | |||
537 | type = ACPI_TYPE_FIELD_UNIT; |
||
538 | break; |
||
539 | |||
540 | case ACPI_TYPE_LOCAL_SCOPE: |
||
541 | |||
542 | /* Per ACPI Specification, Scope is untyped */ |
||
543 | |||
544 | type = ACPI_TYPE_ANY; |
||
545 | break; |
||
546 | |||
547 | default: |
||
548 | |||
549 | /* No change to Type required */ |
||
550 | |||
551 | break; |
||
552 | } |
||
553 | |||
554 | *return_type = type; |
||
555 | if (return_desc) { |
||
556 | *return_desc = obj_desc; |
||
557 | } |
||
558 | return_ACPI_STATUS(AE_OK); |
||
559 | } |