532 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: dspkginit - Completion of deferred package initialization5 *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_NAMESPACE19ACPI_MODULE_NAME("dspkginit")20 21/* Local prototypes */22static void23acpi_ds_resolve_package_element(union acpi_operand_object **element);24 25/*******************************************************************************26 *27 * FUNCTION: acpi_ds_build_internal_package_obj28 *29 * PARAMETERS: walk_state - Current walk state30 * op - Parser object to be translated31 * element_count - Number of elements in the package - this is32 * the num_elements argument to Package()33 * obj_desc_ptr - Where the ACPI internal object is returned34 *35 * RETURN: Status36 *37 * DESCRIPTION: Translate a parser Op package object to the equivalent38 * namespace object39 *40 * NOTE: The number of elements in the package will be always be the num_elements41 * count, regardless of the number of elements in the package list. If42 * num_elements is smaller, only that many package list elements are used.43 * if num_elements is larger, the Package object is padded out with44 * objects of type Uninitialized (as per ACPI spec.)45 *46 * Even though the ASL compilers do not allow num_elements to be smaller47 * than the Package list length (for the fixed length package opcode), some48 * BIOS code modifies the AML on the fly to adjust the num_elements, and49 * this code compensates for that. This also provides compatibility with50 * other AML interpreters.51 *52 ******************************************************************************/53 54acpi_status55acpi_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 individual107 * objects) if necessary. the count is based on the num_elements108 * parameter. Add an extra pointer slot so that the list is always109 * null terminated.110 */111 if (!obj_desc->package.elements) {112 obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)113 element_count114 +115 1) *116 sizeof(void117 *));118 119 if (!obj_desc->package.elements) {120 acpi_ut_delete_object_desc(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 the134 * full resolution of the package elements in order to support135 * forward references from the elements. This provides136 * 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) elements150 * 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 individual159 * 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 construct169 * 2) This fixes a fault if the construct is encountered170 */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(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 method184 * invocation, so we special case it here185 */186 arg->common.aml_opcode = AML_INT_NAMEPATH_OP;187 status =188 acpi_ds_build_internal_object(walk_state,189 arg,190 &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, arg,203 &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 the213 * resolution of named references within the package.214 * Forward references from module-level code are deferred215 * until all ACPI tables are loaded.216 */217 acpi_ds_init_package_element(0,218 obj_desc->package.219 elements[i], NULL,220 &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((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 in254 * the package_list. Truncate the package to num_elements.255 *256 * Note: technically, this is an error, from ACPI spec: "It is an257 * error for NumElements to be less than the number of elements in258 * the PackageList". However, we just print a message and no259 * exception is returned. This provides compatibility with other260 * ACPI implementations. Some firmware implementations will alter261 * the num_elements on the fly, possibly creating this type of262 * ill-formed package object.263 */264 while (arg) {265 /*266 * We must delete any package elements that were created earlier267 * 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_PTR271 (union272 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 reach289 * num_elements count.290 *291 * Note: this is not an error, the package is padded out292 * 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_element314 *315 * PARAMETERS: acpi_pkg_callback316 *317 * RETURN: Status318 *319 * DESCRIPTION: Resolve a named reference element within a package object320 *321 ******************************************************************************/322 323acpi_status324acpi_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 pointer339 * to the location within the element array because a new object340 * 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_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_element370 *371 * PARAMETERS: element_ptr - Pointer to a reference object372 *373 * RETURN: Possible new element is stored to the indirect element_ptr374 *375 * DESCRIPTION: Resolve a package element that is a reference to a named376 * object.377 *378 ******************************************************************************/379 380static void381acpi_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, (char *)element->reference.aml,409 ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,410 ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,411 NULL, &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 referenced417 * name. Although this is potentially a serious problem,418 * it can generate a lot of noise/errors on platforms whose419 * 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_errors422 *423 * If the AML actually tries to use such a package, the unresolved424 * 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(*element_ptr);430 *element_ptr = NULL;431 return_VOID;432 }433 434 status2 = acpi_ns_externalize_name(ACPI_UINT32_MAX,435 (char *)element->reference.436 aml, NULL, &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(*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 point464 * 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 into479 * the package. If this is a reference to a common data type,480 * resolve it immediately. According to the ACPI spec, package481 * 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 simple485 * 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 described489 * 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(&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 will500 * leave them as reference objects. In other words, these types501 * 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(original_node->object);517 break;518 519 default:520 /*521 * For all other types - the node was resolved to an actual522 * operand object with a value, return the object. Remove523 * a reference on the existing object.524 */525 acpi_ut_remove_reference(element);526 *element_ptr = (union acpi_operand_object *)resolved_node;527 break;528 }529 530 return_VOID;531}532