1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /****************************************************************************** 3 * 4 * Module Name: nsload - namespace loading/expanding/contracting procedures 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 "acdispat.h" 14 #include "actables.h" 15 #include "acinterp.h" 16 17 #define _COMPONENT ACPI_NAMESPACE 18 ACPI_MODULE_NAME("nsload") 19 20 /* Local prototypes */ 21 #ifdef ACPI_FUTURE_IMPLEMENTATION 22 acpi_status acpi_ns_unload_namespace(acpi_handle handle); 23 24 static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle); 25 #endif 26 27 /******************************************************************************* 28 * 29 * FUNCTION: acpi_ns_load_table 30 * 31 * PARAMETERS: table_index - Index for table to be loaded 32 * node - Owning NS node 33 * 34 * RETURN: Status 35 * 36 * DESCRIPTION: Load one ACPI table into the namespace 37 * 38 ******************************************************************************/ 39 40 acpi_status 41 acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) 42 { 43 acpi_status status; 44 45 ACPI_FUNCTION_TRACE(ns_load_table); 46 47 /* If table already loaded into namespace, just return */ 48 49 if (acpi_tb_is_table_loaded(table_index)) { 50 status = AE_ALREADY_EXISTS; 51 goto unlock; 52 } 53 54 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 55 "**** Loading table into namespace ****\n")); 56 57 status = acpi_tb_allocate_owner_id(table_index); 58 if (ACPI_FAILURE(status)) { 59 goto unlock; 60 } 61 62 /* 63 * Parse the table and load the namespace with all named 64 * objects found within. Control methods are NOT parsed 65 * at this time. In fact, the control methods cannot be 66 * parsed until the entire namespace is loaded, because 67 * if a control method makes a forward reference (call) 68 * to another control method, we can't continue parsing 69 * because we don't know how many arguments to parse next! 70 */ 71 status = acpi_ns_parse_table(table_index, node); 72 if (ACPI_SUCCESS(status)) { 73 acpi_tb_set_table_loaded_flag(table_index, TRUE); 74 } else { 75 /* 76 * On error, delete any namespace objects created by this table. 77 * We cannot initialize these objects, so delete them. There are 78 * a couple of especially bad cases: 79 * AE_ALREADY_EXISTS - namespace collision. 80 * AE_NOT_FOUND - the target of a Scope operator does not 81 * exist. This target of Scope must already exist in the 82 * namespace, as per the ACPI specification. 83 */ 84 acpi_ns_delete_namespace_by_owner(acpi_gbl_root_table_list. 85 tables[table_index].owner_id); 86 87 acpi_tb_release_owner_id(table_index); 88 return_ACPI_STATUS(status); 89 } 90 91 unlock: 92 if (ACPI_FAILURE(status)) { 93 return_ACPI_STATUS(status); 94 } 95 96 /* 97 * Now we can parse the control methods. We always parse 98 * them here for a sanity check, and if configured for 99 * just-in-time parsing, we delete the control method 100 * parse trees. 101 */ 102 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 103 "**** Begin Table Object Initialization\n")); 104 105 acpi_ex_enter_interpreter(); 106 status = acpi_ds_initialize_objects(table_index, node); 107 acpi_ex_exit_interpreter(); 108 109 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 110 "**** Completed Table Object Initialization\n")); 111 112 return_ACPI_STATUS(status); 113 } 114 115 #ifdef ACPI_OBSOLETE_FUNCTIONS 116 /******************************************************************************* 117 * 118 * FUNCTION: acpi_load_namespace 119 * 120 * PARAMETERS: None 121 * 122 * RETURN: Status 123 * 124 * DESCRIPTION: Load the name space from what ever is pointed to by DSDT. 125 * (DSDT points to either the BIOS or a buffer.) 126 * 127 ******************************************************************************/ 128 129 acpi_status acpi_ns_load_namespace(void) 130 { 131 acpi_status status; 132 133 ACPI_FUNCTION_TRACE(acpi_load_name_space); 134 135 /* There must be at least a DSDT installed */ 136 137 if (acpi_gbl_DSDT == NULL) { 138 ACPI_ERROR((AE_INFO, "DSDT is not in memory")); 139 return_ACPI_STATUS(AE_NO_ACPI_TABLES); 140 } 141 142 /* 143 * Load the namespace. The DSDT is required, 144 * but the SSDT and PSDT tables are optional. 145 */ 146 status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT); 147 if (ACPI_FAILURE(status)) { 148 return_ACPI_STATUS(status); 149 } 150 151 /* Ignore exceptions from these */ 152 153 (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_SSDT); 154 (void)acpi_ns_load_table_by_type(ACPI_TABLE_ID_PSDT); 155 156 ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, 157 "ACPI Namespace successfully loaded at root %p\n", 158 acpi_gbl_root_node)); 159 160 return_ACPI_STATUS(status); 161 } 162 #endif 163 164 #ifdef ACPI_FUTURE_IMPLEMENTATION 165 /******************************************************************************* 166 * 167 * FUNCTION: acpi_ns_delete_subtree 168 * 169 * PARAMETERS: start_handle - Handle in namespace where search begins 170 * 171 * RETURNS Status 172 * 173 * DESCRIPTION: Walks the namespace starting at the given handle and deletes 174 * all objects, entries, and scopes in the entire subtree. 175 * 176 * Namespace/Interpreter should be locked or the subsystem should 177 * be in shutdown before this routine is called. 178 * 179 ******************************************************************************/ 180 181 static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) 182 { 183 acpi_status status; 184 acpi_handle child_handle; 185 acpi_handle parent_handle; 186 acpi_handle next_child_handle; 187 acpi_handle dummy; 188 u32 level; 189 190 ACPI_FUNCTION_TRACE(ns_delete_subtree); 191 192 parent_handle = start_handle; 193 child_handle = NULL; 194 level = 1; 195 196 /* 197 * Traverse the tree of objects until we bubble back up 198 * to where we started. 199 */ 200 while (level > 0) { 201 202 /* Attempt to get the next object in this scope */ 203 204 status = acpi_get_next_object(ACPI_TYPE_ANY, parent_handle, 205 child_handle, &next_child_handle); 206 207 child_handle = next_child_handle; 208 209 /* Did we get a new object? */ 210 211 if (ACPI_SUCCESS(status)) { 212 213 /* Check if this object has any children */ 214 215 if (ACPI_SUCCESS 216 (acpi_get_next_object 217 (ACPI_TYPE_ANY, child_handle, NULL, &dummy))) { 218 /* 219 * There is at least one child of this object, 220 * visit the object 221 */ 222 level++; 223 parent_handle = child_handle; 224 child_handle = NULL; 225 } 226 } else { 227 /* 228 * No more children in this object, go back up to 229 * the object's parent 230 */ 231 level--; 232 233 /* Delete all children now */ 234 235 acpi_ns_delete_children(child_handle); 236 237 child_handle = parent_handle; 238 status = acpi_get_parent(parent_handle, &parent_handle); 239 if (ACPI_FAILURE(status)) { 240 return_ACPI_STATUS(status); 241 } 242 } 243 } 244 245 /* Now delete the starting object, and we are done */ 246 247 acpi_ns_remove_node(child_handle); 248 return_ACPI_STATUS(AE_OK); 249 } 250 251 /******************************************************************************* 252 * 253 * FUNCTION: acpi_ns_unload_name_space 254 * 255 * PARAMETERS: handle - Root of namespace subtree to be deleted 256 * 257 * RETURN: Status 258 * 259 * DESCRIPTION: Shrinks the namespace, typically in response to an undocking 260 * event. Deletes an entire subtree starting from (and 261 * including) the given handle. 262 * 263 ******************************************************************************/ 264 265 acpi_status acpi_ns_unload_namespace(acpi_handle handle) 266 { 267 acpi_status status; 268 269 ACPI_FUNCTION_TRACE(ns_unload_name_space); 270 271 /* Parameter validation */ 272 273 if (!acpi_gbl_root_node) { 274 return_ACPI_STATUS(AE_NO_NAMESPACE); 275 } 276 277 if (!handle) { 278 return_ACPI_STATUS(AE_BAD_PARAMETER); 279 } 280 281 /* This function does the real work */ 282 283 status = acpi_ns_delete_subtree(handle); 284 return_ACPI_STATUS(status); 285 } 286 #endif 287