162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/******************************************************************************* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: nsaccess - Top-level functions for accessing ACPI namespace 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci ******************************************************************************/ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <acpi/acpi.h> 962306a36Sopenharmony_ci#include "accommon.h" 1062306a36Sopenharmony_ci#include "amlcode.h" 1162306a36Sopenharmony_ci#include "acnamesp.h" 1262306a36Sopenharmony_ci#include "acdispat.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#ifdef ACPI_ASL_COMPILER 1562306a36Sopenharmony_ci#include "acdisasm.h" 1662306a36Sopenharmony_ci#endif 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define _COMPONENT ACPI_NAMESPACE 1962306a36Sopenharmony_ciACPI_MODULE_NAME("nsaccess") 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/******************************************************************************* 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * FUNCTION: acpi_ns_root_initialize 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * PARAMETERS: None 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * RETURN: Status 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * DESCRIPTION: Allocate and initialize the default root named objects 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * MUTEX: Locks namespace for entire execution 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci ******************************************************************************/ 3462306a36Sopenharmony_ciacpi_status acpi_ns_root_initialize(void) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci acpi_status status; 3762306a36Sopenharmony_ci const struct acpi_predefined_names *init_val = NULL; 3862306a36Sopenharmony_ci struct acpi_namespace_node *new_node; 3962306a36Sopenharmony_ci struct acpi_namespace_node *prev_node = NULL; 4062306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 4162306a36Sopenharmony_ci acpi_string val = NULL; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_root_initialize); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 4662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 4762306a36Sopenharmony_ci return_ACPI_STATUS(status); 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci /* 5162306a36Sopenharmony_ci * The global root ptr is initially NULL, so a non-NULL value indicates 5262306a36Sopenharmony_ci * that acpi_ns_root_initialize() has already been called; just return. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_ci if (acpi_gbl_root_node) { 5562306a36Sopenharmony_ci status = AE_OK; 5662306a36Sopenharmony_ci goto unlock_and_exit; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* 6062306a36Sopenharmony_ci * Tell the rest of the subsystem that the root is initialized 6162306a36Sopenharmony_ci * (This is OK because the namespace is locked) 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci acpi_gbl_root_node = &acpi_gbl_root_node_struct; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* Enter the predefined names in the name table */ 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, 6862306a36Sopenharmony_ci "Entering predefined entries into namespace\n")); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * Create the initial (default) namespace. 7262306a36Sopenharmony_ci * This namespace looks like something similar to this: 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * ACPI Namespace (from Namespace Root): 7562306a36Sopenharmony_ci * 0 _GPE Scope 00203160 00 7662306a36Sopenharmony_ci * 0 _PR_ Scope 002031D0 00 7762306a36Sopenharmony_ci * 0 _SB_ Device 00203240 00 Notify Object: 0020ADD8 7862306a36Sopenharmony_ci * 0 _SI_ Scope 002032B0 00 7962306a36Sopenharmony_ci * 0 _TZ_ Device 00203320 00 8062306a36Sopenharmony_ci * 0 _REV Integer 00203390 00 = 0000000000000002 8162306a36Sopenharmony_ci * 0 _OS_ String 00203488 00 Len 14 "Microsoft Windows NT" 8262306a36Sopenharmony_ci * 0 _GL_ Mutex 00203580 00 Object 002035F0 8362306a36Sopenharmony_ci * 0 _OSI Method 00203678 00 Args 1 Len 0000 Aml 00000000 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { 8662306a36Sopenharmony_ci status = AE_OK; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* _OSI is optional for now, will be permanent later */ 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (!strcmp(init_val->name, "_OSI") 9162306a36Sopenharmony_ci && !acpi_gbl_create_osi_method) { 9262306a36Sopenharmony_ci continue; 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* 9662306a36Sopenharmony_ci * Create, init, and link the new predefined name 9762306a36Sopenharmony_ci * Note: No need to use acpi_ns_lookup here because all the 9862306a36Sopenharmony_ci * predefined names are at the root level. It is much easier to 9962306a36Sopenharmony_ci * just create and link the new node(s) here. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci new_node = 10262306a36Sopenharmony_ci acpi_ns_create_node(*ACPI_CAST_PTR(u32, init_val->name)); 10362306a36Sopenharmony_ci if (!new_node) { 10462306a36Sopenharmony_ci status = AE_NO_MEMORY; 10562306a36Sopenharmony_ci goto unlock_and_exit; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci new_node->descriptor_type = ACPI_DESC_TYPE_NAMED; 10962306a36Sopenharmony_ci new_node->type = init_val->type; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (!prev_node) { 11262306a36Sopenharmony_ci acpi_gbl_root_node_struct.child = new_node; 11362306a36Sopenharmony_ci } else { 11462306a36Sopenharmony_ci prev_node->peer = new_node; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci new_node->parent = &acpi_gbl_root_node_struct; 11862306a36Sopenharmony_ci prev_node = new_node; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* 12162306a36Sopenharmony_ci * Name entered successfully. If entry in pre_defined_names[] specifies 12262306a36Sopenharmony_ci * an initial value, create the initial value. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci if (init_val->val) { 12562306a36Sopenharmony_ci status = acpi_os_predefined_override(init_val, &val); 12662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 12762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 12862306a36Sopenharmony_ci "Could not override predefined %s", 12962306a36Sopenharmony_ci init_val->name)); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (!val) { 13362306a36Sopenharmony_ci val = init_val->val; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * Entry requests an initial value, allocate a 13862306a36Sopenharmony_ci * descriptor for it. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci obj_desc = 14162306a36Sopenharmony_ci acpi_ut_create_internal_object(init_val->type); 14262306a36Sopenharmony_ci if (!obj_desc) { 14362306a36Sopenharmony_ci status = AE_NO_MEMORY; 14462306a36Sopenharmony_ci goto unlock_and_exit; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * Convert value string from table entry to 14962306a36Sopenharmony_ci * internal representation. Only types actually 15062306a36Sopenharmony_ci * used for initial values are implemented here. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci switch (init_val->type) { 15362306a36Sopenharmony_ci case ACPI_TYPE_METHOD: 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci obj_desc->method.param_count = 15662306a36Sopenharmony_ci (u8) ACPI_TO_INTEGER(val); 15762306a36Sopenharmony_ci obj_desc->common.flags |= AOPOBJ_DATA_VALID; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci#if defined (ACPI_ASL_COMPILER) 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* Save the parameter count for the iASL compiler */ 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci new_node->value = obj_desc->method.param_count; 16462306a36Sopenharmony_ci#else 16562306a36Sopenharmony_ci /* Mark this as a very SPECIAL method (_OSI) */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci obj_desc->method.info_flags = 16862306a36Sopenharmony_ci ACPI_METHOD_INTERNAL_ONLY; 16962306a36Sopenharmony_ci obj_desc->method.dispatch.implementation = 17062306a36Sopenharmony_ci acpi_ut_osi_implementation; 17162306a36Sopenharmony_ci#endif 17262306a36Sopenharmony_ci break; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci case ACPI_TYPE_INTEGER: 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci obj_desc->integer.value = ACPI_TO_INTEGER(val); 17762306a36Sopenharmony_ci break; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci case ACPI_TYPE_STRING: 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Build an object around the static string */ 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci obj_desc->string.length = (u32)strlen(val); 18462306a36Sopenharmony_ci obj_desc->string.pointer = val; 18562306a36Sopenharmony_ci obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci case ACPI_TYPE_MUTEX: 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci obj_desc->mutex.node = new_node; 19162306a36Sopenharmony_ci obj_desc->mutex.sync_level = 19262306a36Sopenharmony_ci (u8) (ACPI_TO_INTEGER(val) - 1); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* Create a mutex */ 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci status = 19762306a36Sopenharmony_ci acpi_os_create_mutex(&obj_desc->mutex. 19862306a36Sopenharmony_ci os_mutex); 19962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 20062306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 20162306a36Sopenharmony_ci goto unlock_and_exit; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Special case for ACPI Global Lock */ 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (strcmp(init_val->name, "_GL_") == 0) { 20762306a36Sopenharmony_ci acpi_gbl_global_lock_mutex = obj_desc; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* Create additional counting semaphore for global lock */ 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci status = 21262306a36Sopenharmony_ci acpi_os_create_semaphore(1, 0, 21362306a36Sopenharmony_ci &acpi_gbl_global_lock_semaphore); 21462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 21562306a36Sopenharmony_ci acpi_ut_remove_reference 21662306a36Sopenharmony_ci (obj_desc); 21762306a36Sopenharmony_ci goto unlock_and_exit; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci break; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci default: 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 22562306a36Sopenharmony_ci "Unsupported initial type value 0x%X", 22662306a36Sopenharmony_ci init_val->type)); 22762306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 22862306a36Sopenharmony_ci obj_desc = NULL; 22962306a36Sopenharmony_ci continue; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* Store pointer to value descriptor in the Node */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci status = acpi_ns_attach_object(new_node, obj_desc, 23562306a36Sopenharmony_ci obj_desc->common.type); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Remove local reference to the object */ 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ciunlock_and_exit: 24462306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* Save a handle to "_GPE", it is always present */ 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 24962306a36Sopenharmony_ci status = acpi_ns_get_node(NULL, "\\_GPE", ACPI_NS_NO_UPSEARCH, 25062306a36Sopenharmony_ci &acpi_gbl_fadt_gpe_device); 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return_ACPI_STATUS(status); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/******************************************************************************* 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * FUNCTION: acpi_ns_lookup 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * PARAMETERS: scope_info - Current scope info block 26162306a36Sopenharmony_ci * pathname - Search pathname, in internal format 26262306a36Sopenharmony_ci * (as represented in the AML stream) 26362306a36Sopenharmony_ci * type - Type associated with name 26462306a36Sopenharmony_ci * interpreter_mode - IMODE_LOAD_PASS2 => add name if not found 26562306a36Sopenharmony_ci * flags - Flags describing the search restrictions 26662306a36Sopenharmony_ci * walk_state - Current state of the walk 26762306a36Sopenharmony_ci * return_node - Where the Node is placed (if found 26862306a36Sopenharmony_ci * or created successfully) 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * RETURN: Status 27162306a36Sopenharmony_ci * 27262306a36Sopenharmony_ci * DESCRIPTION: Find or enter the passed name in the name space. 27362306a36Sopenharmony_ci * Log an error if name not found in Exec mode. 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * MUTEX: Assumes namespace is locked. 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci ******************************************************************************/ 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciacpi_status 28062306a36Sopenharmony_ciacpi_ns_lookup(union acpi_generic_state *scope_info, 28162306a36Sopenharmony_ci char *pathname, 28262306a36Sopenharmony_ci acpi_object_type type, 28362306a36Sopenharmony_ci acpi_interpreter_mode interpreter_mode, 28462306a36Sopenharmony_ci u32 flags, 28562306a36Sopenharmony_ci struct acpi_walk_state *walk_state, 28662306a36Sopenharmony_ci struct acpi_namespace_node **return_node) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci acpi_status status; 28962306a36Sopenharmony_ci char *path = pathname; 29062306a36Sopenharmony_ci char *external_path; 29162306a36Sopenharmony_ci struct acpi_namespace_node *prefix_node; 29262306a36Sopenharmony_ci struct acpi_namespace_node *current_node = NULL; 29362306a36Sopenharmony_ci struct acpi_namespace_node *this_node = NULL; 29462306a36Sopenharmony_ci u32 num_segments; 29562306a36Sopenharmony_ci u32 num_carats; 29662306a36Sopenharmony_ci acpi_name simple_name; 29762306a36Sopenharmony_ci acpi_object_type type_to_check_for; 29862306a36Sopenharmony_ci acpi_object_type this_search_type; 29962306a36Sopenharmony_ci u32 search_parent_flag = ACPI_NS_SEARCH_PARENT; 30062306a36Sopenharmony_ci u32 local_flags; 30162306a36Sopenharmony_ci acpi_interpreter_mode local_interpreter_mode; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_lookup); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (!return_node) { 30662306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci local_flags = flags & 31062306a36Sopenharmony_ci ~(ACPI_NS_ERROR_IF_FOUND | ACPI_NS_OVERRIDE_IF_FOUND | 31162306a36Sopenharmony_ci ACPI_NS_SEARCH_PARENT); 31262306a36Sopenharmony_ci *return_node = ACPI_ENTRY_NOT_FOUND; 31362306a36Sopenharmony_ci acpi_gbl_ns_lookup_count++; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (!acpi_gbl_root_node) { 31662306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_NAMESPACE); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* Get the prefix scope. A null scope means use the root scope */ 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if ((!scope_info) || (!scope_info->scope.node)) { 32262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 32362306a36Sopenharmony_ci "Null scope prefix, using root node (%p)\n", 32462306a36Sopenharmony_ci acpi_gbl_root_node)); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci prefix_node = acpi_gbl_root_node; 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci prefix_node = scope_info->scope.node; 32962306a36Sopenharmony_ci if (ACPI_GET_DESCRIPTOR_TYPE(prefix_node) != 33062306a36Sopenharmony_ci ACPI_DESC_TYPE_NAMED) { 33162306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "%p is not a namespace node [%s]", 33262306a36Sopenharmony_ci prefix_node, 33362306a36Sopenharmony_ci acpi_ut_get_descriptor_name(prefix_node))); 33462306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INTERNAL); 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (!(flags & ACPI_NS_PREFIX_IS_SCOPE)) { 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * This node might not be a actual "scope" node (such as a 34062306a36Sopenharmony_ci * Device/Method, etc.) It could be a Package or other object 34162306a36Sopenharmony_ci * node. Backup up the tree to find the containing scope node. 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_ci while (!acpi_ns_opens_scope(prefix_node->type) && 34462306a36Sopenharmony_ci prefix_node->type != ACPI_TYPE_ANY) { 34562306a36Sopenharmony_ci prefix_node = prefix_node->parent; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci /* Save type. TBD: may be no longer necessary */ 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci type_to_check_for = type; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* 35562306a36Sopenharmony_ci * Begin examination of the actual pathname 35662306a36Sopenharmony_ci */ 35762306a36Sopenharmony_ci if (!pathname) { 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* A Null name_path is allowed and refers to the root */ 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci num_segments = 0; 36262306a36Sopenharmony_ci this_node = acpi_gbl_root_node; 36362306a36Sopenharmony_ci path = ""; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 36662306a36Sopenharmony_ci "Null Pathname (Zero segments), Flags=%X\n", 36762306a36Sopenharmony_ci flags)); 36862306a36Sopenharmony_ci } else { 36962306a36Sopenharmony_ci /* 37062306a36Sopenharmony_ci * Name pointer is valid (and must be in internal name format) 37162306a36Sopenharmony_ci * 37262306a36Sopenharmony_ci * Check for scope prefixes: 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci * As represented in the AML stream, a namepath consists of an 37562306a36Sopenharmony_ci * optional scope prefix followed by a name segment part. 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * If present, the scope prefix is either a Root Prefix (in 37862306a36Sopenharmony_ci * which case the name is fully qualified), or one or more 37962306a36Sopenharmony_ci * Parent Prefixes (in which case the name's scope is relative 38062306a36Sopenharmony_ci * to the current scope). 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci if (*path == (u8) AML_ROOT_PREFIX) { 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Pathname is fully qualified, start from the root */ 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci this_node = acpi_gbl_root_node; 38762306a36Sopenharmony_ci search_parent_flag = ACPI_NS_NO_UPSEARCH; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* Point to name segment part */ 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci path++; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 39462306a36Sopenharmony_ci "Path is absolute from root [%p]\n", 39562306a36Sopenharmony_ci this_node)); 39662306a36Sopenharmony_ci } else { 39762306a36Sopenharmony_ci /* Pathname is relative to current scope, start there */ 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 40062306a36Sopenharmony_ci "Searching relative to prefix scope [%4.4s] (%p)\n", 40162306a36Sopenharmony_ci acpi_ut_get_node_name(prefix_node), 40262306a36Sopenharmony_ci prefix_node)); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* 40562306a36Sopenharmony_ci * Handle multiple Parent Prefixes (carat) by just getting 40662306a36Sopenharmony_ci * the parent node for each prefix instance. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_ci this_node = prefix_node; 40962306a36Sopenharmony_ci num_carats = 0; 41062306a36Sopenharmony_ci while (*path == (u8) AML_PARENT_PREFIX) { 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* Name is fully qualified, no search rules apply */ 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci search_parent_flag = ACPI_NS_NO_UPSEARCH; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* 41762306a36Sopenharmony_ci * Point past this prefix to the name segment 41862306a36Sopenharmony_ci * part or the next Parent Prefix 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci path++; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* Backup to the parent node */ 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci num_carats++; 42562306a36Sopenharmony_ci this_node = this_node->parent; 42662306a36Sopenharmony_ci if (!this_node) { 42762306a36Sopenharmony_ci /* 42862306a36Sopenharmony_ci * Current scope has no parent scope. Externalize 42962306a36Sopenharmony_ci * the internal path for error message. 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci status = 43262306a36Sopenharmony_ci acpi_ns_externalize_name 43362306a36Sopenharmony_ci (ACPI_UINT32_MAX, pathname, NULL, 43462306a36Sopenharmony_ci &external_path); 43562306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 43662306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 43762306a36Sopenharmony_ci "%s: Path has too many parent prefixes (^)", 43862306a36Sopenharmony_ci external_path)); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ACPI_FREE(external_path); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_FOUND); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (search_parent_flag == ACPI_NS_NO_UPSEARCH) { 44862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 44962306a36Sopenharmony_ci "Search scope is [%4.4s], path has %u carat(s)\n", 45062306a36Sopenharmony_ci acpi_ut_get_node_name 45162306a36Sopenharmony_ci (this_node), num_carats)); 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* 45662306a36Sopenharmony_ci * Determine the number of ACPI name segments in this pathname. 45762306a36Sopenharmony_ci * 45862306a36Sopenharmony_ci * The segment part consists of either: 45962306a36Sopenharmony_ci * - A Null name segment (0) 46062306a36Sopenharmony_ci * - A dual_name_prefix followed by two 4-byte name segments 46162306a36Sopenharmony_ci * - A multi_name_prefix followed by a byte indicating the 46262306a36Sopenharmony_ci * number of segments and the segments themselves. 46362306a36Sopenharmony_ci * - A single 4-byte name segment 46462306a36Sopenharmony_ci * 46562306a36Sopenharmony_ci * Examine the name prefix opcode, if any, to determine the number of 46662306a36Sopenharmony_ci * segments. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci switch (*path) { 46962306a36Sopenharmony_ci case 0: 47062306a36Sopenharmony_ci /* 47162306a36Sopenharmony_ci * Null name after a root or parent prefixes. We already 47262306a36Sopenharmony_ci * have the correct target node and there are no name segments. 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_ci num_segments = 0; 47562306a36Sopenharmony_ci type = this_node->type; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 47862306a36Sopenharmony_ci "Prefix-only Pathname (Zero name segments), Flags=%X\n", 47962306a36Sopenharmony_ci flags)); 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci case AML_DUAL_NAME_PREFIX: 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* More than one name_seg, search rules do not apply */ 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci search_parent_flag = ACPI_NS_NO_UPSEARCH; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Two segments, point to first name segment */ 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci num_segments = 2; 49162306a36Sopenharmony_ci path++; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 49462306a36Sopenharmony_ci "Dual Pathname (2 segments, Flags=%X)\n", 49562306a36Sopenharmony_ci flags)); 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci case AML_MULTI_NAME_PREFIX: 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* More than one name_seg, search rules do not apply */ 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci search_parent_flag = ACPI_NS_NO_UPSEARCH; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* Extract segment count, point to first name segment */ 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci path++; 50762306a36Sopenharmony_ci num_segments = (u32) (u8) * path; 50862306a36Sopenharmony_ci path++; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 51162306a36Sopenharmony_ci "Multi Pathname (%u Segments, Flags=%X)\n", 51262306a36Sopenharmony_ci num_segments, flags)); 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci default: 51662306a36Sopenharmony_ci /* 51762306a36Sopenharmony_ci * Not a Null name, no Dual or Multi prefix, hence there is 51862306a36Sopenharmony_ci * only one name segment and Pathname is already pointing to it. 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_ci num_segments = 1; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 52362306a36Sopenharmony_ci "Simple Pathname (1 segment, Flags=%X)\n", 52462306a36Sopenharmony_ci flags)); 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci ACPI_DEBUG_EXEC(acpi_ns_print_pathname(num_segments, path)); 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* 53262306a36Sopenharmony_ci * Search namespace for each segment of the name. Loop through and 53362306a36Sopenharmony_ci * verify (or add to the namespace) each name segment. 53462306a36Sopenharmony_ci * 53562306a36Sopenharmony_ci * The object type is significant only at the last name 53662306a36Sopenharmony_ci * segment. (We don't care about the types along the path, only 53762306a36Sopenharmony_ci * the type of the final target object.) 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_ci this_search_type = ACPI_TYPE_ANY; 54062306a36Sopenharmony_ci current_node = this_node; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci while (num_segments && current_node) { 54362306a36Sopenharmony_ci num_segments--; 54462306a36Sopenharmony_ci if (!num_segments) { 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* This is the last segment, enable typechecking */ 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci this_search_type = type; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* 55162306a36Sopenharmony_ci * Only allow automatic parent search (search rules) if the caller 55262306a36Sopenharmony_ci * requested it AND we have a single, non-fully-qualified name_seg 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_ci if ((search_parent_flag != ACPI_NS_NO_UPSEARCH) && 55562306a36Sopenharmony_ci (flags & ACPI_NS_SEARCH_PARENT)) { 55662306a36Sopenharmony_ci local_flags |= ACPI_NS_SEARCH_PARENT; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* Set error flag according to caller */ 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (flags & ACPI_NS_ERROR_IF_FOUND) { 56262306a36Sopenharmony_ci local_flags |= ACPI_NS_ERROR_IF_FOUND; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* Set override flag according to caller */ 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (flags & ACPI_NS_OVERRIDE_IF_FOUND) { 56862306a36Sopenharmony_ci local_flags |= ACPI_NS_OVERRIDE_IF_FOUND; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Handle opcodes that create a new name_seg via a full name_path */ 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci local_interpreter_mode = interpreter_mode; 57562306a36Sopenharmony_ci if ((flags & ACPI_NS_PREFIX_MUST_EXIST) && (num_segments > 0)) { 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* Every element of the path must exist (except for the final name_seg) */ 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci local_interpreter_mode = ACPI_IMODE_EXECUTE; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* Extract one ACPI name from the front of the pathname */ 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci ACPI_MOVE_32_TO_32(&simple_name, path); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* Try to find the single (4 character) ACPI name */ 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci status = 58962306a36Sopenharmony_ci acpi_ns_search_and_enter(simple_name, walk_state, 59062306a36Sopenharmony_ci current_node, 59162306a36Sopenharmony_ci local_interpreter_mode, 59262306a36Sopenharmony_ci this_search_type, local_flags, 59362306a36Sopenharmony_ci &this_node); 59462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 59562306a36Sopenharmony_ci if (status == AE_NOT_FOUND) { 59662306a36Sopenharmony_ci#if !defined ACPI_ASL_COMPILER /* Note: iASL reports this error by itself, not needed here */ 59762306a36Sopenharmony_ci if (flags & ACPI_NS_PREFIX_MUST_EXIST) { 59862306a36Sopenharmony_ci acpi_os_printf(ACPI_MSG_BIOS_ERROR 59962306a36Sopenharmony_ci "Object does not exist: %4.4s\n", 60062306a36Sopenharmony_ci (char *)&simple_name); 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci#endif 60362306a36Sopenharmony_ci /* Name not found in ACPI namespace */ 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 60662306a36Sopenharmony_ci "Name [%4.4s] not found in scope [%4.4s] %p\n", 60762306a36Sopenharmony_ci (char *)&simple_name, 60862306a36Sopenharmony_ci (char *)¤t_node->name, 60962306a36Sopenharmony_ci current_node)); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci#ifdef ACPI_EXEC_APP 61262306a36Sopenharmony_ci if ((status == AE_ALREADY_EXISTS) && 61362306a36Sopenharmony_ci (this_node->flags & ANOBJ_NODE_EARLY_INIT)) { 61462306a36Sopenharmony_ci this_node->flags &= ~ANOBJ_NODE_EARLY_INIT; 61562306a36Sopenharmony_ci status = AE_OK; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci#endif 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci#ifdef ACPI_ASL_COMPILER 62062306a36Sopenharmony_ci /* 62162306a36Sopenharmony_ci * If this ACPI name already exists within the namespace as an 62262306a36Sopenharmony_ci * external declaration, then mark the external as a conflicting 62362306a36Sopenharmony_ci * declaration and proceed to process the current node as if it did 62462306a36Sopenharmony_ci * not exist in the namespace. If this node is not processed as 62562306a36Sopenharmony_ci * normal, then it could cause improper namespace resolution 62662306a36Sopenharmony_ci * by failing to open a new scope. 62762306a36Sopenharmony_ci */ 62862306a36Sopenharmony_ci if (acpi_gbl_disasm_flag && 62962306a36Sopenharmony_ci (status == AE_ALREADY_EXISTS) && 63062306a36Sopenharmony_ci ((this_node->flags & ANOBJ_IS_EXTERNAL) || 63162306a36Sopenharmony_ci (walk_state 63262306a36Sopenharmony_ci && walk_state->opcode == AML_EXTERNAL_OP))) { 63362306a36Sopenharmony_ci this_node->flags &= ~ANOBJ_IS_EXTERNAL; 63462306a36Sopenharmony_ci this_node->type = (u8)this_search_type; 63562306a36Sopenharmony_ci if (walk_state->opcode != AML_EXTERNAL_OP) { 63662306a36Sopenharmony_ci acpi_dm_mark_external_conflict 63762306a36Sopenharmony_ci (this_node); 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci#endif 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci *return_node = this_node; 64462306a36Sopenharmony_ci return_ACPI_STATUS(status); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* More segments to follow? */ 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci if (num_segments > 0) { 65062306a36Sopenharmony_ci /* 65162306a36Sopenharmony_ci * If we have an alias to an object that opens a scope (such as a 65262306a36Sopenharmony_ci * device or processor), we need to dereference the alias here so 65362306a36Sopenharmony_ci * that we can access any children of the original node (via the 65462306a36Sopenharmony_ci * remaining segments). 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_ci if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) { 65762306a36Sopenharmony_ci if (!this_node->object) { 65862306a36Sopenharmony_ci return_ACPI_STATUS(AE_NOT_EXIST); 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (acpi_ns_opens_scope 66262306a36Sopenharmony_ci (((struct acpi_namespace_node *) 66362306a36Sopenharmony_ci this_node->object)->type)) { 66462306a36Sopenharmony_ci this_node = 66562306a36Sopenharmony_ci (struct acpi_namespace_node *) 66662306a36Sopenharmony_ci this_node->object; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* Special handling for the last segment (num_segments == 0) */ 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci else { 67462306a36Sopenharmony_ci /* 67562306a36Sopenharmony_ci * Sanity typecheck of the target object: 67662306a36Sopenharmony_ci * 67762306a36Sopenharmony_ci * If 1) This is the last segment (num_segments == 0) 67862306a36Sopenharmony_ci * 2) And we are looking for a specific type 67962306a36Sopenharmony_ci * (Not checking for TYPE_ANY) 68062306a36Sopenharmony_ci * 3) Which is not an alias 68162306a36Sopenharmony_ci * 4) Which is not a local type (TYPE_SCOPE) 68262306a36Sopenharmony_ci * 5) And the type of target object is known (not TYPE_ANY) 68362306a36Sopenharmony_ci * 6) And target object does not match what we are looking for 68462306a36Sopenharmony_ci * 68562306a36Sopenharmony_ci * Then we have a type mismatch. Just warn and ignore it. 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_ci if ((type_to_check_for != ACPI_TYPE_ANY) && 68862306a36Sopenharmony_ci (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) && 68962306a36Sopenharmony_ci (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) 69062306a36Sopenharmony_ci && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) 69162306a36Sopenharmony_ci && (this_node->type != ACPI_TYPE_ANY) 69262306a36Sopenharmony_ci && (this_node->type != type_to_check_for)) { 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* Complain about a type mismatch */ 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci ACPI_WARNING((AE_INFO, 69762306a36Sopenharmony_ci "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)", 69862306a36Sopenharmony_ci ACPI_CAST_PTR(char, &simple_name), 69962306a36Sopenharmony_ci acpi_ut_get_type_name(this_node-> 70062306a36Sopenharmony_ci type), 70162306a36Sopenharmony_ci acpi_ut_get_type_name 70262306a36Sopenharmony_ci (type_to_check_for))); 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* 70662306a36Sopenharmony_ci * If this is the last name segment and we are not looking for a 70762306a36Sopenharmony_ci * specific type, but the type of found object is known, use that 70862306a36Sopenharmony_ci * type to (later) see if it opens a scope. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (type == ACPI_TYPE_ANY) { 71162306a36Sopenharmony_ci type = this_node->type; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* Point to next name segment and make this node current */ 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci path += ACPI_NAMESEG_SIZE; 71862306a36Sopenharmony_ci current_node = this_node; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* Always check if we need to open a new scope */ 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci if (!(flags & ACPI_NS_DONT_OPEN_SCOPE) && (walk_state)) { 72462306a36Sopenharmony_ci /* 72562306a36Sopenharmony_ci * If entry is a type which opens a scope, push the new scope on the 72662306a36Sopenharmony_ci * scope stack. 72762306a36Sopenharmony_ci */ 72862306a36Sopenharmony_ci if (acpi_ns_opens_scope(type)) { 72962306a36Sopenharmony_ci status = 73062306a36Sopenharmony_ci acpi_ds_scope_stack_push(this_node, type, 73162306a36Sopenharmony_ci walk_state); 73262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 73362306a36Sopenharmony_ci return_ACPI_STATUS(status); 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci#ifdef ACPI_EXEC_APP 73862306a36Sopenharmony_ci if (flags & ACPI_NS_EARLY_INIT) { 73962306a36Sopenharmony_ci this_node->flags |= ANOBJ_NODE_EARLY_INIT; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci#endif 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci *return_node = this_node; 74462306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 74562306a36Sopenharmony_ci} 746