1 /******************************************************************************
3 * Module Name: dsopcode - Dispatcher Op Region support and handling of
7 *****************************************************************************/
10 * Copyright (C) 2000, 2001 R. Byron Moore
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #define _COMPONENT ACPI_DISPATCHER
31 MODULE_NAME ("dsopcode")
34 /*****************************************************************************
36 * FUNCTION: Acpi_ds_get_field_unit_arguments
38 * PARAMETERS: Obj_desc - A valid Field_unit object
42 * DESCRIPTION: Get Field_unit Buffer and Index. This implements the late
43 * evaluation of these field attributes.
45 ****************************************************************************/
48 acpi_ds_get_field_unit_arguments (
49 ACPI_OPERAND_OBJECT
*obj_desc
)
51 ACPI_OPERAND_OBJECT
*extra_desc
;
52 ACPI_NAMESPACE_NODE
*node
;
53 ACPI_PARSE_OBJECT
*op
;
54 ACPI_PARSE_OBJECT
*field_op
;
56 ACPI_TABLE_DESC
*table_desc
;
59 if (obj_desc
->common
.flags
& AOPOBJ_DATA_VALID
) {
64 /* Get the AML pointer (method object) and Field_unit node */
66 extra_desc
= obj_desc
->field_unit
.extra
;
67 node
= obj_desc
->field_unit
.node
;
70 * Allocate a new parser op to be the root of the parsed
74 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
76 return (AE_NO_MEMORY
);
79 /* Save the Node for use in Acpi_ps_parse_aml */
81 op
->node
= acpi_ns_get_parent_object (node
);
83 /* Get a handle to the parent ACPI table */
85 status
= acpi_tb_handle_to_object (node
->owner_id
, &table_desc
);
86 if (ACPI_FAILURE (status
)) {
90 /* Pass1: Parse the entire Field_unit declaration */
92 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
93 extra_desc
->extra
.pcode_length
, 0,
94 NULL
, NULL
, NULL
, acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
95 if (ACPI_FAILURE (status
)) {
96 acpi_ps_delete_parse_tree (op
);
101 /* Get and init the actual Fiel_unit_op created above */
103 field_op
= op
->value
.arg
;
107 field_op
= op
->value
.arg
;
108 field_op
->node
= node
;
109 acpi_ps_delete_parse_tree (op
);
111 /* Acpi_evaluate the address and length arguments for the Op_region */
113 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
115 return (AE_NO_MEMORY
);
118 op
->node
= acpi_ns_get_parent_object (node
);
120 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
121 extra_desc
->extra
.pcode_length
,
122 ACPI_PARSE_EXECUTE
| ACPI_PARSE_DELETE_TREE
,
123 NULL
/*Method_desc*/, NULL
, NULL
,
124 acpi_ds_exec_begin_op
, acpi_ds_exec_end_op
);
125 /* All done with the parse tree, delete it */
127 acpi_ps_delete_parse_tree (op
);
131 * The pseudo-method object is no longer needed since the region is
134 acpi_cm_remove_reference (obj_desc
->field_unit
.extra
);
135 obj_desc
->field_unit
.extra
= NULL
;
141 /*****************************************************************************
143 * FUNCTION: Acpi_ds_get_region_arguments
145 * PARAMETERS: Obj_desc - A valid region object
149 * DESCRIPTION: Get region address and length. This implements the late
150 * evaluation of these region attributes.
152 ****************************************************************************/
155 acpi_ds_get_region_arguments (
156 ACPI_OPERAND_OBJECT
*obj_desc
)
158 ACPI_OPERAND_OBJECT
*extra_desc
= NULL
;
159 ACPI_NAMESPACE_NODE
*node
;
160 ACPI_PARSE_OBJECT
*op
;
161 ACPI_PARSE_OBJECT
*region_op
;
163 ACPI_TABLE_DESC
*table_desc
;
166 if (obj_desc
->region
.flags
& AOPOBJ_DATA_VALID
) {
171 /* Get the AML pointer (method object) and region node */
173 extra_desc
= obj_desc
->region
.extra
;
174 node
= obj_desc
->region
.node
;
177 * Allocate a new parser op to be the root of the parsed
181 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
183 return (AE_NO_MEMORY
);
186 /* Save the Node for use in Acpi_ps_parse_aml */
188 op
->node
= acpi_ns_get_parent_object (node
);
190 /* Get a handle to the parent ACPI table */
192 status
= acpi_tb_handle_to_object (node
->owner_id
, &table_desc
);
193 if (ACPI_FAILURE (status
)) {
197 /* Parse the entire Op_region declaration, creating a parse tree */
199 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
200 extra_desc
->extra
.pcode_length
, 0,
201 NULL
, NULL
, NULL
, acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
203 if (ACPI_FAILURE (status
)) {
204 acpi_ps_delete_parse_tree (op
);
209 /* Get and init the actual Region_op created above */
211 region_op
= op
->value
.arg
;
215 region_op
= op
->value
.arg
;
216 region_op
->node
= node
;
217 acpi_ps_delete_parse_tree (op
);
219 /* Acpi_evaluate the address and length arguments for the Op_region */
221 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
223 return (AE_NO_MEMORY
);
226 op
->node
= acpi_ns_get_parent_object (node
);
228 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
229 extra_desc
->extra
.pcode_length
,
230 ACPI_PARSE_EXECUTE
| ACPI_PARSE_DELETE_TREE
,
231 NULL
/*Method_desc*/, NULL
, NULL
,
232 acpi_ds_exec_begin_op
, acpi_ds_exec_end_op
);
234 /* All done with the parse tree, delete it */
236 acpi_ps_delete_parse_tree (op
);
242 /*****************************************************************************
244 * FUNCTION: Acpi_ds_initialize_region
246 * PARAMETERS: Op - A valid region Op object
252 ****************************************************************************/
255 acpi_ds_initialize_region (
256 ACPI_HANDLE obj_handle
)
258 ACPI_OPERAND_OBJECT
*obj_desc
;
262 obj_desc
= acpi_ns_get_attached_object (obj_handle
);
264 /* Namespace is NOT locked */
266 status
= acpi_ev_initialize_region (obj_desc
, FALSE
);
272 /*****************************************************************************
274 * FUNCTION: Acpi_ds_eval_field_unit_operands
276 * PARAMETERS: Op - A valid Field_unit Op object
280 * DESCRIPTION: Get Field_unit Buffer and Index
281 * Called from Acpi_ds_exec_end_op during Field_unit parse tree walk
283 ****************************************************************************/
286 acpi_ds_eval_field_unit_operands (
287 ACPI_WALK_STATE
*walk_state
,
288 ACPI_PARSE_OBJECT
*op
)
291 ACPI_OPERAND_OBJECT
*field_desc
;
292 ACPI_NAMESPACE_NODE
*node
;
293 ACPI_PARSE_OBJECT
*next_op
;
299 ACPI_OPERAND_OBJECT
*res_desc
= NULL
;
300 ACPI_OPERAND_OBJECT
*cnt_desc
= NULL
;
301 ACPI_OPERAND_OBJECT
*off_desc
= NULL
;
302 ACPI_OPERAND_OBJECT
*src_desc
= NULL
;
303 u32 num_operands
= 3;
307 * This is where we evaluate the address and length fields of the Op_field_unit declaration
312 /* Next_op points to the op that holds the Buffer */
313 next_op
= op
->value
.arg
;
315 /* Acpi_evaluate/create the address and length operands */
317 status
= acpi_ds_create_operands (walk_state
, next_op
);
318 if (ACPI_FAILURE (status
)) {
322 field_desc
= acpi_ns_get_attached_object (node
);
324 return (AE_NOT_EXIST
);
328 /* Resolve the operands */
330 status
= acpi_aml_resolve_operands (op
->opcode
, WALK_OPERANDS
, walk_state
);
332 /* Get the operands */
334 status
|= acpi_ds_obj_stack_pop_object (&res_desc
, walk_state
);
335 if (AML_CREATE_FIELD_OP
== op
->opcode
) {
337 status
|= acpi_ds_obj_stack_pop_object (&cnt_desc
, walk_state
);
340 status
|= acpi_ds_obj_stack_pop_object (&off_desc
, walk_state
);
341 status
|= acpi_ds_obj_stack_pop_object (&src_desc
, walk_state
);
343 if (ACPI_FAILURE (status
)) {
344 /* Invalid parameters on object stack */
350 offset
= (u32
) off_desc
->integer
.value
;
354 * If Res_desc is a Name, it will be a direct name pointer after
355 * Acpi_aml_resolve_operands()
358 if (!VALID_DESCRIPTOR_TYPE (res_desc
, ACPI_DESC_TYPE_NAMED
)) {
359 status
= AE_AML_OPERAND_TYPE
;
365 * Setup the Bit offsets and counts, according to the opcode
368 switch (op
->opcode
) {
370 /* Def_create_bit_field */
372 case AML_BIT_FIELD_OP
:
374 /* Offset is in bits, Field is a bit */
381 /* Def_create_byte_field */
383 case AML_BYTE_FIELD_OP
:
385 /* Offset is in bytes, field is a byte */
387 bit_offset
= 8 * offset
;
392 /* Def_create_word_field */
394 case AML_WORD_FIELD_OP
:
396 /* Offset is in bytes, field is a word */
398 bit_offset
= 8 * offset
;
403 /* Def_create_dWord_field */
405 case AML_DWORD_FIELD_OP
:
407 /* Offset is in bytes, field is a dword */
409 bit_offset
= 8 * offset
;
414 /* Def_create_field */
416 case AML_CREATE_FIELD_OP
:
418 /* Offset is in bits, count is in bits */
421 bit_count
= (u16
) cnt_desc
->integer
.value
;
427 status
= AE_AML_BAD_OPCODE
;
433 * Setup field according to the object type
436 switch (src_desc
->common
.type
) {
438 /* Source_buff := Term_arg=>Buffer */
440 case ACPI_TYPE_BUFFER
:
442 if (bit_offset
+ (u32
) bit_count
>
443 (8 * (u32
) src_desc
->buffer
.length
)) {
444 status
= AE_AML_BUFFER_LIMIT
;
449 /* Construct the remainder of the field object */
451 field_desc
->field_unit
.access
= (u8
) ACCESS_ANY_ACC
;
452 field_desc
->field_unit
.lock_rule
= (u8
) GLOCK_NEVER_LOCK
;
453 field_desc
->field_unit
.update_rule
= (u8
) UPDATE_PRESERVE
;
454 field_desc
->field_unit
.length
= bit_count
;
455 field_desc
->field_unit
.bit_offset
= (u8
) (bit_offset
% 8);
456 field_desc
->field_unit
.offset
= DIV_8 (bit_offset
);
457 field_desc
->field_unit
.container
= src_desc
;
459 /* Reference count for Src_desc inherits Field_desc count */
461 src_desc
->common
.reference_count
= (u16
) (src_desc
->common
.reference_count
+
462 field_desc
->common
.reference_count
);
467 /* Improper object type */
473 status
= AE_AML_OPERAND_TYPE
;
478 if (AML_CREATE_FIELD_OP
== op
->opcode
) {
479 /* Delete object descriptor unique to Create_field */
481 acpi_cm_remove_reference (cnt_desc
);
488 /* Always delete the operands */
490 acpi_cm_remove_reference (off_desc
);
491 acpi_cm_remove_reference (src_desc
);
493 if (AML_CREATE_FIELD_OP
== op
->opcode
) {
494 acpi_cm_remove_reference (cnt_desc
);
497 /* On failure, delete the result descriptor */
499 if (ACPI_FAILURE (status
)) {
500 acpi_cm_remove_reference (res_desc
); /* Result descriptor */
504 /* Now the address and length are valid for this op_field_unit */
506 field_desc
->field_unit
.flags
|= AOPOBJ_DATA_VALID
;
513 /*****************************************************************************
515 * FUNCTION: Acpi_ds_eval_region_operands
517 * PARAMETERS: Op - A valid region Op object
521 * DESCRIPTION: Get region address and length
522 * Called from Acpi_ds_exec_end_op during Op_region parse tree walk
524 ****************************************************************************/
527 acpi_ds_eval_region_operands (
528 ACPI_WALK_STATE
*walk_state
,
529 ACPI_PARSE_OBJECT
*op
)
532 ACPI_OPERAND_OBJECT
*obj_desc
;
533 ACPI_OPERAND_OBJECT
*operand_desc
;
534 ACPI_NAMESPACE_NODE
*node
;
535 ACPI_PARSE_OBJECT
*next_op
;
539 * This is where we evaluate the address and length fields of the Op_region declaration
544 /* Next_op points to the op that holds the Space_iD */
545 next_op
= op
->value
.arg
;
547 /* Next_op points to address op */
548 next_op
= next_op
->next
;
550 /* Acpi_evaluate/create the address and length operands */
552 status
= acpi_ds_create_operands (walk_state
, next_op
);
553 if (ACPI_FAILURE (status
)) {
557 /* Resolve the length and address operands to numbers */
559 status
= acpi_aml_resolve_operands (op
->opcode
, WALK_OPERANDS
, walk_state
);
560 if (ACPI_FAILURE (status
)) {
565 obj_desc
= acpi_ns_get_attached_object (node
);
567 return (AE_NOT_EXIST
);
571 * Get the length operand and save it
574 operand_desc
= walk_state
->operands
[walk_state
->num_operands
- 1];
576 obj_desc
->region
.length
= (u32
) operand_desc
->integer
.value
;
577 acpi_cm_remove_reference (operand_desc
);
580 * Get the address and save it
581 * (at top of stack - 1)
583 operand_desc
= walk_state
->operands
[walk_state
->num_operands
- 2];
585 obj_desc
->region
.address
= (ACPI_PHYSICAL_ADDRESS
) operand_desc
->integer
.value
;
586 acpi_cm_remove_reference (operand_desc
);
589 /* Now the address and length are valid for this opregion */
591 obj_desc
->region
.flags
|= AOPOBJ_DATA_VALID
;
597 /*******************************************************************************
599 * FUNCTION: Acpi_ds_exec_begin_control_op
601 * PARAMETERS: Walk_list - The list that owns the walk stack
602 * Op - The control Op
606 * DESCRIPTION: Handles all control ops encountered during control method
609 ******************************************************************************/
612 acpi_ds_exec_begin_control_op (
613 ACPI_WALK_STATE
*walk_state
,
614 ACPI_PARSE_OBJECT
*op
)
616 ACPI_STATUS status
= AE_OK
;
617 ACPI_GENERIC_STATE
*control_state
;
620 switch (op
->opcode
) {
625 * IF/WHILE: Create a new control state to manage these
626 * constructs. We need to manage these as a stack, in order
630 control_state
= acpi_cm_create_control_state ();
631 if (!control_state
) {
632 status
= AE_NO_MEMORY
;
636 acpi_cm_push_generic_state (&walk_state
->control_state
, control_state
);
639 * Save a pointer to the predicate for multiple executions
642 walk_state
->control_state
->control
.aml_predicate_start
=
643 walk_state
->parser_state
->aml
- 1;
644 /* TBD: can this be removed? */
645 /*Acpi_ps_pkg_length_encoding_size (GET8 (Walk_state->Parser_state->Aml));*/
651 /* Predicate is in the state object */
652 /* If predicate is true, the IF was executed, ignore ELSE part */
654 if (walk_state
->last_predicate
) {
655 status
= AE_CTRL_TRUE
;
674 /*******************************************************************************
676 * FUNCTION: Acpi_ds_exec_end_control_op
678 * PARAMETERS: Walk_list - The list that owns the walk stack
679 * Op - The control Op
683 * DESCRIPTION: Handles all control ops encountered during control method
687 ******************************************************************************/
690 acpi_ds_exec_end_control_op (
691 ACPI_WALK_STATE
*walk_state
,
692 ACPI_PARSE_OBJECT
*op
)
694 ACPI_STATUS status
= AE_OK
;
695 ACPI_GENERIC_STATE
*control_state
;
698 switch (op
->opcode
) {
702 * Save the result of the predicate in case there is an
706 walk_state
->last_predicate
=
707 (u8
) walk_state
->control_state
->common
.value
;
710 * Pop the control state that was created at the start
711 * of the IF and free it
715 acpi_cm_pop_generic_state (&walk_state
->control_state
);
717 acpi_cm_delete_generic_state (control_state
);
729 if (walk_state
->control_state
->common
.value
) {
730 /* Predicate was true, go back and evaluate it again! */
732 status
= AE_CTRL_PENDING
;
736 /* Pop this control state and free it */
739 acpi_cm_pop_generic_state (&walk_state
->control_state
);
741 walk_state
->aml_last_while
= control_state
->control
.aml_predicate_start
;
742 acpi_cm_delete_generic_state (control_state
);
751 * One optional operand -- the return value
752 * It can be either an immediate operand or a result that
753 * has been bubbled up the tree
756 /* Return statement has an immediate operand */
758 status
= acpi_ds_create_operands (walk_state
, op
->value
.arg
);
759 if (ACPI_FAILURE (status
)) {
764 * If value being returned is a Reference (such as
765 * an arg or local), resolve it now because it may
766 * cease to exist at the end of the method.
768 status
= acpi_aml_resolve_to_value (&walk_state
->operands
[0], walk_state
);
769 if (ACPI_FAILURE (status
)) {
774 * Get the return value and save as the last result
775 * value. This is the only place where Walk_state->Return_desc
776 * is set to anything other than zero!
779 walk_state
->return_desc
= walk_state
->operands
[0];
782 else if ((walk_state
->results
) &&
783 (walk_state
->results
->results
.num_results
> 0)) {
785 * The return value has come from a previous calculation.
787 * If value being returned is a Reference (such as
788 * an arg or local), resolve it now because it may
789 * cease to exist at the end of the method.
791 * Allow references created by the Index operator to return unchanged.
794 if (VALID_DESCRIPTOR_TYPE (walk_state
->results
->results
.obj_desc
[0], ACPI_DESC_TYPE_INTERNAL
) &&
795 ((walk_state
->results
->results
.obj_desc
[0])->common
.type
== INTERNAL_TYPE_REFERENCE
) &&
796 ((walk_state
->results
->results
.obj_desc
[0])->reference
.opcode
!= AML_INDEX_OP
)) {
797 status
= acpi_aml_resolve_to_value (&walk_state
->results
->results
.obj_desc
[0], walk_state
);
798 if (ACPI_FAILURE (status
)) {
803 walk_state
->return_desc
= walk_state
->results
->results
.obj_desc
[0];
807 /* No return operand */
809 if (walk_state
->num_operands
) {
810 acpi_cm_remove_reference (walk_state
->operands
[0]);
813 walk_state
->operands
[0] = NULL
;
814 walk_state
->num_operands
= 0;
815 walk_state
->return_desc
= NULL
;
819 /* End the control method execution right now */
820 status
= AE_CTRL_TERMINATE
;
826 /* Just do nothing! */
830 case AML_BREAK_POINT_OP
:
832 /* Call up to the OS dependent layer to handle this */
834 acpi_os_breakpoint (NULL
);
836 /* If it returns, we are done! */
844 * As per the ACPI specification:
845 * "The break operation causes the current package
846 * execution to complete"
847 * "Break -- Stop executing the current code package
850 * Returning AE_FALSE here will cause termination of
851 * the current package, and execution will continue one
852 * level up, starting with the completion of the parent Op.
855 status
= AE_CTRL_FALSE
;
861 status
= AE_AML_BAD_OPCODE
;