1 /******************************************************************************
3 * Module Name: dsopcode - Dispatcher Op Region support and handling of
7 *****************************************************************************/
10 * Copyright (C) 2000 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
37 #define _COMPONENT DISPATCHER
38 MODULE_NAME ("dsopcode")
41 /*****************************************************************************
43 * FUNCTION: Acpi_ds_get_field_unit_arguments
45 * PARAMETERS: Obj_desc - A valid Field_unit object
49 * DESCRIPTION: Get Field_unit Buffer and Index. This implements the late
50 * evaluation of these field attributes.
52 ****************************************************************************/
55 acpi_ds_get_field_unit_arguments (
56 ACPI_OPERAND_OBJECT
*obj_desc
)
58 ACPI_OPERAND_OBJECT
*extra_desc
;
59 ACPI_NAMESPACE_NODE
*node
;
60 ACPI_PARSE_OBJECT
*op
;
61 ACPI_PARSE_OBJECT
*field_op
;
63 ACPI_TABLE_DESC
*table_desc
;
66 if (obj_desc
->common
.flags
& AOPOBJ_DATA_VALID
) {
71 /* Get the AML pointer (method object) and Field_unit node */
73 extra_desc
= obj_desc
->field_unit
.extra
;
74 node
= obj_desc
->field_unit
.node
;
78 * Allocate a new parser op to be the root of the parsed
82 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
84 return (AE_NO_MEMORY
);
87 /* Save the Node for use in Acpi_ps_parse_aml */
89 op
->node
= acpi_ns_get_parent_object (node
);
91 /* Get a handle to the parent ACPI table */
93 status
= acpi_tb_handle_to_object (node
->owner_id
, &table_desc
);
94 if (ACPI_FAILURE (status
)) {
98 /* Pass1: Parse the entire Field_unit declaration */
100 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
101 extra_desc
->extra
.pcode_length
, 0,
102 NULL
, NULL
, NULL
, acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
103 if (ACPI_FAILURE (status
)) {
104 acpi_ps_delete_parse_tree (op
);
109 /* Get and init the actual Fiel_unit_op created above */
111 field_op
= op
->value
.arg
;
115 field_op
= op
->value
.arg
;
116 field_op
->node
= node
;
117 acpi_ps_delete_parse_tree (op
);
119 /* Acpi_evaluate the address and length arguments for the Op_region */
121 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
123 return (AE_NO_MEMORY
);
126 op
->node
= acpi_ns_get_parent_object (node
);
128 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
129 extra_desc
->extra
.pcode_length
,
130 ACPI_PARSE_EXECUTE
| ACPI_PARSE_DELETE_TREE
,
131 NULL
/*Method_desc*/, NULL
, NULL
,
132 acpi_ds_exec_begin_op
, acpi_ds_exec_end_op
);
133 /* All done with the parse tree, delete it */
135 acpi_ps_delete_parse_tree (op
);
139 * The pseudo-method object is no longer needed since the region is
142 acpi_cm_remove_reference (obj_desc
->field_unit
.extra
);
143 obj_desc
->field_unit
.extra
= NULL
;
149 /*****************************************************************************
151 * FUNCTION: Acpi_ds_get_region_arguments
153 * PARAMETERS: Obj_desc - A valid region object
157 * DESCRIPTION: Get region address and length. This implements the late
158 * evaluation of these region attributes.
160 ****************************************************************************/
163 acpi_ds_get_region_arguments (
164 ACPI_OPERAND_OBJECT
*obj_desc
)
166 ACPI_OPERAND_OBJECT
*extra_desc
= NULL
;
167 ACPI_NAMESPACE_NODE
*node
;
168 ACPI_PARSE_OBJECT
*op
;
169 ACPI_PARSE_OBJECT
*region_op
;
171 ACPI_TABLE_DESC
*table_desc
;
174 if (obj_desc
->region
.flags
& AOPOBJ_DATA_VALID
) {
179 /* Get the AML pointer (method object) and region node */
181 extra_desc
= obj_desc
->region
.extra
;
182 node
= obj_desc
->region
.node
;
185 * Allocate a new parser op to be the root of the parsed
189 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
191 return (AE_NO_MEMORY
);
194 /* Save the Node for use in Acpi_ps_parse_aml */
196 op
->node
= acpi_ns_get_parent_object (node
);
198 /* Get a handle to the parent ACPI table */
200 status
= acpi_tb_handle_to_object (node
->owner_id
, &table_desc
);
201 if (ACPI_FAILURE (status
)) {
205 /* Parse the entire Op_region declaration, creating a parse tree */
207 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
208 extra_desc
->extra
.pcode_length
, 0,
209 NULL
, NULL
, NULL
, acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
211 if (ACPI_FAILURE (status
)) {
212 acpi_ps_delete_parse_tree (op
);
217 /* Get and init the actual Region_op created above */
219 region_op
= op
->value
.arg
;
223 region_op
= op
->value
.arg
;
224 region_op
->node
= node
;
225 acpi_ps_delete_parse_tree (op
);
227 /* Acpi_evaluate the address and length arguments for the Op_region */
229 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
231 return (AE_NO_MEMORY
);
234 op
->node
= acpi_ns_get_parent_object (node
);
236 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
237 extra_desc
->extra
.pcode_length
,
238 ACPI_PARSE_EXECUTE
| ACPI_PARSE_DELETE_TREE
,
239 NULL
/*Method_desc*/, NULL
, NULL
,
240 acpi_ds_exec_begin_op
, acpi_ds_exec_end_op
);
242 /* All done with the parse tree, delete it */
244 acpi_ps_delete_parse_tree (op
);
250 /*****************************************************************************
252 * FUNCTION: Acpi_ds_initialize_region
254 * PARAMETERS: Op - A valid region Op object
260 ****************************************************************************/
263 acpi_ds_initialize_region (
264 ACPI_HANDLE obj_handle
)
266 ACPI_OPERAND_OBJECT
*obj_desc
;
270 obj_desc
= acpi_ns_get_attached_object (obj_handle
);
272 /* Namespace is NOT locked */
274 status
= acpi_ev_initialize_region (obj_desc
, FALSE
);
280 /*****************************************************************************
282 * FUNCTION: Acpi_ds_eval_field_unit_operands
284 * PARAMETERS: Op - A valid Field_unit Op object
288 * DESCRIPTION: Get Field_unit Buffer and Index
289 * Called from Acpi_ds_exec_end_op during Field_unit parse tree walk
291 ****************************************************************************/
294 acpi_ds_eval_field_unit_operands (
295 ACPI_WALK_STATE
*walk_state
,
296 ACPI_PARSE_OBJECT
*op
)
299 ACPI_OPERAND_OBJECT
*field_desc
;
300 ACPI_NAMESPACE_NODE
*node
;
301 ACPI_PARSE_OBJECT
*next_op
;
307 ACPI_OPERAND_OBJECT
*res_desc
= NULL
;
308 ACPI_OPERAND_OBJECT
*cnt_desc
= NULL
;
309 ACPI_OPERAND_OBJECT
*off_desc
= NULL
;
310 ACPI_OPERAND_OBJECT
*src_desc
= NULL
;
311 u32 num_operands
= 3;
315 * This is where we evaluate the address and length fields of the Op_field_unit declaration
320 /* Next_op points to the op that holds the Buffer */
321 next_op
= op
->value
.arg
;
323 /* Acpi_evaluate/create the address and length operands */
325 status
= acpi_ds_create_operands (walk_state
, next_op
);
326 if (ACPI_FAILURE (status
)) {
330 field_desc
= acpi_ns_get_attached_object (node
);
332 return (AE_NOT_EXIST
);
336 /* Resolve the operands */
338 status
= acpi_aml_resolve_operands (op
->opcode
, WALK_OPERANDS
, walk_state
);
340 /* Get the operands */
342 status
|= acpi_ds_obj_stack_pop_object (&res_desc
, walk_state
);
343 if (AML_CREATE_FIELD_OP
== op
->opcode
) {
345 status
|= acpi_ds_obj_stack_pop_object (&cnt_desc
, walk_state
);
348 status
|= acpi_ds_obj_stack_pop_object (&off_desc
, walk_state
);
349 status
|= acpi_ds_obj_stack_pop_object (&src_desc
, walk_state
);
351 if (ACPI_FAILURE (status
)) {
352 /* Invalid parameters on object stack */
358 offset
= (u32
) off_desc
->number
.value
;
362 * If Res_desc is a Name, it will be a direct name pointer after
363 * Acpi_aml_resolve_operands()
366 if (!VALID_DESCRIPTOR_TYPE (res_desc
, ACPI_DESC_TYPE_NAMED
)) {
367 status
= AE_AML_OPERAND_TYPE
;
373 * Setup the Bit offsets and counts, according to the opcode
379 /* Def_create_bit_field */
381 case AML_BIT_FIELD_OP
:
383 /* Offset is in bits, Field is a bit */
390 /* Def_create_byte_field */
392 case AML_BYTE_FIELD_OP
:
394 /* Offset is in bytes, field is a byte */
396 bit_offset
= 8 * offset
;
401 /* Def_create_word_field */
403 case AML_WORD_FIELD_OP
:
405 /* Offset is in bytes, field is a word */
407 bit_offset
= 8 * offset
;
412 /* Def_create_dWord_field */
414 case AML_DWORD_FIELD_OP
:
416 /* Offset is in bytes, field is a dword */
418 bit_offset
= 8 * offset
;
423 /* Def_create_field */
425 case AML_CREATE_FIELD_OP
:
427 /* Offset is in bits, count is in bits */
430 bit_count
= (u16
) cnt_desc
->number
.value
;
436 status
= AE_AML_BAD_OPCODE
;
442 * Setup field according to the object type
445 switch (src_desc
->common
.type
)
448 /* Source_buff := Term_arg=>Buffer */
450 case ACPI_TYPE_BUFFER
:
452 if (bit_offset
+ (u32
) bit_count
>
453 (8 * (u32
) src_desc
->buffer
.length
))
455 status
= AE_AML_BUFFER_LIMIT
;
460 /* Construct the remainder of the field object */
462 field_desc
->field_unit
.access
= (u8
) ACCESS_ANY_ACC
;
463 field_desc
->field_unit
.lock_rule
= (u8
) GLOCK_NEVER_LOCK
;
464 field_desc
->field_unit
.update_rule
= (u8
) UPDATE_PRESERVE
;
465 field_desc
->field_unit
.length
= bit_count
;
466 field_desc
->field_unit
.bit_offset
= (u8
) (bit_offset
% 8);
467 field_desc
->field_unit
.offset
= DIV_8 (bit_offset
);
468 field_desc
->field_unit
.container
= src_desc
;
470 /* Reference count for Src_desc inherits Field_desc count */
472 src_desc
->common
.reference_count
= (u16
) (src_desc
->common
.reference_count
+
473 field_desc
->common
.reference_count
);
478 /* Improper object type */
482 if ((src_desc
->common
.type
> (u8
) INTERNAL_TYPE_REFERENCE
) ||
483 !acpi_cm_valid_object_type (src_desc
->common
.type
))
486 status
= AE_AML_OPERAND_TYPE
;
491 if (AML_CREATE_FIELD_OP
== op
->opcode
) {
492 /* Delete object descriptor unique to Create_field */
494 acpi_cm_remove_reference (cnt_desc
);
501 /* Always delete the operands */
503 acpi_cm_remove_reference (off_desc
);
504 acpi_cm_remove_reference (src_desc
);
506 if (AML_CREATE_FIELD_OP
== op
->opcode
) {
507 acpi_cm_remove_reference (cnt_desc
);
510 /* On failure, delete the result descriptor */
512 if (ACPI_FAILURE (status
)) {
513 acpi_cm_remove_reference (res_desc
); /* Result descriptor */
517 /* Now the address and length are valid for this op_field_unit */
519 field_desc
->field_unit
.flags
|= AOPOBJ_DATA_VALID
;
526 /*****************************************************************************
528 * FUNCTION: Acpi_ds_eval_region_operands
530 * PARAMETERS: Op - A valid region Op object
534 * DESCRIPTION: Get region address and length
535 * Called from Acpi_ds_exec_end_op during Op_region parse tree walk
537 ****************************************************************************/
540 acpi_ds_eval_region_operands (
541 ACPI_WALK_STATE
*walk_state
,
542 ACPI_PARSE_OBJECT
*op
)
545 ACPI_OPERAND_OBJECT
*obj_desc
;
546 ACPI_OPERAND_OBJECT
*operand_desc
;
547 ACPI_NAMESPACE_NODE
*node
;
548 ACPI_PARSE_OBJECT
*next_op
;
552 * This is where we evaluate the address and length fields of the Op_region declaration
557 /* Next_op points to the op that holds the Space_iD */
558 next_op
= op
->value
.arg
;
560 /* Next_op points to address op */
561 next_op
= next_op
->next
;
563 /* Acpi_evaluate/create the address and length operands */
565 status
= acpi_ds_create_operands (walk_state
, next_op
);
566 if (ACPI_FAILURE (status
)) {
570 /* Resolve the length and address operands to numbers */
572 status
= acpi_aml_resolve_operands (op
->opcode
, WALK_OPERANDS
, walk_state
);
573 if (ACPI_FAILURE (status
)) {
578 obj_desc
= acpi_ns_get_attached_object (node
);
580 return (AE_NOT_EXIST
);
584 * Get the length operand and save it
587 operand_desc
= walk_state
->operands
[walk_state
->num_operands
- 1];
589 obj_desc
->region
.length
= (u32
) operand_desc
->number
.value
;
590 acpi_cm_remove_reference (operand_desc
);
593 * Get the address and save it
594 * (at top of stack - 1)
596 operand_desc
= walk_state
->operands
[walk_state
->num_operands
- 2];
598 obj_desc
->region
.address
= (ACPI_PHYSICAL_ADDRESS
) operand_desc
->number
.value
;
599 acpi_cm_remove_reference (operand_desc
);
602 /* Now the address and length are valid for this opregion */
604 obj_desc
->region
.flags
|= AOPOBJ_DATA_VALID
;
610 /*******************************************************************************
612 * FUNCTION: Acpi_ds_exec_begin_control_op
614 * PARAMETERS: Walk_list - The list that owns the walk stack
615 * Op - The control Op
619 * DESCRIPTION: Handles all control ops encountered during control method
622 ******************************************************************************/
625 acpi_ds_exec_begin_control_op (
626 ACPI_WALK_STATE
*walk_state
,
627 ACPI_PARSE_OBJECT
*op
)
629 ACPI_STATUS status
= AE_OK
;
630 ACPI_GENERIC_STATE
*control_state
;
639 * IF/WHILE: Create a new control state to manage these
640 * constructs. We need to manage these as a stack, in order
644 control_state
= acpi_cm_create_control_state ();
645 if (!control_state
) {
646 status
= AE_NO_MEMORY
;
650 acpi_cm_push_generic_state (&walk_state
->control_state
, control_state
);
653 * Save a pointer to the predicate for multiple executions
656 walk_state
->control_state
->control
.aml_predicate_start
=
657 walk_state
->parser_state
->aml
- 1;
658 /* TBD: can this be removed? */
659 /*Acpi_ps_pkg_length_encoding_size (GET8 (Walk_state->Parser_state->Aml));*/
665 /* Predicate is in the state object */
666 /* If predicate is true, the IF was executed, ignore ELSE part */
668 if (walk_state
->last_predicate
) {
669 status
= AE_CTRL_TRUE
;
688 /*******************************************************************************
690 * FUNCTION: Acpi_ds_exec_end_control_op
692 * PARAMETERS: Walk_list - The list that owns the walk stack
693 * Op - The control Op
697 * DESCRIPTION: Handles all control ops encountered during control method
701 ******************************************************************************/
704 acpi_ds_exec_end_control_op (
705 ACPI_WALK_STATE
*walk_state
,
706 ACPI_PARSE_OBJECT
*op
)
708 ACPI_STATUS status
= AE_OK
;
709 ACPI_GENERIC_STATE
*control_state
;
717 * Save the result of the predicate in case there is an
721 walk_state
->last_predicate
=
722 (u8
) walk_state
->control_state
->common
.value
;
725 * Pop the control state that was created at the start
726 * of the IF and free it
730 acpi_cm_pop_generic_state (&walk_state
->control_state
);
732 acpi_cm_delete_generic_state (control_state
);
744 if (walk_state
->control_state
->common
.value
) {
745 /* Predicate was true, go back and evaluate it again! */
747 status
= AE_CTRL_PENDING
;
751 /* Pop this control state and free it */
754 acpi_cm_pop_generic_state (&walk_state
->control_state
);
756 walk_state
->aml_last_while
= control_state
->control
.aml_predicate_start
;
757 acpi_cm_delete_generic_state (control_state
);
766 * One optional operand -- the return value
767 * It can be either an immediate operand or a result that
768 * has been bubbled up the tree
771 /* Return statement has an immediate operand */
773 status
= acpi_ds_create_operands (walk_state
, op
->value
.arg
);
774 if (ACPI_FAILURE (status
)) {
779 * If value being returned is a Reference (such as
780 * an arg or local), resolve it now because it may
781 * cease to exist at the end of the method.
784 status
= acpi_aml_resolve_to_value (&walk_state
->operands
[0], walk_state
);
785 if (ACPI_FAILURE (status
)) {
790 * Get the return value and save as the last result
791 * value. This is the only place where Walk_state->Return_desc
792 * is set to anything other than zero!
795 walk_state
->return_desc
= walk_state
->operands
[0];
798 else if ((walk_state
->results
) &&
799 (walk_state
->results
->results
.num_results
> 0))
802 * The return value has come from a previous calculation.
804 * If value being returned is a Reference (such as
805 * an arg or local), resolve it now because it may
806 * cease to exist at the end of the method.
809 status
= acpi_aml_resolve_to_value (&walk_state
->results
->results
.obj_desc
[0], walk_state
);
810 if (ACPI_FAILURE (status
)) {
814 walk_state
->return_desc
= walk_state
->results
->results
.obj_desc
[0];
818 /* No return operand */
820 if (walk_state
->num_operands
) {
821 acpi_cm_remove_reference (walk_state
->operands
[0]);
824 walk_state
->operands
[0] = NULL
;
825 walk_state
->num_operands
= 0;
826 walk_state
->return_desc
= NULL
;
830 /* End the control method execution right now */
831 status
= AE_CTRL_TERMINATE
;
837 /* Just do nothing! */
841 case AML_BREAK_POINT_OP
:
843 /* Call up to the OS dependent layer to handle this */
845 acpi_os_breakpoint (NULL
);
847 /* If it returns, we are done! */
855 * As per the ACPI specification:
856 * "The break operation causes the current package
857 * execution to complete"
858 * "Break -- Stop executing the current code package
861 * Returning AE_FALSE here will cause termination of
862 * the current package, and execution will continue one
863 * level up, starting with the completion of the parent Op.
866 status
= AE_CTRL_FALSE
;
872 status
= AE_AML_BAD_OPCODE
;