1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: dspkginit - Completion of deferred package initialization |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acnamesp.h" |
13 | #include "amlcode.h" |
14 | #include "acdispat.h" |
15 | #include "acinterp.h" |
16 | #include "acparser.h" |
17 | |
18 | #define _COMPONENT ACPI_NAMESPACE |
19 | ACPI_MODULE_NAME("dspkginit" ) |
20 | |
21 | /* Local prototypes */ |
22 | static void |
23 | acpi_ds_resolve_package_element(union acpi_operand_object **element); |
24 | |
25 | /******************************************************************************* |
26 | * |
27 | * FUNCTION: acpi_ds_build_internal_package_obj |
28 | * |
29 | * PARAMETERS: walk_state - Current walk state |
30 | * op - Parser object to be translated |
31 | * element_count - Number of elements in the package - this is |
32 | * the num_elements argument to Package() |
33 | * obj_desc_ptr - Where the ACPI internal object is returned |
34 | * |
35 | * RETURN: Status |
36 | * |
37 | * DESCRIPTION: Translate a parser Op package object to the equivalent |
38 | * namespace object |
39 | * |
40 | * NOTE: The number of elements in the package will be always be the num_elements |
41 | * count, regardless of the number of elements in the package list. If |
42 | * num_elements is smaller, only that many package list elements are used. |
43 | * if num_elements is larger, the Package object is padded out with |
44 | * objects of type Uninitialized (as per ACPI spec.) |
45 | * |
46 | * Even though the ASL compilers do not allow num_elements to be smaller |
47 | * than the Package list length (for the fixed length package opcode), some |
48 | * BIOS code modifies the AML on the fly to adjust the num_elements, and |
49 | * this code compensates for that. This also provides compatibility with |
50 | * other AML interpreters. |
51 | * |
52 | ******************************************************************************/ |
53 | |
54 | acpi_status |
55 | acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, |
56 | union acpi_parse_object *op, |
57 | u32 element_count, |
58 | union acpi_operand_object **obj_desc_ptr) |
59 | { |
60 | union acpi_parse_object *arg; |
61 | union acpi_parse_object *parent; |
62 | union acpi_operand_object *obj_desc = NULL; |
63 | acpi_status status = AE_OK; |
64 | u8 module_level_code = FALSE; |
65 | u16 reference_count; |
66 | u32 index; |
67 | u32 i; |
68 | |
69 | ACPI_FUNCTION_TRACE(ds_build_internal_package_obj); |
70 | |
71 | /* Check if we are executing module level code */ |
72 | |
73 | if (walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL) { |
74 | module_level_code = TRUE; |
75 | } |
76 | |
77 | /* Find the parent of a possibly nested package */ |
78 | |
79 | parent = op->common.parent; |
80 | while ((parent->common.aml_opcode == AML_PACKAGE_OP) || |
81 | (parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP)) { |
82 | parent = parent->common.parent; |
83 | } |
84 | |
85 | /* |
86 | * If we are evaluating a Named package object of the form: |
87 | * Name (xxxx, Package) |
88 | * the package object already exists, otherwise it must be created. |
89 | */ |
90 | obj_desc = *obj_desc_ptr; |
91 | if (!obj_desc) { |
92 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE); |
93 | *obj_desc_ptr = obj_desc; |
94 | if (!obj_desc) { |
95 | return_ACPI_STATUS(AE_NO_MEMORY); |
96 | } |
97 | |
98 | obj_desc->package.node = parent->common.node; |
99 | } |
100 | |
101 | if (obj_desc->package.flags & AOPOBJ_DATA_VALID) { /* Just in case */ |
102 | return_ACPI_STATUS(AE_OK); |
103 | } |
104 | |
105 | /* |
106 | * Allocate the element array (array of pointers to the individual |
107 | * objects) if necessary. the count is based on the num_elements |
108 | * parameter. Add an extra pointer slot so that the list is always |
109 | * null terminated. |
110 | */ |
111 | if (!obj_desc->package.elements) { |
112 | obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) |
113 | element_count |
114 | + |
115 | 1) * |
116 | sizeof(void |
117 | *)); |
118 | |
119 | if (!obj_desc->package.elements) { |
120 | acpi_ut_delete_object_desc(object: obj_desc); |
121 | return_ACPI_STATUS(AE_NO_MEMORY); |
122 | } |
123 | |
124 | obj_desc->package.count = element_count; |
125 | } |
126 | |
127 | /* First arg is element count. Second arg begins the initializer list */ |
128 | |
129 | arg = op->common.value.arg; |
130 | arg = arg->common.next; |
131 | |
132 | /* |
133 | * If we are executing module-level code, we will defer the |
134 | * full resolution of the package elements in order to support |
135 | * forward references from the elements. This provides |
136 | * compatibility with other ACPI implementations. |
137 | */ |
138 | if (module_level_code) { |
139 | obj_desc->package.aml_start = walk_state->aml; |
140 | obj_desc->package.aml_length = 0; |
141 | |
142 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE, |
143 | "%s: Deferring resolution of Package elements\n" , |
144 | ACPI_GET_FUNCTION_NAME)); |
145 | } |
146 | |
147 | /* |
148 | * Initialize the elements of the package, up to the num_elements count. |
149 | * Package is automatically padded with uninitialized (NULL) elements |
150 | * if num_elements is greater than the package list length. Likewise, |
151 | * Package is truncated if num_elements is less than the list length. |
152 | */ |
153 | for (i = 0; arg && (i < element_count); i++) { |
154 | if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { |
155 | if (!arg->common.node) { |
156 | /* |
157 | * This is the case where an expression has returned a value. |
158 | * The use of expressions (term_args) within individual |
159 | * package elements is not supported by the AML interpreter, |
160 | * even though the ASL grammar supports it. Example: |
161 | * |
162 | * Name (INT1, 0x1234) |
163 | * |
164 | * Name (PKG3, Package () { |
165 | * Add (INT1, 0xAAAA0000) |
166 | * }) |
167 | * |
168 | * 1) No known AML interpreter supports this type of construct |
169 | * 2) This fixes a fault if the construct is encountered |
170 | */ |
171 | ACPI_EXCEPTION((AE_INFO, AE_SUPPORT, |
172 | "Expressions within package elements are not supported" )); |
173 | |
174 | /* Cleanup the return object, it is not needed */ |
175 | |
176 | acpi_ut_remove_reference(object: walk_state->results-> |
177 | results.obj_desc[0]); |
178 | return_ACPI_STATUS(AE_SUPPORT); |
179 | } |
180 | |
181 | if (arg->common.node->type == ACPI_TYPE_METHOD) { |
182 | /* |
183 | * A method reference "looks" to the parser to be a method |
184 | * invocation, so we special case it here |
185 | */ |
186 | arg->common.aml_opcode = AML_INT_NAMEPATH_OP; |
187 | status = |
188 | acpi_ds_build_internal_object(walk_state, |
189 | op: arg, |
190 | obj_desc_ptr: &obj_desc-> |
191 | package. |
192 | elements[i]); |
193 | } else { |
194 | /* This package element is already built, just get it */ |
195 | |
196 | obj_desc->package.elements[i] = |
197 | ACPI_CAST_PTR(union acpi_operand_object, |
198 | arg->common.node); |
199 | } |
200 | } else { |
201 | status = |
202 | acpi_ds_build_internal_object(walk_state, op: arg, |
203 | obj_desc_ptr: &obj_desc->package. |
204 | elements[i]); |
205 | if (status == AE_NOT_FOUND) { |
206 | ACPI_ERROR((AE_INFO, "%-48s" , |
207 | "****DS namepath not found" )); |
208 | } |
209 | |
210 | if (!module_level_code) { |
211 | /* |
212 | * Initialize this package element. This function handles the |
213 | * resolution of named references within the package. |
214 | * Forward references from module-level code are deferred |
215 | * until all ACPI tables are loaded. |
216 | */ |
217 | acpi_ds_init_package_element(object_type: 0, |
218 | source_object: obj_desc->package. |
219 | elements[i], NULL, |
220 | context: &obj_desc->package. |
221 | elements[i]); |
222 | } |
223 | } |
224 | |
225 | if (*obj_desc_ptr) { |
226 | |
227 | /* Existing package, get existing reference count */ |
228 | |
229 | reference_count = |
230 | (*obj_desc_ptr)->common.reference_count; |
231 | if (reference_count > 1) { |
232 | |
233 | /* Make new element ref count match original ref count */ |
234 | /* TBD: Probably need an acpi_ut_add_references function */ |
235 | |
236 | for (index = 0; |
237 | index < ((u32)reference_count - 1); |
238 | index++) { |
239 | acpi_ut_add_reference(object: (obj_desc-> |
240 | package. |
241 | elements[i])); |
242 | } |
243 | } |
244 | } |
245 | |
246 | arg = arg->common.next; |
247 | } |
248 | |
249 | /* Check for match between num_elements and actual length of package_list */ |
250 | |
251 | if (arg) { |
252 | /* |
253 | * num_elements was exhausted, but there are remaining elements in |
254 | * the package_list. Truncate the package to num_elements. |
255 | * |
256 | * Note: technically, this is an error, from ACPI spec: "It is an |
257 | * error for NumElements to be less than the number of elements in |
258 | * the PackageList". However, we just print a message and no |
259 | * exception is returned. This provides compatibility with other |
260 | * ACPI implementations. Some firmware implementations will alter |
261 | * the num_elements on the fly, possibly creating this type of |
262 | * ill-formed package object. |
263 | */ |
264 | while (arg) { |
265 | /* |
266 | * We must delete any package elements that were created earlier |
267 | * and are not going to be used because of the package truncation. |
268 | */ |
269 | if (arg->common.node) { |
270 | acpi_ut_remove_reference(ACPI_CAST_PTR |
271 | (union |
272 | acpi_operand_object, |
273 | arg->common.node)); |
274 | arg->common.node = NULL; |
275 | } |
276 | |
277 | /* Find out how many elements there really are */ |
278 | |
279 | i++; |
280 | arg = arg->common.next; |
281 | } |
282 | |
283 | ACPI_INFO(("Actual Package length (%u) is larger than " |
284 | "NumElements field (%u), truncated" , |
285 | i, element_count)); |
286 | } else if (i < element_count) { |
287 | /* |
288 | * Arg list (elements) was exhausted, but we did not reach |
289 | * num_elements count. |
290 | * |
291 | * Note: this is not an error, the package is padded out |
292 | * with NULLs as per the ACPI specification. |
293 | */ |
294 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, |
295 | "%s: Package List length (%u) smaller than NumElements " |
296 | "count (%u), padded with null elements\n" , |
297 | ACPI_GET_FUNCTION_NAME, i, |
298 | element_count)); |
299 | } |
300 | |
301 | /* Module-level packages will be resolved later */ |
302 | |
303 | if (!module_level_code) { |
304 | obj_desc->package.flags |= AOPOBJ_DATA_VALID; |
305 | } |
306 | |
307 | op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); |
308 | return_ACPI_STATUS(status); |
309 | } |
310 | |
311 | /******************************************************************************* |
312 | * |
313 | * FUNCTION: acpi_ds_init_package_element |
314 | * |
315 | * PARAMETERS: acpi_pkg_callback |
316 | * |
317 | * RETURN: Status |
318 | * |
319 | * DESCRIPTION: Resolve a named reference element within a package object |
320 | * |
321 | ******************************************************************************/ |
322 | |
323 | acpi_status |
324 | acpi_ds_init_package_element(u8 object_type, |
325 | union acpi_operand_object *source_object, |
326 | union acpi_generic_state *state, void *context) |
327 | { |
328 | union acpi_operand_object **element_ptr; |
329 | |
330 | ACPI_FUNCTION_TRACE(ds_init_package_element); |
331 | |
332 | if (!source_object) { |
333 | return_ACPI_STATUS(AE_OK); |
334 | } |
335 | |
336 | /* |
337 | * The following code is a bit of a hack to workaround a (current) |
338 | * limitation of the acpi_pkg_callback interface. We need a pointer |
339 | * to the location within the element array because a new object |
340 | * may be created and stored there. |
341 | */ |
342 | if (context) { |
343 | |
344 | /* A direct call was made to this function */ |
345 | |
346 | element_ptr = (union acpi_operand_object **)context; |
347 | } else { |
348 | /* Call came from acpi_ut_walk_package_tree */ |
349 | |
350 | element_ptr = state->pkg.this_target_obj; |
351 | } |
352 | |
353 | /* We are only interested in reference objects/elements */ |
354 | |
355 | if (source_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) { |
356 | |
357 | /* Attempt to resolve the (named) reference to a namespace node */ |
358 | |
359 | acpi_ds_resolve_package_element(element: element_ptr); |
360 | } else if (source_object->common.type == ACPI_TYPE_PACKAGE) { |
361 | source_object->package.flags |= AOPOBJ_DATA_VALID; |
362 | } |
363 | |
364 | return_ACPI_STATUS(AE_OK); |
365 | } |
366 | |
367 | /******************************************************************************* |
368 | * |
369 | * FUNCTION: acpi_ds_resolve_package_element |
370 | * |
371 | * PARAMETERS: element_ptr - Pointer to a reference object |
372 | * |
373 | * RETURN: Possible new element is stored to the indirect element_ptr |
374 | * |
375 | * DESCRIPTION: Resolve a package element that is a reference to a named |
376 | * object. |
377 | * |
378 | ******************************************************************************/ |
379 | |
380 | static void |
381 | acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr) |
382 | { |
383 | acpi_status status; |
384 | acpi_status status2; |
385 | union acpi_generic_state scope_info; |
386 | union acpi_operand_object *element = *element_ptr; |
387 | struct acpi_namespace_node *resolved_node; |
388 | struct acpi_namespace_node *original_node; |
389 | char *external_path = "" ; |
390 | acpi_object_type type; |
391 | |
392 | ACPI_FUNCTION_TRACE(ds_resolve_package_element); |
393 | |
394 | /* Check if reference element is already resolved */ |
395 | |
396 | if (element->reference.resolved) { |
397 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE, |
398 | "%s: Package element is already resolved\n" , |
399 | ACPI_GET_FUNCTION_NAME)); |
400 | |
401 | return_VOID; |
402 | } |
403 | |
404 | /* Element must be a reference object of correct type */ |
405 | |
406 | scope_info.scope.node = element->reference.node; /* Prefix node */ |
407 | |
408 | status = acpi_ns_lookup(scope_info: &scope_info, name: (char *)element->reference.aml, |
409 | ACPI_TYPE_ANY, interpreter_mode: ACPI_IMODE_EXECUTE, |
410 | ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, |
411 | NULL, ret_node: &resolved_node); |
412 | if (ACPI_FAILURE(status)) { |
413 | if ((status == AE_NOT_FOUND) |
414 | && acpi_gbl_ignore_package_resolution_errors) { |
415 | /* |
416 | * Optionally be silent about the NOT_FOUND case for the referenced |
417 | * name. Although this is potentially a serious problem, |
418 | * it can generate a lot of noise/errors on platforms whose |
419 | * firmware carries around a bunch of unused Package objects. |
420 | * To disable these errors, set this global to TRUE: |
421 | * acpi_gbl_ignore_package_resolution_errors |
422 | * |
423 | * If the AML actually tries to use such a package, the unresolved |
424 | * element(s) will be replaced with NULL elements. |
425 | */ |
426 | |
427 | /* Referenced name not found, set the element to NULL */ |
428 | |
429 | acpi_ut_remove_reference(object: *element_ptr); |
430 | *element_ptr = NULL; |
431 | return_VOID; |
432 | } |
433 | |
434 | status2 = acpi_ns_externalize_name(ACPI_UINT32_MAX, |
435 | internal_name: (char *)element->reference. |
436 | aml, NULL, converted_name: &external_path); |
437 | |
438 | ACPI_EXCEPTION((AE_INFO, status, |
439 | "While resolving a named reference package element - %s" , |
440 | external_path)); |
441 | if (ACPI_SUCCESS(status2)) { |
442 | ACPI_FREE(external_path); |
443 | } |
444 | |
445 | /* Could not resolve name, set the element to NULL */ |
446 | |
447 | acpi_ut_remove_reference(object: *element_ptr); |
448 | *element_ptr = NULL; |
449 | return_VOID; |
450 | } else if (resolved_node->type == ACPI_TYPE_ANY) { |
451 | |
452 | /* Named reference not resolved, return a NULL package element */ |
453 | |
454 | ACPI_ERROR((AE_INFO, |
455 | "Could not resolve named package element [%4.4s] in [%4.4s]" , |
456 | resolved_node->name.ascii, |
457 | scope_info.scope.node->name.ascii)); |
458 | *element_ptr = NULL; |
459 | return_VOID; |
460 | } |
461 | |
462 | /* |
463 | * Special handling for Alias objects. We need resolved_node to point |
464 | * to the Alias target. This effectively "resolves" the alias. |
465 | */ |
466 | if (resolved_node->type == ACPI_TYPE_LOCAL_ALIAS) { |
467 | resolved_node = ACPI_CAST_PTR(struct acpi_namespace_node, |
468 | resolved_node->object); |
469 | } |
470 | |
471 | /* Update the reference object */ |
472 | |
473 | element->reference.resolved = TRUE; |
474 | element->reference.node = resolved_node; |
475 | type = element->reference.node->type; |
476 | |
477 | /* |
478 | * Attempt to resolve the node to a value before we insert it into |
479 | * the package. If this is a reference to a common data type, |
480 | * resolve it immediately. According to the ACPI spec, package |
481 | * elements can only be "data objects" or method references. |
482 | * Attempt to resolve to an Integer, Buffer, String or Package. |
483 | * If cannot, return the named reference (for things like Devices, |
484 | * Methods, etc.) Buffer Fields and Fields will resolve to simple |
485 | * objects (int/buf/str/pkg). |
486 | * |
487 | * NOTE: References to things like Devices, Methods, Mutexes, etc. |
488 | * will remain as named references. This behavior is not described |
489 | * in the ACPI spec, but it appears to be an oversight. |
490 | */ |
491 | original_node = resolved_node; |
492 | status = acpi_ex_resolve_node_to_value(stack_ptr: &resolved_node, NULL); |
493 | if (ACPI_FAILURE(status)) { |
494 | return_VOID; |
495 | } |
496 | |
497 | switch (type) { |
498 | /* |
499 | * These object types are a result of named references, so we will |
500 | * leave them as reference objects. In other words, these types |
501 | * have no intrinsic "value". |
502 | */ |
503 | case ACPI_TYPE_DEVICE: |
504 | case ACPI_TYPE_THERMAL: |
505 | case ACPI_TYPE_METHOD: |
506 | break; |
507 | |
508 | case ACPI_TYPE_MUTEX: |
509 | case ACPI_TYPE_POWER: |
510 | case ACPI_TYPE_PROCESSOR: |
511 | case ACPI_TYPE_EVENT: |
512 | case ACPI_TYPE_REGION: |
513 | |
514 | /* acpi_ex_resolve_node_to_value gave these an extra reference */ |
515 | |
516 | acpi_ut_remove_reference(object: original_node->object); |
517 | break; |
518 | |
519 | default: |
520 | /* |
521 | * For all other types - the node was resolved to an actual |
522 | * operand object with a value, return the object. Remove |
523 | * a reference on the existing object. |
524 | */ |
525 | acpi_ut_remove_reference(object: element); |
526 | *element_ptr = (union acpi_operand_object *)resolved_node; |
527 | break; |
528 | } |
529 | |
530 | return_VOID; |
531 | } |
532 | |