1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: excreate - Named object creation |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acinterp.h" |
13 | #include "amlcode.h" |
14 | #include "acnamesp.h" |
15 | |
16 | #define _COMPONENT ACPI_EXECUTER |
17 | ACPI_MODULE_NAME("excreate" ) |
18 | /******************************************************************************* |
19 | * |
20 | * FUNCTION: acpi_ex_create_alias |
21 | * |
22 | * PARAMETERS: walk_state - Current state, contains operands |
23 | * |
24 | * RETURN: Status |
25 | * |
26 | * DESCRIPTION: Create a new named alias |
27 | * |
28 | ******************************************************************************/ |
29 | acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) |
30 | { |
31 | struct acpi_namespace_node *target_node; |
32 | struct acpi_namespace_node *alias_node; |
33 | acpi_status status = AE_OK; |
34 | |
35 | ACPI_FUNCTION_TRACE(ex_create_alias); |
36 | |
37 | /* Get the source/alias operands (both namespace nodes) */ |
38 | |
39 | alias_node = (struct acpi_namespace_node *)walk_state->operands[0]; |
40 | target_node = (struct acpi_namespace_node *)walk_state->operands[1]; |
41 | |
42 | if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) || |
43 | (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { |
44 | /* |
45 | * Dereference an existing alias so that we don't create a chain |
46 | * of aliases. With this code, we guarantee that an alias is |
47 | * always exactly one level of indirection away from the |
48 | * actual aliased name. |
49 | */ |
50 | target_node = |
51 | ACPI_CAST_PTR(struct acpi_namespace_node, |
52 | target_node->object); |
53 | } |
54 | |
55 | /* Ensure that the target node is valid */ |
56 | |
57 | if (!target_node) { |
58 | return_ACPI_STATUS(AE_NULL_OBJECT); |
59 | } |
60 | |
61 | /* Construct the alias object (a namespace node) */ |
62 | |
63 | switch (target_node->type) { |
64 | case ACPI_TYPE_METHOD: |
65 | /* |
66 | * Control method aliases need to be differentiated with |
67 | * a special type |
68 | */ |
69 | alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS; |
70 | break; |
71 | |
72 | default: |
73 | /* |
74 | * All other object types. |
75 | * |
76 | * The new alias has the type ALIAS and points to the original |
77 | * NS node, not the object itself. |
78 | */ |
79 | alias_node->type = ACPI_TYPE_LOCAL_ALIAS; |
80 | alias_node->object = |
81 | ACPI_CAST_PTR(union acpi_operand_object, target_node); |
82 | break; |
83 | } |
84 | |
85 | /* Since both operands are Nodes, we don't need to delete them */ |
86 | |
87 | alias_node->object = |
88 | ACPI_CAST_PTR(union acpi_operand_object, target_node); |
89 | return_ACPI_STATUS(status); |
90 | } |
91 | |
92 | /******************************************************************************* |
93 | * |
94 | * FUNCTION: acpi_ex_create_event |
95 | * |
96 | * PARAMETERS: walk_state - Current state |
97 | * |
98 | * RETURN: Status |
99 | * |
100 | * DESCRIPTION: Create a new event object |
101 | * |
102 | ******************************************************************************/ |
103 | |
104 | acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state) |
105 | { |
106 | acpi_status status; |
107 | union acpi_operand_object *obj_desc; |
108 | |
109 | ACPI_FUNCTION_TRACE(ex_create_event); |
110 | |
111 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_EVENT); |
112 | if (!obj_desc) { |
113 | status = AE_NO_MEMORY; |
114 | goto cleanup; |
115 | } |
116 | |
117 | /* |
118 | * Create the actual OS semaphore, with zero initial units -- meaning |
119 | * that the event is created in an unsignalled state |
120 | */ |
121 | status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, initial_units: 0, |
122 | out_handle: &obj_desc->event.os_semaphore); |
123 | if (ACPI_FAILURE(status)) { |
124 | goto cleanup; |
125 | } |
126 | |
127 | /* Attach object to the Node */ |
128 | |
129 | status = acpi_ns_attach_object(node: (struct acpi_namespace_node *) |
130 | walk_state->operands[0], object: obj_desc, |
131 | ACPI_TYPE_EVENT); |
132 | |
133 | cleanup: |
134 | /* |
135 | * Remove local reference to the object (on error, will cause deletion |
136 | * of both object and semaphore if present.) |
137 | */ |
138 | acpi_ut_remove_reference(object: obj_desc); |
139 | return_ACPI_STATUS(status); |
140 | } |
141 | |
142 | /******************************************************************************* |
143 | * |
144 | * FUNCTION: acpi_ex_create_mutex |
145 | * |
146 | * PARAMETERS: walk_state - Current state |
147 | * |
148 | * RETURN: Status |
149 | * |
150 | * DESCRIPTION: Create a new mutex object |
151 | * |
152 | * Mutex (Name[0], sync_level[1]) |
153 | * |
154 | ******************************************************************************/ |
155 | |
156 | acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) |
157 | { |
158 | acpi_status status = AE_OK; |
159 | union acpi_operand_object *obj_desc; |
160 | |
161 | ACPI_FUNCTION_TRACE_PTR(ex_create_mutex, ACPI_WALK_OPERANDS); |
162 | |
163 | /* Create the new mutex object */ |
164 | |
165 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX); |
166 | if (!obj_desc) { |
167 | status = AE_NO_MEMORY; |
168 | goto cleanup; |
169 | } |
170 | |
171 | /* Create the actual OS Mutex */ |
172 | |
173 | status = acpi_os_create_mutex(&obj_desc->mutex.os_mutex); |
174 | if (ACPI_FAILURE(status)) { |
175 | goto cleanup; |
176 | } |
177 | |
178 | /* Init object and attach to NS node */ |
179 | |
180 | obj_desc->mutex.sync_level = (u8)walk_state->operands[1]->integer.value; |
181 | obj_desc->mutex.node = |
182 | (struct acpi_namespace_node *)walk_state->operands[0]; |
183 | |
184 | status = |
185 | acpi_ns_attach_object(node: obj_desc->mutex.node, object: obj_desc, |
186 | ACPI_TYPE_MUTEX); |
187 | |
188 | cleanup: |
189 | /* |
190 | * Remove local reference to the object (on error, will cause deletion |
191 | * of both object and semaphore if present.) |
192 | */ |
193 | acpi_ut_remove_reference(object: obj_desc); |
194 | return_ACPI_STATUS(status); |
195 | } |
196 | |
197 | /******************************************************************************* |
198 | * |
199 | * FUNCTION: acpi_ex_create_region |
200 | * |
201 | * PARAMETERS: aml_start - Pointer to the region declaration AML |
202 | * aml_length - Max length of the declaration AML |
203 | * space_id - Address space ID for the region |
204 | * walk_state - Current state |
205 | * |
206 | * RETURN: Status |
207 | * |
208 | * DESCRIPTION: Create a new operation region object |
209 | * |
210 | ******************************************************************************/ |
211 | |
212 | acpi_status |
213 | acpi_ex_create_region(u8 * aml_start, |
214 | u32 aml_length, |
215 | u8 space_id, struct acpi_walk_state *walk_state) |
216 | { |
217 | acpi_status status; |
218 | union acpi_operand_object *obj_desc; |
219 | struct acpi_namespace_node *node; |
220 | union acpi_operand_object *region_obj2; |
221 | |
222 | ACPI_FUNCTION_TRACE(ex_create_region); |
223 | |
224 | /* Get the Namespace Node */ |
225 | |
226 | node = walk_state->op->common.node; |
227 | |
228 | /* |
229 | * If the region object is already attached to this node, |
230 | * just return |
231 | */ |
232 | if (acpi_ns_get_attached_object(node)) { |
233 | return_ACPI_STATUS(AE_OK); |
234 | } |
235 | |
236 | /* |
237 | * Space ID must be one of the predefined IDs, or in the user-defined |
238 | * range |
239 | */ |
240 | if (!acpi_is_valid_space_id(space_id)) { |
241 | /* |
242 | * Print an error message, but continue. We don't want to abort |
243 | * a table load for this exception. Instead, if the region is |
244 | * actually used at runtime, abort the executing method. |
245 | */ |
246 | ACPI_ERROR((AE_INFO, |
247 | "Invalid/unknown Address Space ID: 0x%2.2X" , |
248 | space_id)); |
249 | } |
250 | |
251 | ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Region Type - %s (0x%X)\n" , |
252 | acpi_ut_get_region_name(space_id), space_id)); |
253 | |
254 | /* Create the region descriptor */ |
255 | |
256 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION); |
257 | if (!obj_desc) { |
258 | status = AE_NO_MEMORY; |
259 | goto cleanup; |
260 | } |
261 | |
262 | /* |
263 | * Remember location in AML stream of address & length |
264 | * operands since they need to be evaluated at run time. |
265 | */ |
266 | region_obj2 = acpi_ns_get_secondary_object(obj_desc); |
267 | region_obj2->extra.aml_start = aml_start; |
268 | region_obj2->extra.aml_length = aml_length; |
269 | region_obj2->extra.method_REG = NULL; |
270 | if (walk_state->scope_info) { |
271 | region_obj2->extra.scope_node = |
272 | walk_state->scope_info->scope.node; |
273 | } else { |
274 | region_obj2->extra.scope_node = node; |
275 | } |
276 | |
277 | /* Init the region from the operands */ |
278 | |
279 | obj_desc->region.space_id = space_id; |
280 | obj_desc->region.address = 0; |
281 | obj_desc->region.length = 0; |
282 | obj_desc->region.pointer = NULL; |
283 | obj_desc->region.node = node; |
284 | obj_desc->region.handler = NULL; |
285 | obj_desc->common.flags &= |
286 | ~(AOPOBJ_SETUP_COMPLETE | AOPOBJ_REG_CONNECTED | |
287 | AOPOBJ_OBJECT_INITIALIZED); |
288 | |
289 | /* Install the new region object in the parent Node */ |
290 | |
291 | status = acpi_ns_attach_object(node, object: obj_desc, ACPI_TYPE_REGION); |
292 | |
293 | cleanup: |
294 | |
295 | /* Remove local reference to the object */ |
296 | |
297 | acpi_ut_remove_reference(object: obj_desc); |
298 | return_ACPI_STATUS(status); |
299 | } |
300 | |
301 | /******************************************************************************* |
302 | * |
303 | * FUNCTION: acpi_ex_create_processor |
304 | * |
305 | * PARAMETERS: walk_state - Current state |
306 | * |
307 | * RETURN: Status |
308 | * |
309 | * DESCRIPTION: Create a new processor object and populate the fields |
310 | * |
311 | * Processor (Name[0], cpu_ID[1], pblock_addr[2], pblock_length[3]) |
312 | * |
313 | ******************************************************************************/ |
314 | |
315 | acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state) |
316 | { |
317 | union acpi_operand_object **operand = &walk_state->operands[0]; |
318 | union acpi_operand_object *obj_desc; |
319 | acpi_status status; |
320 | |
321 | ACPI_FUNCTION_TRACE_PTR(ex_create_processor, walk_state); |
322 | |
323 | /* Create the processor object */ |
324 | |
325 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PROCESSOR); |
326 | if (!obj_desc) { |
327 | return_ACPI_STATUS(AE_NO_MEMORY); |
328 | } |
329 | |
330 | /* Initialize the processor object from the operands */ |
331 | |
332 | obj_desc->processor.proc_id = (u8) operand[1]->integer.value; |
333 | obj_desc->processor.length = (u8) operand[3]->integer.value; |
334 | obj_desc->processor.address = |
335 | (acpi_io_address)operand[2]->integer.value; |
336 | |
337 | /* Install the processor object in the parent Node */ |
338 | |
339 | status = acpi_ns_attach_object(node: (struct acpi_namespace_node *)operand[0], |
340 | object: obj_desc, ACPI_TYPE_PROCESSOR); |
341 | |
342 | /* Remove local reference to the object */ |
343 | |
344 | acpi_ut_remove_reference(object: obj_desc); |
345 | return_ACPI_STATUS(status); |
346 | } |
347 | |
348 | /******************************************************************************* |
349 | * |
350 | * FUNCTION: acpi_ex_create_power_resource |
351 | * |
352 | * PARAMETERS: walk_state - Current state |
353 | * |
354 | * RETURN: Status |
355 | * |
356 | * DESCRIPTION: Create a new power_resource object and populate the fields |
357 | * |
358 | * power_resource (Name[0], system_level[1], resource_order[2]) |
359 | * |
360 | ******************************************************************************/ |
361 | |
362 | acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state) |
363 | { |
364 | union acpi_operand_object **operand = &walk_state->operands[0]; |
365 | acpi_status status; |
366 | union acpi_operand_object *obj_desc; |
367 | |
368 | ACPI_FUNCTION_TRACE_PTR(ex_create_power_resource, walk_state); |
369 | |
370 | /* Create the power resource object */ |
371 | |
372 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_POWER); |
373 | if (!obj_desc) { |
374 | return_ACPI_STATUS(AE_NO_MEMORY); |
375 | } |
376 | |
377 | /* Initialize the power object from the operands */ |
378 | |
379 | obj_desc->power_resource.system_level = (u8) operand[1]->integer.value; |
380 | obj_desc->power_resource.resource_order = |
381 | (u16) operand[2]->integer.value; |
382 | |
383 | /* Install the power resource object in the parent Node */ |
384 | |
385 | status = acpi_ns_attach_object(node: (struct acpi_namespace_node *)operand[0], |
386 | object: obj_desc, ACPI_TYPE_POWER); |
387 | |
388 | /* Remove local reference to the object */ |
389 | |
390 | acpi_ut_remove_reference(object: obj_desc); |
391 | return_ACPI_STATUS(status); |
392 | } |
393 | |
394 | /******************************************************************************* |
395 | * |
396 | * FUNCTION: acpi_ex_create_method |
397 | * |
398 | * PARAMETERS: aml_start - First byte of the method's AML |
399 | * aml_length - AML byte count for this method |
400 | * walk_state - Current state |
401 | * |
402 | * RETURN: Status |
403 | * |
404 | * DESCRIPTION: Create a new method object |
405 | * |
406 | ******************************************************************************/ |
407 | |
408 | acpi_status |
409 | acpi_ex_create_method(u8 * aml_start, |
410 | u32 aml_length, struct acpi_walk_state *walk_state) |
411 | { |
412 | union acpi_operand_object **operand = &walk_state->operands[0]; |
413 | union acpi_operand_object *obj_desc; |
414 | acpi_status status; |
415 | u8 method_flags; |
416 | |
417 | ACPI_FUNCTION_TRACE_PTR(ex_create_method, walk_state); |
418 | |
419 | /* Create a new method object */ |
420 | |
421 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); |
422 | if (!obj_desc) { |
423 | status = AE_NO_MEMORY; |
424 | goto exit; |
425 | } |
426 | |
427 | /* Save the method's AML pointer and length */ |
428 | |
429 | obj_desc->method.aml_start = aml_start; |
430 | obj_desc->method.aml_length = aml_length; |
431 | obj_desc->method.node = operand[0]; |
432 | |
433 | /* |
434 | * Disassemble the method flags. Split off the arg_count, Serialized |
435 | * flag, and sync_level for efficiency. |
436 | */ |
437 | method_flags = (u8)operand[1]->integer.value; |
438 | obj_desc->method.param_count = (u8) |
439 | (method_flags & AML_METHOD_ARG_COUNT); |
440 | |
441 | /* |
442 | * Get the sync_level. If method is serialized, a mutex will be |
443 | * created for this method when it is parsed. |
444 | */ |
445 | if (method_flags & AML_METHOD_SERIALIZED) { |
446 | obj_desc->method.info_flags = ACPI_METHOD_SERIALIZED; |
447 | |
448 | /* |
449 | * ACPI 1.0: sync_level = 0 |
450 | * ACPI 2.0: sync_level = sync_level in method declaration |
451 | */ |
452 | obj_desc->method.sync_level = (u8) |
453 | ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); |
454 | } |
455 | |
456 | /* Attach the new object to the method Node */ |
457 | |
458 | status = acpi_ns_attach_object(node: (struct acpi_namespace_node *)operand[0], |
459 | object: obj_desc, ACPI_TYPE_METHOD); |
460 | |
461 | /* Remove local reference to the object */ |
462 | |
463 | acpi_ut_remove_reference(object: obj_desc); |
464 | |
465 | exit: |
466 | /* Remove a reference to the operand */ |
467 | |
468 | acpi_ut_remove_reference(object: operand[1]); |
469 | return_ACPI_STATUS(status); |
470 | } |
471 | |