File: /usr/src/linux/drivers/acpi/dispatcher/dsmthdat.c
1 /*******************************************************************************
2 *
3 * Module Name: dsmthdat - control method arguments and local variables
4 * $Revision: 49 $
5 *
6 ******************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 R. Byron Moore
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include "acpi.h"
28 #include "acparser.h"
29 #include "acdispat.h"
30 #include "acinterp.h"
31 #include "amlcode.h"
32 #include "acnamesp.h"
33
34
35 #define _COMPONENT ACPI_DISPATCHER
36 MODULE_NAME ("dsmthdat")
37
38
39 /*******************************************************************************
40 *
41 * FUNCTION: Acpi_ds_method_data_init
42 *
43 * PARAMETERS: Walk_state - Current walk state object
44 *
45 * RETURN: Status
46 *
47 * DESCRIPTION: Initialize the data structures that hold the method's arguments
48 * and locals. The data struct is an array of NTEs for each.
49 * This allows Ref_of and De_ref_of to work properly for these
50 * special data types.
51 *
52 ******************************************************************************/
53
54 acpi_status
55 acpi_ds_method_data_init (
56 acpi_walk_state *walk_state)
57 {
58 u32 i;
59
60
61 FUNCTION_TRACE ("Ds_method_data_init");
62
63 /*
64 * Walk_state fields are initialized to zero by the
65 * ACPI_MEM_CALLOCATE().
66 *
67 * An Node is assigned to each argument and local so
68 * that Ref_of() can return a pointer to the Node.
69 */
70
71 /* Init the method arguments */
72
73 for (i = 0; i < MTH_NUM_ARGS; i++) {
74 MOVE_UNALIGNED32_TO_32 (&walk_state->arguments[i].name,
75 NAMEOF_ARG_NTE);
76 walk_state->arguments[i].name |= (i << 24);
77 walk_state->arguments[i].data_type = ACPI_DESC_TYPE_NAMED;
78 walk_state->arguments[i].type = ACPI_TYPE_ANY;
79 walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
80 }
81
82 /* Init the method locals */
83
84 for (i = 0; i < MTH_NUM_LOCALS; i++) {
85 MOVE_UNALIGNED32_TO_32 (&walk_state->local_variables[i].name,
86 NAMEOF_LOCAL_NTE);
87
88 walk_state->local_variables[i].name |= (i << 24);
89 walk_state->local_variables[i].data_type = ACPI_DESC_TYPE_NAMED;
90 walk_state->local_variables[i].type = ACPI_TYPE_ANY;
91 walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
92 }
93
94 return_ACPI_STATUS (AE_OK);
95 }
96
97
98 /*******************************************************************************
99 *
100 * FUNCTION: Acpi_ds_method_data_delete_all
101 *
102 * PARAMETERS: Walk_state - Current walk state object
103 *
104 * RETURN: Status
105 *
106 * DESCRIPTION: Delete method locals and arguments. Arguments are only
107 * deleted if this method was called from another method.
108 *
109 ******************************************************************************/
110
111 acpi_status
112 acpi_ds_method_data_delete_all (
113 acpi_walk_state *walk_state)
114 {
115 u32 index;
116 acpi_operand_object *object;
117
118
119 FUNCTION_TRACE ("Ds_method_data_delete_all");
120
121
122 /* Delete the locals */
123
124 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting local variables in %p\n", walk_state));
125
126 for (index = 0; index < MTH_NUM_LOCALS; index++) {
127 object = walk_state->local_variables[index].object;
128 if (object) {
129 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Local%d=%p\n", index, object));
130
131 /* Remove first */
132
133 walk_state->local_variables[index].object = NULL;
134
135 /* Was given a ref when stored */
136
137 acpi_ut_remove_reference (object);
138 }
139 }
140
141
142 /* Delete the arguments */
143
144 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting arguments in %p\n", walk_state));
145
146 for (index = 0; index < MTH_NUM_ARGS; index++) {
147 object = walk_state->arguments[index].object;
148 if (object) {
149 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Arg%d=%p\n", index, object));
150
151 /* Remove first */
152
153 walk_state->arguments[index].object = NULL;
154
155 /* Was given a ref when stored */
156
157 acpi_ut_remove_reference (object);
158 }
159 }
160
161 return_ACPI_STATUS (AE_OK);
162 }
163
164
165 /*******************************************************************************
166 *
167 * FUNCTION: Acpi_ds_method_data_init_args
168 *
169 * PARAMETERS: *Params - Pointer to a parameter list for the method
170 * Max_param_count - The arg count for this method
171 * Walk_state - Current walk state object
172 *
173 * RETURN: Status
174 *
175 * DESCRIPTION: Initialize arguments for a method
176 *
177 ******************************************************************************/
178
179 acpi_status
180 acpi_ds_method_data_init_args (
181 acpi_operand_object **params,
182 u32 max_param_count,
183 acpi_walk_state *walk_state)
184 {
185 acpi_status status;
186 u32 mindex;
187 u32 pindex;
188
189
190 FUNCTION_TRACE_PTR ("Ds_method_data_init_args", params);
191
192
193 if (!params) {
194 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "No param list passed to method\n"));
195 return_ACPI_STATUS (AE_OK);
196 }
197
198 /* Copy passed parameters into the new method stack frame */
199
200 for (pindex = mindex = 0;
201 (mindex < MTH_NUM_ARGS) && (pindex < max_param_count);
202 mindex++) {
203 if (params[pindex]) {
204 /*
205 * A valid parameter.
206 * Set the current method argument to the
207 * Params[Pindex++] argument object descriptor
208 */
209 status = acpi_ds_store_object_to_local (AML_ARG_OP, mindex,
210 params[pindex], walk_state);
211 if (ACPI_FAILURE (status)) {
212 break;
213 }
214
215 pindex++;
216 }
217
218 else {
219 break;
220 }
221 }
222
223 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%d args passed to method\n", pindex));
224 return_ACPI_STATUS (AE_OK);
225 }
226
227
228 /*******************************************************************************
229 *
230 * FUNCTION: Acpi_ds_method_data_get_entry
231 *
232 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
233 * Index - Which local_var or argument to get
234 * Entry - Pointer to where a pointer to the stack
235 * entry is returned.
236 * Walk_state - Current walk state object
237 *
238 * RETURN: Status
239 *
240 * DESCRIPTION: Get the address of the object entry given by Opcode:Index
241 *
242 ******************************************************************************/
243
244 acpi_status
245 acpi_ds_method_data_get_entry (
246 u16 opcode,
247 u32 index,
248 acpi_walk_state *walk_state,
249 acpi_operand_object ***entry)
250 {
251
252 FUNCTION_TRACE_U32 ("Ds_method_data_get_entry", index);
253
254
255 /*
256 * Get the requested object.
257 * The stack "Opcode" is either a Local_variable or an Argument
258 */
259 switch (opcode) {
260
261 case AML_LOCAL_OP:
262
263 if (index > MTH_MAX_LOCAL) {
264 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local_var index %d is invalid (max %d)\n",
265 index, MTH_MAX_LOCAL));
266 return_ACPI_STATUS (AE_BAD_PARAMETER);
267 }
268
269 *entry = (acpi_operand_object **)
270 &walk_state->local_variables[index].object;
271 break;
272
273
274 case AML_ARG_OP:
275
276 if (index > MTH_MAX_ARG) {
277 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n",
278 index, MTH_MAX_ARG));
279 return_ACPI_STATUS (AE_BAD_PARAMETER);
280 }
281
282 *entry = (acpi_operand_object **)
283 &walk_state->arguments[index].object;
284 break;
285
286
287 default:
288 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Opcode %d is invalid\n", opcode));
289 return_ACPI_STATUS (AE_BAD_PARAMETER);
290 }
291
292
293 return_ACPI_STATUS (AE_OK);
294 }
295
296
297 /*******************************************************************************
298 *
299 * FUNCTION: Acpi_ds_method_data_set_entry
300 *
301 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
302 * Index - Which local_var or argument to get
303 * Object - Object to be inserted into the stack entry
304 * Walk_state - Current walk state object
305 *
306 * RETURN: Status
307 *
308 * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index.
309 *
310 ******************************************************************************/
311
312 acpi_status
313 acpi_ds_method_data_set_entry (
314 u16 opcode,
315 u32 index,
316 acpi_operand_object *object,
317 acpi_walk_state *walk_state)
318 {
319 acpi_status status;
320 acpi_operand_object **entry;
321
322
323 FUNCTION_TRACE ("Ds_method_data_set_entry");
324
325
326 /* Get a pointer to the stack entry to set */
327
328 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
329 if (ACPI_FAILURE (status)) {
330 return_ACPI_STATUS (status);
331 }
332
333 /* Increment ref count so object can't be deleted while installed */
334
335 acpi_ut_add_reference (object);
336
337 /* Install the object into the stack entry */
338
339 *entry = object;
340
341 return_ACPI_STATUS (AE_OK);
342 }
343
344
345 /*******************************************************************************
346 *
347 * FUNCTION: Acpi_ds_method_data_get_type
348 *
349 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
350 * Index - Which local_var or argument whose type
351 * to get
352 * Walk_state - Current walk state object
353 *
354 * RETURN: Data type of selected Arg or Local
355 * Used only in Exec_monadic2()/Type_op.
356 *
357 ******************************************************************************/
358
359 acpi_object_type8
360 acpi_ds_method_data_get_type (
361 u16 opcode,
362 u32 index,
363 acpi_walk_state *walk_state)
364 {
365 acpi_status status;
366 acpi_operand_object **entry;
367 acpi_operand_object *object;
368
369
370 FUNCTION_TRACE ("Ds_method_data_get_type");
371
372
373 /* Get a pointer to the requested stack entry */
374
375 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
376 if (ACPI_FAILURE (status)) {
377 return_VALUE ((ACPI_TYPE_NOT_FOUND));
378 }
379
380 /* Get the object from the method stack */
381
382 object = *entry;
383
384 /* Get the object type */
385
386 if (!object) {
387 /* Any == 0 => "uninitialized" -- see spec 15.2.3.5.2.28 */
388 return_VALUE (ACPI_TYPE_ANY);
389 }
390
391 return_VALUE (object->common.type);
392 }
393
394
395 /*******************************************************************************
396 *
397 * FUNCTION: Acpi_ds_method_data_get_node
398 *
399 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
400 * Index - Which local_var or argument whose type
401 * to get
402 * Walk_state - Current walk state object
403 *
404 * RETURN: Get the Node associated with a local or arg.
405 *
406 ******************************************************************************/
407
408 acpi_namespace_node *
409 acpi_ds_method_data_get_node (
410 u16 opcode,
411 u32 index,
412 acpi_walk_state *walk_state)
413 {
414 acpi_namespace_node *node = NULL;
415
416
417 FUNCTION_TRACE ("Ds_method_data_get_node");
418
419
420 switch (opcode) {
421
422 case AML_LOCAL_OP:
423
424 if (index > MTH_MAX_LOCAL) {
425 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n",
426 index, MTH_MAX_LOCAL));
427 return_PTR (node);
428 }
429
430 node = &walk_state->local_variables[index];
431 break;
432
433
434 case AML_ARG_OP:
435
436 if (index > MTH_MAX_ARG) {
437 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n",
438 index, MTH_MAX_ARG));
439 return_PTR (node);
440 }
441
442 node = &walk_state->arguments[index];
443 break;
444
445
446 default:
447 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Opcode %d is invalid\n", opcode));
448 break;
449 }
450
451
452 return_PTR (node);
453 }
454
455
456 /*******************************************************************************
457 *
458 * FUNCTION: Acpi_ds_method_data_get_value
459 *
460 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
461 * Index - Which local_var or argument to get
462 * Walk_state - Current walk state object
463 * *Dest_desc - Ptr to Descriptor into which selected Arg
464 * or Local value should be copied
465 *
466 * RETURN: Status
467 *
468 * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame
469 * at the current top of the method stack.
470 * Used only in Acpi_ex_resolve_to_value().
471 *
472 ******************************************************************************/
473
474 acpi_status
475 acpi_ds_method_data_get_value (
476 u16 opcode,
477 u32 index,
478 acpi_walk_state *walk_state,
479 acpi_operand_object **dest_desc)
480 {
481 acpi_status status;
482 acpi_operand_object **entry;
483 acpi_operand_object *object;
484
485
486 FUNCTION_TRACE ("Ds_method_data_get_value");
487
488
489 /* Validate the object descriptor */
490
491 if (!dest_desc) {
492 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null object descriptor pointer\n"));
493 return_ACPI_STATUS (AE_BAD_PARAMETER);
494 }
495
496
497 /* Get a pointer to the requested method stack entry */
498
499 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
500 if (ACPI_FAILURE (status)) {
501 return_ACPI_STATUS (status);
502 }
503
504 /* Get the object from the method stack */
505
506 object = *entry;
507
508
509 /* Examine the returned object, it must be valid. */
510
511 if (!object) {
512 /*
513 * Index points to uninitialized object stack value.
514 * This means that either 1) The expected argument was
515 * not passed to the method, or 2) A local variable
516 * was referenced by the method (via the ASL)
517 * before it was initialized. Either case is an error.
518 */
519 switch (opcode) {
520 case AML_ARG_OP:
521
522 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at entry %p\n",
523 index, entry));
524
525 return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG);
526 break;
527
528 case AML_LOCAL_OP:
529
530 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at entry %p\n",
531 index, entry));
532
533 return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL);
534 break;
535 }
536 }
537
538
539 /*
540 * Index points to initialized and valid object stack value.
541 * Return an additional reference to the object
542 */
543 *dest_desc = object;
544 acpi_ut_add_reference (object);
545
546 return_ACPI_STATUS (AE_OK);
547 }
548
549
550 /*******************************************************************************
551 *
552 * FUNCTION: Acpi_ds_method_data_delete_value
553 *
554 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
555 * Index - Which local_var or argument to delete
556 * Walk_state - Current walk state object
557 *
558 * RETURN: Status
559 *
560 * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts
561 * a null into the stack slot after the object is deleted.
562 *
563 ******************************************************************************/
564
565 acpi_status
566 acpi_ds_method_data_delete_value (
567 u16 opcode,
568 u32 index,
569 acpi_walk_state *walk_state)
570 {
571 acpi_status status;
572 acpi_operand_object **entry;
573 acpi_operand_object *object;
574
575
576 FUNCTION_TRACE ("Ds_method_data_delete_value");
577
578
579 /* Get a pointer to the requested entry */
580
581 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
582 if (ACPI_FAILURE (status)) {
583 return_ACPI_STATUS (status);
584 }
585
586 /* Get the current entry in this slot k */
587
588 object = *entry;
589
590 /*
591 * Undefine the Arg or Local by setting its descriptor
592 * pointer to NULL. Locals/Args can contain both
593 * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs
594 */
595 *entry = NULL;
596
597 if ((object) &&
598 (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL))) {
599 /*
600 * There is a valid object in this slot
601 * Decrement the reference count by one to balance the
602 * increment when the object was stored in the slot.
603 */
604 acpi_ut_remove_reference (object);
605 }
606
607 return_ACPI_STATUS (AE_OK);
608 }
609
610
611 /*******************************************************************************
612 *
613 * FUNCTION: Acpi_ds_store_object_to_local
614 *
615 * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
616 * Index - Which local_var or argument to set
617 * Src_desc - Value to be stored
618 * Walk_state - Current walk state
619 *
620 * RETURN: Status
621 *
622 * DESCRIPTION: Store a value in an Arg or Local. The Src_desc is installed
623 * as the new value for the Arg or Local and the reference count
624 * for Src_desc is incremented.
625 *
626 ******************************************************************************/
627
628 acpi_status
629 acpi_ds_store_object_to_local (
630 u16 opcode,
631 u32 index,
632 acpi_operand_object *src_desc,
633 acpi_walk_state *walk_state)
634 {
635 acpi_status status;
636 acpi_operand_object **entry;
637
638
639 FUNCTION_TRACE ("Ds_method_data_set_value");
640 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%d Idx=%d Obj=%p\n",
641 opcode, index, src_desc));
642
643
644 /* Parameter validation */
645
646 if (!src_desc) {
647 return_ACPI_STATUS (AE_BAD_PARAMETER);
648 }
649
650
651 /* Get a pointer to the requested method stack entry */
652
653 status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
654 if (ACPI_FAILURE (status)) {
655 goto cleanup;
656 }
657
658 if (*entry == src_desc) {
659 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p already installed!\n", src_desc));
660 goto cleanup;
661 }
662
663
664 /*
665 * If there is an object already in this slot, we either
666 * have to delete it, or if this is an argument and there
667 * is an object reference stored there, we have to do
668 * an indirect store!
669 */
670 if (*entry) {
671 /*
672 * Check for an indirect store if an argument
673 * contains an object reference (stored as an Node).
674 * We don't allow this automatic dereferencing for
675 * locals, since a store to a local should overwrite
676 * anything there, including an object reference.
677 *
678 * If both Arg0 and Local0 contain Ref_of (Local4):
679 *
680 * Store (1, Arg0) - Causes indirect store to local4
681 * Store (1, Local0) - Stores 1 in local0, overwriting
682 * the reference to local4
683 * Store (1, De_refof (Local0)) - Causes indirect store to local4
684 *
685 * Weird, but true.
686 */
687 if ((opcode == AML_ARG_OP) &&
688 (VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED))) {
689 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
690 "Arg (%p) is an Obj_ref(Node), storing in %p\n",
691 src_desc, *entry));
692
693 /* Detach an existing object from the Node */
694
695 acpi_ns_detach_object ((acpi_namespace_node *) *entry);
696
697 /*
698 * Store this object into the Node
699 * (do the indirect store)
700 */
701 status = acpi_ns_attach_object ((acpi_namespace_node *) *entry, src_desc,
702 src_desc->common.type);
703 return_ACPI_STATUS (status);
704 }
705
706
707 #ifdef ACPI_ENABLE_IMPLICIT_CONVERSION
708 /*
709 * Perform "Implicit conversion" of the new object to the type of the
710 * existing object
711 */
712 status = acpi_ex_convert_to_target_type ((*entry)->common.type, &src_desc, walk_state);
713 if (ACPI_FAILURE (status)) {
714 goto cleanup;
715 }
716 #endif
717
718 /*
719 * Delete the existing object
720 * before storing the new one
721 */
722 acpi_ds_method_data_delete_value (opcode, index, walk_state);
723 }
724
725
726 /*
727 * Install the Obj_stack descriptor (*Src_desc) into
728 * the descriptor for the Arg or Local.
729 * Install the new object in the stack entry
730 * (increments the object reference count by one)
731 */
732 status = acpi_ds_method_data_set_entry (opcode, index, src_desc, walk_state);
733 if (ACPI_FAILURE (status)) {
734 goto cleanup;
735 }
736
737 /* Normal exit */
738
739 return_ACPI_STATUS (AE_OK);
740
741
742 /* Error exit */
743
744 cleanup:
745
746 return_ACPI_STATUS (status);
747 }
748
749