Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
6595 | serge | 1 | /****************************************************************************** |
2 | * |
||
3 | * Module Name: excreate - Named object creation |
||
4 | * |
||
5 | *****************************************************************************/ |
||
6 | |||
7 | /* |
||
8 | * Copyright (C) 2000 - 2015, Intel Corp. |
||
9 | * All rights reserved. |
||
10 | * |
||
11 | * Redistribution and use in source and binary forms, with or without |
||
12 | * modification, are permitted provided that the following conditions |
||
13 | * are met: |
||
14 | * 1. Redistributions of source code must retain the above copyright |
||
15 | * notice, this list of conditions, and the following disclaimer, |
||
16 | * without modification. |
||
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
||
18 | * substantially similar to the "NO WARRANTY" disclaimer below |
||
19 | * ("Disclaimer") and any redistribution must be conditioned upon |
||
20 | * including a substantially similar Disclaimer requirement for further |
||
21 | * binary redistribution. |
||
22 | * 3. Neither the names of the above-listed copyright holders nor the names |
||
23 | * of any contributors may be used to endorse or promote products derived |
||
24 | * from this software without specific prior written permission. |
||
25 | * |
||
26 | * Alternatively, this software may be distributed under the terms of the |
||
27 | * GNU General Public License ("GPL") version 2 as published by the Free |
||
28 | * Software Foundation. |
||
29 | * |
||
30 | * NO WARRANTY |
||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
||
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
41 | * POSSIBILITY OF SUCH DAMAGES. |
||
42 | */ |
||
43 | |||
44 | #include |
||
45 | #include "accommon.h" |
||
46 | #include "acinterp.h" |
||
47 | #include "amlcode.h" |
||
48 | #include "acnamesp.h" |
||
49 | |||
50 | #define _COMPONENT ACPI_EXECUTER |
||
51 | ACPI_MODULE_NAME("excreate") |
||
52 | #ifndef ACPI_NO_METHOD_EXECUTION |
||
53 | /******************************************************************************* |
||
54 | * |
||
55 | * FUNCTION: acpi_ex_create_alias |
||
56 | * |
||
57 | * PARAMETERS: walk_state - Current state, contains operands |
||
58 | * |
||
59 | * RETURN: Status |
||
60 | * |
||
61 | * DESCRIPTION: Create a new named alias |
||
62 | * |
||
63 | ******************************************************************************/ |
||
64 | acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) |
||
65 | { |
||
66 | struct acpi_namespace_node *target_node; |
||
67 | struct acpi_namespace_node *alias_node; |
||
68 | acpi_status status = AE_OK; |
||
69 | |||
70 | ACPI_FUNCTION_TRACE(ex_create_alias); |
||
71 | |||
72 | /* Get the source/alias operands (both namespace nodes) */ |
||
73 | |||
74 | alias_node = (struct acpi_namespace_node *)walk_state->operands[0]; |
||
75 | target_node = (struct acpi_namespace_node *)walk_state->operands[1]; |
||
76 | |||
77 | if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) || |
||
78 | (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { |
||
79 | /* |
||
80 | * Dereference an existing alias so that we don't create a chain |
||
81 | * of aliases. With this code, we guarantee that an alias is |
||
82 | * always exactly one level of indirection away from the |
||
83 | * actual aliased name. |
||
84 | */ |
||
85 | target_node = |
||
86 | ACPI_CAST_PTR(struct acpi_namespace_node, |
||
87 | target_node->object); |
||
88 | } |
||
89 | |||
90 | /* |
||
91 | * For objects that can never change (i.e., the NS node will |
||
92 | * permanently point to the same object), we can simply attach |
||
93 | * the object to the new NS node. For other objects (such as |
||
94 | * Integers, buffers, etc.), we have to point the Alias node |
||
95 | * to the original Node. |
||
96 | */ |
||
97 | switch (target_node->type) { |
||
98 | |||
99 | /* For these types, the sub-object can change dynamically via a Store */ |
||
100 | |||
101 | case ACPI_TYPE_INTEGER: |
||
102 | case ACPI_TYPE_STRING: |
||
103 | case ACPI_TYPE_BUFFER: |
||
104 | case ACPI_TYPE_PACKAGE: |
||
105 | case ACPI_TYPE_BUFFER_FIELD: |
||
106 | /* |
||
107 | * These types open a new scope, so we need the NS node in order to access |
||
108 | * any children. |
||
109 | */ |
||
110 | case ACPI_TYPE_DEVICE: |
||
111 | case ACPI_TYPE_POWER: |
||
112 | case ACPI_TYPE_PROCESSOR: |
||
113 | case ACPI_TYPE_THERMAL: |
||
114 | case ACPI_TYPE_LOCAL_SCOPE: |
||
115 | /* |
||
116 | * The new alias has the type ALIAS and points to the original |
||
117 | * NS node, not the object itself. |
||
118 | */ |
||
119 | alias_node->type = ACPI_TYPE_LOCAL_ALIAS; |
||
120 | alias_node->object = |
||
121 | ACPI_CAST_PTR(union acpi_operand_object, target_node); |
||
122 | break; |
||
123 | |||
124 | case ACPI_TYPE_METHOD: |
||
125 | /* |
||
126 | * Control method aliases need to be differentiated |
||
127 | */ |
||
128 | alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS; |
||
129 | alias_node->object = |
||
130 | ACPI_CAST_PTR(union acpi_operand_object, target_node); |
||
131 | break; |
||
132 | |||
133 | default: |
||
134 | |||
135 | /* Attach the original source object to the new Alias Node */ |
||
136 | |||
137 | /* |
||
138 | * The new alias assumes the type of the target, and it points |
||
139 | * to the same object. The reference count of the object has an |
||
140 | * additional reference to prevent deletion out from under either the |
||
141 | * target node or the alias Node |
||
142 | */ |
||
143 | status = acpi_ns_attach_object(alias_node, |
||
144 | acpi_ns_get_attached_object |
||
145 | (target_node), |
||
146 | target_node->type); |
||
147 | break; |
||
148 | } |
||
149 | |||
150 | /* Since both operands are Nodes, we don't need to delete them */ |
||
151 | |||
152 | return_ACPI_STATUS(status); |
||
153 | } |
||
154 | |||
155 | /******************************************************************************* |
||
156 | * |
||
157 | * FUNCTION: acpi_ex_create_event |
||
158 | * |
||
159 | * PARAMETERS: walk_state - Current state |
||
160 | * |
||
161 | * RETURN: Status |
||
162 | * |
||
163 | * DESCRIPTION: Create a new event object |
||
164 | * |
||
165 | ******************************************************************************/ |
||
166 | |||
167 | acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state) |
||
168 | { |
||
169 | acpi_status status; |
||
170 | union acpi_operand_object *obj_desc; |
||
171 | |||
172 | ACPI_FUNCTION_TRACE(ex_create_event); |
||
173 | |||
174 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_EVENT); |
||
175 | if (!obj_desc) { |
||
176 | status = AE_NO_MEMORY; |
||
177 | goto cleanup; |
||
178 | } |
||
179 | |||
180 | /* |
||
181 | * Create the actual OS semaphore, with zero initial units -- meaning |
||
182 | * that the event is created in an unsignalled state |
||
183 | */ |
||
184 | status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, |
||
185 | &obj_desc->event.os_semaphore); |
||
186 | if (ACPI_FAILURE(status)) { |
||
187 | goto cleanup; |
||
188 | } |
||
189 | |||
190 | /* Attach object to the Node */ |
||
191 | |||
192 | status = |
||
193 | acpi_ns_attach_object((struct acpi_namespace_node *)walk_state-> |
||
194 | operands[0], obj_desc, ACPI_TYPE_EVENT); |
||
195 | |||
196 | cleanup: |
||
197 | /* |
||
198 | * Remove local reference to the object (on error, will cause deletion |
||
199 | * of both object and semaphore if present.) |
||
200 | */ |
||
201 | acpi_ut_remove_reference(obj_desc); |
||
202 | return_ACPI_STATUS(status); |
||
203 | } |
||
204 | |||
205 | /******************************************************************************* |
||
206 | * |
||
207 | * FUNCTION: acpi_ex_create_mutex |
||
208 | * |
||
209 | * PARAMETERS: walk_state - Current state |
||
210 | * |
||
211 | * RETURN: Status |
||
212 | * |
||
213 | * DESCRIPTION: Create a new mutex object |
||
214 | * |
||
215 | * Mutex (Name[0], sync_level[1]) |
||
216 | * |
||
217 | ******************************************************************************/ |
||
218 | |||
219 | acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) |
||
220 | { |
||
221 | acpi_status status = AE_OK; |
||
222 | union acpi_operand_object *obj_desc; |
||
223 | |||
224 | ACPI_FUNCTION_TRACE_PTR(ex_create_mutex, ACPI_WALK_OPERANDS); |
||
225 | |||
226 | /* Create the new mutex object */ |
||
227 | |||
228 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX); |
||
229 | if (!obj_desc) { |
||
230 | status = AE_NO_MEMORY; |
||
231 | goto cleanup; |
||
232 | } |
||
233 | |||
234 | /* Create the actual OS Mutex */ |
||
235 | |||
236 | status = acpi_os_create_mutex(&obj_desc->mutex.os_mutex); |
||
237 | if (ACPI_FAILURE(status)) { |
||
238 | goto cleanup; |
||
239 | } |
||
240 | |||
241 | /* Init object and attach to NS node */ |
||
242 | |||
243 | obj_desc->mutex.sync_level = (u8)walk_state->operands[1]->integer.value; |
||
244 | obj_desc->mutex.node = |
||
245 | (struct acpi_namespace_node *)walk_state->operands[0]; |
||
246 | |||
247 | status = |
||
248 | acpi_ns_attach_object(obj_desc->mutex.node, obj_desc, |
||
249 | ACPI_TYPE_MUTEX); |
||
250 | |||
251 | cleanup: |
||
252 | /* |
||
253 | * Remove local reference to the object (on error, will cause deletion |
||
254 | * of both object and semaphore if present.) |
||
255 | */ |
||
256 | acpi_ut_remove_reference(obj_desc); |
||
257 | return_ACPI_STATUS(status); |
||
258 | } |
||
259 | |||
260 | /******************************************************************************* |
||
261 | * |
||
262 | * FUNCTION: acpi_ex_create_region |
||
263 | * |
||
264 | * PARAMETERS: aml_start - Pointer to the region declaration AML |
||
265 | * aml_length - Max length of the declaration AML |
||
266 | * space_id - Address space ID for the region |
||
267 | * walk_state - Current state |
||
268 | * |
||
269 | * RETURN: Status |
||
270 | * |
||
271 | * DESCRIPTION: Create a new operation region object |
||
272 | * |
||
273 | ******************************************************************************/ |
||
274 | |||
275 | acpi_status |
||
276 | acpi_ex_create_region(u8 * aml_start, |
||
277 | u32 aml_length, |
||
278 | u8 space_id, struct acpi_walk_state *walk_state) |
||
279 | { |
||
280 | acpi_status status; |
||
281 | union acpi_operand_object *obj_desc; |
||
282 | struct acpi_namespace_node *node; |
||
283 | union acpi_operand_object *region_obj2; |
||
284 | |||
285 | ACPI_FUNCTION_TRACE(ex_create_region); |
||
286 | |||
287 | /* Get the Namespace Node */ |
||
288 | |||
289 | node = walk_state->op->common.node; |
||
290 | |||
291 | /* |
||
292 | * If the region object is already attached to this node, |
||
293 | * just return |
||
294 | */ |
||
295 | if (acpi_ns_get_attached_object(node)) { |
||
296 | return_ACPI_STATUS(AE_OK); |
||
297 | } |
||
298 | |||
299 | /* |
||
300 | * Space ID must be one of the predefined IDs, or in the user-defined |
||
301 | * range |
||
302 | */ |
||
303 | if (!acpi_is_valid_space_id(space_id)) { |
||
304 | /* |
||
305 | * Print an error message, but continue. We don't want to abort |
||
306 | * a table load for this exception. Instead, if the region is |
||
307 | * actually used at runtime, abort the executing method. |
||
308 | */ |
||
309 | ACPI_ERROR((AE_INFO, |
||
310 | "Invalid/unknown Address Space ID: 0x%2.2X", |
||
311 | space_id)); |
||
312 | } |
||
313 | |||
314 | ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Region Type - %s (0x%X)\n", |
||
315 | acpi_ut_get_region_name(space_id), space_id)); |
||
316 | |||
317 | /* Create the region descriptor */ |
||
318 | |||
319 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION); |
||
320 | if (!obj_desc) { |
||
321 | status = AE_NO_MEMORY; |
||
322 | goto cleanup; |
||
323 | } |
||
324 | |||
325 | /* |
||
326 | * Remember location in AML stream of address & length |
||
327 | * operands since they need to be evaluated at run time. |
||
328 | */ |
||
329 | region_obj2 = obj_desc->common.next_object; |
||
330 | region_obj2->extra.aml_start = aml_start; |
||
331 | region_obj2->extra.aml_length = aml_length; |
||
332 | if (walk_state->scope_info) { |
||
333 | region_obj2->extra.scope_node = |
||
334 | walk_state->scope_info->scope.node; |
||
335 | } else { |
||
336 | region_obj2->extra.scope_node = node; |
||
337 | } |
||
338 | |||
339 | /* Init the region from the operands */ |
||
340 | |||
341 | obj_desc->region.space_id = space_id; |
||
342 | obj_desc->region.address = 0; |
||
343 | obj_desc->region.length = 0; |
||
344 | obj_desc->region.node = node; |
||
345 | |||
346 | /* Install the new region object in the parent Node */ |
||
347 | |||
348 | status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_REGION); |
||
349 | |||
350 | cleanup: |
||
351 | |||
352 | /* Remove local reference to the object */ |
||
353 | |||
354 | acpi_ut_remove_reference(obj_desc); |
||
355 | return_ACPI_STATUS(status); |
||
356 | } |
||
357 | |||
358 | /******************************************************************************* |
||
359 | * |
||
360 | * FUNCTION: acpi_ex_create_processor |
||
361 | * |
||
362 | * PARAMETERS: walk_state - Current state |
||
363 | * |
||
364 | * RETURN: Status |
||
365 | * |
||
366 | * DESCRIPTION: Create a new processor object and populate the fields |
||
367 | * |
||
368 | * Processor (Name[0], cpu_ID[1], pblock_addr[2], pblock_length[3]) |
||
369 | * |
||
370 | ******************************************************************************/ |
||
371 | |||
372 | acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state) |
||
373 | { |
||
374 | union acpi_operand_object **operand = &walk_state->operands[0]; |
||
375 | union acpi_operand_object *obj_desc; |
||
376 | acpi_status status; |
||
377 | |||
378 | ACPI_FUNCTION_TRACE_PTR(ex_create_processor, walk_state); |
||
379 | |||
380 | /* Create the processor object */ |
||
381 | |||
382 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PROCESSOR); |
||
383 | if (!obj_desc) { |
||
384 | return_ACPI_STATUS(AE_NO_MEMORY); |
||
385 | } |
||
386 | |||
387 | /* Initialize the processor object from the operands */ |
||
388 | |||
389 | obj_desc->processor.proc_id = (u8) operand[1]->integer.value; |
||
390 | obj_desc->processor.length = (u8) operand[3]->integer.value; |
||
391 | obj_desc->processor.address = |
||
392 | (acpi_io_address) operand[2]->integer.value; |
||
393 | |||
394 | /* Install the processor object in the parent Node */ |
||
395 | |||
396 | status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0], |
||
397 | obj_desc, ACPI_TYPE_PROCESSOR); |
||
398 | |||
399 | /* Remove local reference to the object */ |
||
400 | |||
401 | acpi_ut_remove_reference(obj_desc); |
||
402 | return_ACPI_STATUS(status); |
||
403 | } |
||
404 | |||
405 | /******************************************************************************* |
||
406 | * |
||
407 | * FUNCTION: acpi_ex_create_power_resource |
||
408 | * |
||
409 | * PARAMETERS: walk_state - Current state |
||
410 | * |
||
411 | * RETURN: Status |
||
412 | * |
||
413 | * DESCRIPTION: Create a new power_resource object and populate the fields |
||
414 | * |
||
415 | * power_resource (Name[0], system_level[1], resource_order[2]) |
||
416 | * |
||
417 | ******************************************************************************/ |
||
418 | |||
419 | acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state) |
||
420 | { |
||
421 | union acpi_operand_object **operand = &walk_state->operands[0]; |
||
422 | acpi_status status; |
||
423 | union acpi_operand_object *obj_desc; |
||
424 | |||
425 | ACPI_FUNCTION_TRACE_PTR(ex_create_power_resource, walk_state); |
||
426 | |||
427 | /* Create the power resource object */ |
||
428 | |||
429 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_POWER); |
||
430 | if (!obj_desc) { |
||
431 | return_ACPI_STATUS(AE_NO_MEMORY); |
||
432 | } |
||
433 | |||
434 | /* Initialize the power object from the operands */ |
||
435 | |||
436 | obj_desc->power_resource.system_level = (u8) operand[1]->integer.value; |
||
437 | obj_desc->power_resource.resource_order = |
||
438 | (u16) operand[2]->integer.value; |
||
439 | |||
440 | /* Install the power resource object in the parent Node */ |
||
441 | |||
442 | status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0], |
||
443 | obj_desc, ACPI_TYPE_POWER); |
||
444 | |||
445 | /* Remove local reference to the object */ |
||
446 | |||
447 | acpi_ut_remove_reference(obj_desc); |
||
448 | return_ACPI_STATUS(status); |
||
449 | } |
||
450 | #endif |
||
451 | |||
452 | /******************************************************************************* |
||
453 | * |
||
454 | * FUNCTION: acpi_ex_create_method |
||
455 | * |
||
456 | * PARAMETERS: aml_start - First byte of the method's AML |
||
457 | * aml_length - AML byte count for this method |
||
458 | * walk_state - Current state |
||
459 | * |
||
460 | * RETURN: Status |
||
461 | * |
||
462 | * DESCRIPTION: Create a new method object |
||
463 | * |
||
464 | ******************************************************************************/ |
||
465 | |||
466 | acpi_status |
||
467 | acpi_ex_create_method(u8 * aml_start, |
||
468 | u32 aml_length, struct acpi_walk_state *walk_state) |
||
469 | { |
||
470 | union acpi_operand_object **operand = &walk_state->operands[0]; |
||
471 | union acpi_operand_object *obj_desc; |
||
472 | acpi_status status; |
||
473 | u8 method_flags; |
||
474 | |||
475 | ACPI_FUNCTION_TRACE_PTR(ex_create_method, walk_state); |
||
476 | |||
477 | /* Create a new method object */ |
||
478 | |||
479 | obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); |
||
480 | if (!obj_desc) { |
||
481 | status = AE_NO_MEMORY; |
||
482 | goto exit; |
||
483 | } |
||
484 | |||
485 | /* Save the method's AML pointer and length */ |
||
486 | |||
487 | obj_desc->method.aml_start = aml_start; |
||
488 | obj_desc->method.aml_length = aml_length; |
||
489 | obj_desc->method.node = operand[0]; |
||
490 | |||
491 | /* |
||
492 | * Disassemble the method flags. Split off the arg_count, Serialized |
||
493 | * flag, and sync_level for efficiency. |
||
494 | */ |
||
495 | method_flags = (u8) operand[1]->integer.value; |
||
496 | |||
497 | obj_desc->method.param_count = |
||
498 | (u8) (method_flags & AML_METHOD_ARG_COUNT); |
||
499 | |||
500 | /* |
||
501 | * Get the sync_level. If method is serialized, a mutex will be |
||
502 | * created for this method when it is parsed. |
||
503 | */ |
||
504 | if (method_flags & AML_METHOD_SERIALIZED) { |
||
505 | obj_desc->method.info_flags = ACPI_METHOD_SERIALIZED; |
||
506 | |||
507 | /* |
||
508 | * ACPI 1.0: sync_level = 0 |
||
509 | * ACPI 2.0: sync_level = sync_level in method declaration |
||
510 | */ |
||
511 | obj_desc->method.sync_level = (u8) |
||
512 | ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); |
||
513 | } |
||
514 | |||
515 | /* Attach the new object to the method Node */ |
||
516 | |||
517 | status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0], |
||
518 | obj_desc, ACPI_TYPE_METHOD); |
||
519 | |||
520 | /* Remove local reference to the object */ |
||
521 | |||
522 | acpi_ut_remove_reference(obj_desc); |
||
523 | |||
524 | exit: |
||
525 | /* Remove a reference to the operand */ |
||
526 | |||
527 | acpi_ut_remove_reference(operand[1]); |
||
528 | return_ACPI_STATUS(status); |
||
529 | } |