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
18ACPI_MODULE_NAME("nsload")
19
20/* Local prototypes */
21#ifdef ACPI_FUTURE_IMPLEMENTATION
22acpi_status acpi_ns_unload_namespace(acpi_handle handle);
23
24static 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
40acpi_status
41acpi_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
91unlock:
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
129acpi_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
181static 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
265acpi_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