// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.01/******************************************************************************2*3* Module Name: dspkginit - Completion of deferred package initialization4*5* Copyright (C) 2000 - 2025, Intel Corp.6*7*****************************************************************************/89#include <acpi/acpi.h>10#include "accommon.h"11#include "acnamesp.h"12#include "amlcode.h"13#include "acdispat.h"14#include "acinterp.h"15#include "acparser.h"1617#define _COMPONENT ACPI_NAMESPACE18ACPI_MODULE_NAME("dspkginit")1920/* Local prototypes */21static void22acpi_ds_resolve_package_element(union acpi_operand_object **element);2324/*******************************************************************************25*26* FUNCTION: acpi_ds_build_internal_package_obj27*28* PARAMETERS: walk_state - Current walk state29* op - Parser object to be translated30* element_count - Number of elements in the package - this is31* the num_elements argument to Package()32* obj_desc_ptr - Where the ACPI internal object is returned33*34* RETURN: Status35*36* DESCRIPTION: Translate a parser Op package object to the equivalent37* namespace object38*39* NOTE: The number of elements in the package will be always be the num_elements40* count, regardless of the number of elements in the package list. If41* num_elements is smaller, only that many package list elements are used.42* if num_elements is larger, the Package object is padded out with43* objects of type Uninitialized (as per ACPI spec.)44*45* Even though the ASL compilers do not allow num_elements to be smaller46* than the Package list length (for the fixed length package opcode), some47* BIOS code modifies the AML on the fly to adjust the num_elements, and48* this code compensates for that. This also provides compatibility with49* other AML interpreters.50*51******************************************************************************/5253acpi_status54acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,55union acpi_parse_object *op,56u32 element_count,57union acpi_operand_object **obj_desc_ptr)58{59union acpi_parse_object *arg;60union acpi_parse_object *parent;61union acpi_operand_object *obj_desc = NULL;62acpi_status status = AE_OK;63u8 module_level_code = FALSE;64u16 reference_count;65u32 index;66u32 i;6768ACPI_FUNCTION_TRACE(ds_build_internal_package_obj);6970/* Check if we are executing module level code */7172if (walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL) {73module_level_code = TRUE;74}7576/* Find the parent of a possibly nested package */7778parent = op->common.parent;79while ((parent->common.aml_opcode == AML_PACKAGE_OP) ||80(parent->common.aml_opcode == AML_VARIABLE_PACKAGE_OP)) {81parent = parent->common.parent;82}8384/*85* If we are evaluating a Named package object of the form:86* Name (xxxx, Package)87* the package object already exists, otherwise it must be created.88*/89obj_desc = *obj_desc_ptr;90if (!obj_desc) {91obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE);92*obj_desc_ptr = obj_desc;93if (!obj_desc) {94return_ACPI_STATUS(AE_NO_MEMORY);95}9697obj_desc->package.node = parent->common.node;98}99100if (obj_desc->package.flags & AOPOBJ_DATA_VALID) { /* Just in case */101return_ACPI_STATUS(AE_OK);102}103104/*105* Allocate the element array (array of pointers to the individual106* objects) if necessary. the count is based on the num_elements107* parameter. Add an extra pointer slot so that the list is always108* null terminated.109*/110if (!obj_desc->package.elements) {111obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)112element_count113+1141) *115sizeof(void116*));117118if (!obj_desc->package.elements) {119acpi_ut_delete_object_desc(obj_desc);120return_ACPI_STATUS(AE_NO_MEMORY);121}122123obj_desc->package.count = element_count;124}125126/* First arg is element count. Second arg begins the initializer list */127128arg = op->common.value.arg;129arg = arg->common.next;130131/*132* If we are executing module-level code, we will defer the133* full resolution of the package elements in order to support134* forward references from the elements. This provides135* compatibility with other ACPI implementations.136*/137if (module_level_code) {138obj_desc->package.aml_start = walk_state->aml;139obj_desc->package.aml_length = 0;140141ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,142"%s: Deferring resolution of Package elements\n",143ACPI_GET_FUNCTION_NAME));144}145146/*147* Initialize the elements of the package, up to the num_elements count.148* Package is automatically padded with uninitialized (NULL) elements149* if num_elements is greater than the package list length. Likewise,150* Package is truncated if num_elements is less than the list length.151*/152for (i = 0; arg && (i < element_count); i++) {153if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {154if (!arg->common.node) {155/*156* This is the case where an expression has returned a value.157* The use of expressions (term_args) within individual158* package elements is not supported by the AML interpreter,159* even though the ASL grammar supports it. Example:160*161* Name (INT1, 0x1234)162*163* Name (PKG3, Package () {164* Add (INT1, 0xAAAA0000)165* })166*167* 1) No known AML interpreter supports this type of construct168* 2) This fixes a fault if the construct is encountered169*/170ACPI_EXCEPTION((AE_INFO, AE_SUPPORT,171"Expressions within package elements are not supported"));172173/* Cleanup the return object, it is not needed */174175acpi_ut_remove_reference(walk_state->results->176results.obj_desc[0]);177return_ACPI_STATUS(AE_SUPPORT);178}179180if (arg->common.node->type == ACPI_TYPE_METHOD) {181/*182* A method reference "looks" to the parser to be a method183* invocation, so we special case it here184*/185arg->common.aml_opcode = AML_INT_NAMEPATH_OP;186status =187acpi_ds_build_internal_object(walk_state,188arg,189&obj_desc->190package.191elements[i]);192} else {193/* This package element is already built, just get it */194195obj_desc->package.elements[i] =196ACPI_CAST_PTR(union acpi_operand_object,197arg->common.node);198}199} else {200status =201acpi_ds_build_internal_object(walk_state, arg,202&obj_desc->package.203elements[i]);204if (status == AE_NOT_FOUND) {205ACPI_ERROR((AE_INFO, "%-48s",206"****DS namepath not found"));207}208209if (!module_level_code) {210/*211* Initialize this package element. This function handles the212* resolution of named references within the package.213* Forward references from module-level code are deferred214* until all ACPI tables are loaded.215*/216acpi_ds_init_package_element(0,217obj_desc->package.218elements[i], NULL,219&obj_desc->package.220elements[i]);221}222}223224if (*obj_desc_ptr) {225226/* Existing package, get existing reference count */227228reference_count =229(*obj_desc_ptr)->common.reference_count;230if (reference_count > 1) {231232/* Make new element ref count match original ref count */233/* TBD: Probably need an acpi_ut_add_references function */234235for (index = 0;236index < ((u32)reference_count - 1);237index++) {238acpi_ut_add_reference((obj_desc->239package.240elements[i]));241}242}243}244245arg = arg->common.next;246}247248/* Check for match between num_elements and actual length of package_list */249250if (arg) {251/*252* num_elements was exhausted, but there are remaining elements in253* the package_list. Truncate the package to num_elements.254*255* Note: technically, this is an error, from ACPI spec: "It is an256* error for NumElements to be less than the number of elements in257* the PackageList". However, we just print a message and no258* exception is returned. This provides compatibility with other259* ACPI implementations. Some firmware implementations will alter260* the num_elements on the fly, possibly creating this type of261* ill-formed package object.262*/263while (arg) {264/*265* We must delete any package elements that were created earlier266* and are not going to be used because of the package truncation.267*/268if (arg->common.node) {269acpi_ut_remove_reference(ACPI_CAST_PTR270(union271acpi_operand_object,272arg->common.node));273arg->common.node = NULL;274}275276/* Find out how many elements there really are */277278i++;279arg = arg->common.next;280}281282ACPI_INFO(("Actual Package length (%u) is larger than "283"NumElements field (%u), truncated",284i, element_count));285} else if (i < element_count) {286/*287* Arg list (elements) was exhausted, but we did not reach288* num_elements count.289*290* Note: this is not an error, the package is padded out291* with NULLs as per the ACPI specification.292*/293ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,294"%s: Package List length (%u) smaller than NumElements "295"count (%u), padded with null elements\n",296ACPI_GET_FUNCTION_NAME, i,297element_count));298}299300/* Module-level packages will be resolved later */301302if (!module_level_code) {303obj_desc->package.flags |= AOPOBJ_DATA_VALID;304}305306op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);307return_ACPI_STATUS(status);308}309310/*******************************************************************************311*312* FUNCTION: acpi_ds_init_package_element313*314* PARAMETERS: acpi_pkg_callback315*316* RETURN: Status317*318* DESCRIPTION: Resolve a named reference element within a package object319*320******************************************************************************/321322acpi_status323acpi_ds_init_package_element(u8 object_type,324union acpi_operand_object *source_object,325union acpi_generic_state *state, void *context)326{327union acpi_operand_object **element_ptr;328329ACPI_FUNCTION_TRACE(ds_init_package_element);330331if (!source_object) {332return_ACPI_STATUS(AE_OK);333}334335/*336* The following code is a bit of a hack to workaround a (current)337* limitation of the acpi_pkg_callback interface. We need a pointer338* to the location within the element array because a new object339* may be created and stored there.340*/341if (context) {342343/* A direct call was made to this function */344345element_ptr = (union acpi_operand_object **)context;346} else {347/* Call came from acpi_ut_walk_package_tree */348349element_ptr = state->pkg.this_target_obj;350}351352/* We are only interested in reference objects/elements */353354if (source_object->common.type == ACPI_TYPE_LOCAL_REFERENCE) {355356/* Attempt to resolve the (named) reference to a namespace node */357358acpi_ds_resolve_package_element(element_ptr);359} else if (source_object->common.type == ACPI_TYPE_PACKAGE) {360source_object->package.flags |= AOPOBJ_DATA_VALID;361}362363return_ACPI_STATUS(AE_OK);364}365366/*******************************************************************************367*368* FUNCTION: acpi_ds_resolve_package_element369*370* PARAMETERS: element_ptr - Pointer to a reference object371*372* RETURN: Possible new element is stored to the indirect element_ptr373*374* DESCRIPTION: Resolve a package element that is a reference to a named375* object.376*377******************************************************************************/378379static void380acpi_ds_resolve_package_element(union acpi_operand_object **element_ptr)381{382acpi_status status;383acpi_status status2;384union acpi_generic_state scope_info;385union acpi_operand_object *element = *element_ptr;386struct acpi_namespace_node *resolved_node;387struct acpi_namespace_node *original_node;388char *external_path = "";389acpi_object_type type;390391ACPI_FUNCTION_TRACE(ds_resolve_package_element);392393/* Check if reference element is already resolved */394395if (element->reference.resolved) {396ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,397"%s: Package element is already resolved\n",398ACPI_GET_FUNCTION_NAME));399400return_VOID;401}402403/* Element must be a reference object of correct type */404405scope_info.scope.node = element->reference.node; /* Prefix node */406407status = acpi_ns_lookup(&scope_info, (char *)element->reference.aml,408ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,409ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,410NULL, &resolved_node);411if (ACPI_FAILURE(status)) {412if ((status == AE_NOT_FOUND)413&& acpi_gbl_ignore_package_resolution_errors) {414/*415* Optionally be silent about the NOT_FOUND case for the referenced416* name. Although this is potentially a serious problem,417* it can generate a lot of noise/errors on platforms whose418* firmware carries around a bunch of unused Package objects.419* To disable these errors, set this global to TRUE:420* acpi_gbl_ignore_package_resolution_errors421*422* If the AML actually tries to use such a package, the unresolved423* element(s) will be replaced with NULL elements.424*/425426/* Referenced name not found, set the element to NULL */427428acpi_ut_remove_reference(*element_ptr);429*element_ptr = NULL;430return_VOID;431}432433status2 = acpi_ns_externalize_name(ACPI_UINT32_MAX,434(char *)element->reference.435aml, NULL, &external_path);436437ACPI_EXCEPTION((AE_INFO, status,438"While resolving a named reference package element - %s",439external_path));440if (ACPI_SUCCESS(status2)) {441ACPI_FREE(external_path);442}443444/* Could not resolve name, set the element to NULL */445446acpi_ut_remove_reference(*element_ptr);447*element_ptr = NULL;448return_VOID;449} else if (resolved_node->type == ACPI_TYPE_ANY) {450451/* Named reference not resolved, return a NULL package element */452453ACPI_ERROR((AE_INFO,454"Could not resolve named package element [%4.4s] in [%4.4s]",455resolved_node->name.ascii,456scope_info.scope.node->name.ascii));457*element_ptr = NULL;458return_VOID;459}460461/*462* Special handling for Alias objects. We need resolved_node to point463* to the Alias target. This effectively "resolves" the alias.464*/465if (resolved_node->type == ACPI_TYPE_LOCAL_ALIAS) {466resolved_node = ACPI_CAST_PTR(struct acpi_namespace_node,467resolved_node->object);468}469470/* Update the reference object */471472element->reference.resolved = TRUE;473element->reference.node = resolved_node;474type = element->reference.node->type;475476/*477* Attempt to resolve the node to a value before we insert it into478* the package. If this is a reference to a common data type,479* resolve it immediately. According to the ACPI spec, package480* elements can only be "data objects" or method references.481* Attempt to resolve to an Integer, Buffer, String or Package.482* If cannot, return the named reference (for things like Devices,483* Methods, etc.) Buffer Fields and Fields will resolve to simple484* objects (int/buf/str/pkg).485*486* NOTE: References to things like Devices, Methods, Mutexes, etc.487* will remain as named references. This behavior is not described488* in the ACPI spec, but it appears to be an oversight.489*/490original_node = resolved_node;491status = acpi_ex_resolve_node_to_value(&resolved_node, NULL);492if (ACPI_FAILURE(status)) {493return_VOID;494}495496switch (type) {497/*498* These object types are a result of named references, so we will499* leave them as reference objects. In other words, these types500* have no intrinsic "value".501*/502case ACPI_TYPE_DEVICE:503case ACPI_TYPE_THERMAL:504case ACPI_TYPE_METHOD:505break;506507case ACPI_TYPE_MUTEX:508case ACPI_TYPE_POWER:509case ACPI_TYPE_PROCESSOR:510case ACPI_TYPE_EVENT:511case ACPI_TYPE_REGION:512513/* acpi_ex_resolve_node_to_value gave these an extra reference */514515acpi_ut_remove_reference(original_node->object);516break;517518default:519/*520* For all other types - the node was resolved to an actual521* operand object with a value, return the object. Remove522* a reference on the existing object.523*/524acpi_ut_remove_reference(element);525*element_ptr = (union acpi_operand_object *)resolved_node;526break;527}528529return_VOID;530}531532533