459b81affa99317ea096135ee57ef64aa9e736ee
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
37 #define _COMPONENT ACPI_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
;
77 * Allocate a new parser op to be the root of the parsed
81 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
83 return (AE_NO_MEMORY
);
86 /* Save the Node for use in Acpi_ps_parse_aml */
88 op
->node
= acpi_ns_get_parent_object (node
);
90 /* Get a handle to the parent ACPI table */
92 status
= acpi_tb_handle_to_object (node
->owner_id
, &table_desc
);
93 if (ACPI_FAILURE (status
)) {
97 /* Pass1: Parse the entire Field_unit declaration */
99 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
100 extra_desc
->extra
.pcode_length
, 0,
101 NULL
, NULL
, NULL
, acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
102 if (ACPI_FAILURE (status
)) {
103 acpi_ps_delete_parse_tree (op
);
108 /* Get and init the actual Fiel_unit_op created above */
110 field_op
= op
->value
.arg
;
114 field_op
= op
->value
.arg
;
115 field_op
->node
= node
;
116 acpi_ps_delete_parse_tree (op
);
118 /* Acpi_evaluate the address and length arguments for the Op_region */
120 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
122 return (AE_NO_MEMORY
);
125 op
->node
= acpi_ns_get_parent_object (node
);
127 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
128 extra_desc
->extra
.pcode_length
,
129 ACPI_PARSE_EXECUTE
| ACPI_PARSE_DELETE_TREE
,
130 NULL
/*Method_desc*/, NULL
, NULL
,
131 acpi_ds_exec_begin_op
, acpi_ds_exec_end_op
);
132 /* All done with the parse tree, delete it */
134 acpi_ps_delete_parse_tree (op
);
138 * The pseudo-method object is no longer needed since the region is
141 acpi_cm_remove_reference (obj_desc
->field_unit
.extra
);
142 obj_desc
->field_unit
.extra
= NULL
;
148 /*****************************************************************************
150 * FUNCTION: Acpi_ds_get_region_arguments
152 * PARAMETERS: Obj_desc - A valid region object
156 * DESCRIPTION: Get region address and length. This implements the late
157 * evaluation of these region attributes.
159 ****************************************************************************/
162 acpi_ds_get_region_arguments (
163 ACPI_OPERAND_OBJECT
*obj_desc
)
165 ACPI_OPERAND_OBJECT
*extra_desc
= NULL
;
166 ACPI_NAMESPACE_NODE
*node
;
167 ACPI_PARSE_OBJECT
*op
;
168 ACPI_PARSE_OBJECT
*region_op
;
170 ACPI_TABLE_DESC
*table_desc
;
173 if (obj_desc
->region
.flags
& AOPOBJ_DATA_VALID
) {
178 /* Get the AML pointer (method object) and region node */
180 extra_desc
= obj_desc
->region
.extra
;
181 node
= obj_desc
->region
.node
;
184 * Allocate a new parser op to be the root of the parsed
188 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
190 return (AE_NO_MEMORY
);
193 /* Save the Node for use in Acpi_ps_parse_aml */
195 op
->node
= acpi_ns_get_parent_object (node
);
197 /* Get a handle to the parent ACPI table */
199 status
= acpi_tb_handle_to_object (node
->owner_id
, &table_desc
);
200 if (ACPI_FAILURE (status
)) {
204 /* Parse the entire Op_region declaration, creating a parse tree */
206 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
207 extra_desc
->extra
.pcode_length
, 0,
208 NULL
, NULL
, NULL
, acpi_ds_load1_begin_op
, acpi_ds_load1_end_op
);
210 if (ACPI_FAILURE (status
)) {
211 acpi_ps_delete_parse_tree (op
);
216 /* Get and init the actual Region_op created above */
218 region_op
= op
->value
.arg
;
222 region_op
= op
->value
.arg
;
223 region_op
->node
= node
;
224 acpi_ps_delete_parse_tree (op
);
226 /* Acpi_evaluate the address and length arguments for the Op_region */
228 op
= acpi_ps_alloc_op (AML_SCOPE_OP
);
230 return (AE_NO_MEMORY
);
233 op
->node
= acpi_ns_get_parent_object (node
);
235 status
= acpi_ps_parse_aml (op
, extra_desc
->extra
.pcode
,
236 extra_desc
->extra
.pcode_length
,
237 ACPI_PARSE_EXECUTE
| ACPI_PARSE_DELETE_TREE
,
238 NULL
/*Method_desc*/, NULL
, NULL
,
239 acpi_ds_exec_begin_op
, acpi_ds_exec_end_op
);
241 /* All done with the parse tree, delete it */
243 acpi_ps_delete_parse_tree (op
);
249 /*****************************************************************************
251 * FUNCTION: Acpi_ds_initialize_region
253 * PARAMETERS: Op - A valid region Op object
259 ****************************************************************************/
262 acpi_ds_initialize_region (
263 ACPI_HANDLE obj_handle
)
265 ACPI_OPERAND_OBJECT
*obj_desc
;
269 obj_desc
= acpi_ns_get_attached_object (obj_handle
);
271 /* Namespace is NOT locked */
273 status
= acpi_ev_initialize_region (obj_desc
, FALSE
);
279 /*****************************************************************************
281 * FUNCTION: Acpi_ds_eval_field_unit_operands
283 * PARAMETERS: Op - A valid Field_unit Op object
287 * DESCRIPTION: Get Field_unit Buffer and Index
288 * Called from Acpi_ds_exec_end_op during Field_unit parse tree walk
290 ****************************************************************************/
293 acpi_ds_eval_field_unit_operands (
294 ACPI_WALK_STATE
*walk_state
,
295 ACPI_PARSE_OBJECT
*op
)
298 ACPI_OPERAND_OBJECT
*field_desc
;
299 ACPI_NAMESPACE_NODE
*node
;
300 ACPI_PARSE_OBJECT
*next_op
;
306 ACPI_OPERAND_OBJECT
*res_desc
= NULL
;
307 ACPI_OPERAND_OBJECT
*cnt_desc
= NULL
;
308 ACPI_OPERAND_OBJECT
*off_desc
= NULL
;
309 ACPI_OPERAND_OBJECT
*src_desc
= NULL
;
310 u32 num_operands
= 3;
314 * This is where we evaluate the address and length fields of the Op_field_unit declaration
319 /* Next_op points to the op that holds the Buffer */
320 next_op
= op
->value
.arg
;
322 /* Acpi_evaluate/create the address and length operands */
324 status
= acpi_ds_create_operands (walk_state
, next_op
);
325 if (ACPI_FAILURE (status
)) {
329 field_desc
= acpi_ns_get_attached_object (node
);
331 return (AE_NOT_EXIST
);
335 /* Resolve the operands */
337 status
= acpi_aml_resolve_operands (op
->opcode
, WALK_OPERANDS
, walk_state
);
339 /* Get the operands */
341 status
|= acpi_ds_obj_stack_pop_object (&res_desc
, walk_state
);
342 if (AML_CREATE_FIELD_OP
== op
->opcode
) {
344 status
|= acpi_ds_obj_stack_pop_object (&cnt_desc
, walk_state
);
347 status
|= acpi_ds_obj_stack_pop_object (&off_desc
, walk_state
);
348 status
|= acpi_ds_obj_stack_pop_object (&src_desc
, walk_state
);
350 if (ACPI_FAILURE (status
)) {
351 /* Invalid parameters on object stack */
357 offset
= (u32
) off_desc
->integer
.value
;
361 * If Res_desc is a Name, it will be a direct name pointer after
362 * Acpi_aml_resolve_operands()
365 if (!VALID_DESCRIPTOR_TYPE (res_desc
, ACPI_DESC_TYPE_NAMED
)) {
366 status
= AE_AML_OPERAND_TYPE
;
372 * Setup the Bit offsets and counts, according to the opcode
375 switch (op
->opcode
) {
377 /* Def_create_bit_field */
379 case AML_BIT_FIELD_OP
:
381 /* Offset is in bits, Field is a bit */
388 /* Def_create_byte_field */
390 case AML_BYTE_FIELD_OP
:
392 /* Offset is in bytes, field is a byte */
394 bit_offset
= 8 * offset
;
399 /* Def_create_word_field */
401 case AML_WORD_FIELD_OP
:
403 /* Offset is in bytes, field is a word */
405 bit_offset
= 8 * offset
;
410 /* Def_create_dWord_field */
412 case AML_DWORD_FIELD_OP
:
414 /* Offset is in bytes, field is a dword */
416 bit_offset
= 8 * offset
;
421 /* Def_create_field */
423 case AML_CREATE_FIELD_OP
:
425 /* Offset is in bits, count is in bits */
428 bit_count
= (u16
) cnt_desc
->integer
.value
;
434 status
= AE_AML_BAD_OPCODE
;
440 * Setup field according to the object type
443 switch (src_desc
->common
.type
) {
445 /* Source_buff := Term_arg=>Buffer */
447 case ACPI_TYPE_BUFFER
:
449 if (bit_offset
+ (u32
) bit_count
>
450 (8 * (u32
) src_desc
->buffer
.length
)) {
451 status
= AE_AML_BUFFER_LIMIT
;
456 /* Construct the remainder of the field object */
458 field_desc
->field_unit
.access
= (u8
) ACCESS_ANY_ACC
;
459 field_desc
->field_unit
.lock_rule
= (u8
) GLOCK_NEVER_LOCK
;
460 field_desc
->field_unit
.update_rule
= (u8
) UPDATE_PRESERVE
;
461 field_desc
->field_unit
.length
= bit_count
;
462 field_desc
->field_unit
.bit_offset
= (u8
) (bit_offset
% 8);
463 field_desc
->field_unit
.offset
= DIV_8 (bit_offset
);
464 field_desc
->field_unit
.container
= src_desc
;
466 /* Reference count for Src_desc inherits Field_desc count */
468 src_desc
->common
.reference_count
= (u16
) (src_desc
->common
.reference_count
+
469 field_desc
->common
.reference_count
);
474 /* Improper object type */
480 status
= AE_AML_OPERAND_TYPE
;
485 if (AML_CREATE_FIELD_OP
== op
->opcode
) {
486 /* Delete object descriptor unique to Create_field */
488 acpi_cm_remove_reference (cnt_desc
);
495 /* Always delete the operands */
497 acpi_cm_remove_reference (off_desc
);
498 acpi_cm_remove_reference (src_desc
);
500 if (AML_CREATE_FIELD_OP
== op
->opcode
) {
501 acpi_cm_remove_reference (cnt_desc
);
504 /* On failure, delete the result descriptor */
506 if (ACPI_FAILURE (status
)) {
507 acpi_cm_remove_reference (res_desc
); /* Result descriptor */
511 /* Now the address and length are valid for this op_field_unit */
513 field_desc
->field_unit
.flags
|= AOPOBJ_DATA_VALID
;
520 /*****************************************************************************
522 * FUNCTION: Acpi_ds_eval_region_operands
524 * PARAMETERS: Op - A valid region Op object
528 * DESCRIPTION: Get region address and length
529 * Called from Acpi_ds_exec_end_op during Op_region parse tree walk
531 ****************************************************************************/
534 acpi_ds_eval_region_operands (
535 ACPI_WALK_STATE
*walk_state
,
536 ACPI_PARSE_OBJECT
*op
)
539 ACPI_OPERAND_OBJECT
*obj_desc
;
540 ACPI_OPERAND_OBJECT
*operand_desc
;
541 ACPI_NAMESPACE_NODE
*node
;
542 ACPI_PARSE_OBJECT
*next_op
;
546 * This is where we evaluate the address and length fields of the Op_region declaration
551 /* Next_op points to the op that holds the Space_iD */
552 next_op
= op
->value
.arg
;
554 /* Next_op points to address op */
555 next_op
= next_op
->next
;
557 /* Acpi_evaluate/create the address and length operands */
559 status
= acpi_ds_create_operands (walk_state
, next_op
);
560 if (ACPI_FAILURE (status
)) {
564 /* Resolve the length and address operands to numbers */
566 status
= acpi_aml_resolve_operands (op
->opcode
, WALK_OPERANDS
, walk_state
);
567 if (ACPI_FAILURE (status
)) {
572 obj_desc
= acpi_ns_get_attached_object (node
);
574 return (AE_NOT_EXIST
);
578 * Get the length operand and save it
581 operand_desc
= walk_state
->operands
[walk_state
->num_operands
- 1];
583 obj_desc
->region
.length
= (u32
) operand_desc
->integer
.value
;
584 acpi_cm_remove_reference (operand_desc
);
587 * Get the address and save it
588 * (at top of stack - 1)
590 operand_desc
= walk_state
->operands
[walk_state
->num_operands
- 2];
592 obj_desc
->region
.address
= (ACPI_PHYSICAL_ADDRESS
) operand_desc
->integer
.value
;
593 acpi_cm_remove_reference (operand_desc
);
596 /* Now the address and length are valid for this opregion */
598 obj_desc
->region
.flags
|= AOPOBJ_DATA_VALID
;
604 /*******************************************************************************
606 * FUNCTION: Acpi_ds_exec_begin_control_op
608 * PARAMETERS: Walk_list - The list that owns the walk stack
609 * Op - The control Op
613 * DESCRIPTION: Handles all control ops encountered during control method
616 ******************************************************************************/
619 acpi_ds_exec_begin_control_op (
620 ACPI_WALK_STATE
*walk_state
,
621 ACPI_PARSE_OBJECT
*op
)
623 ACPI_STATUS status
= AE_OK
;
624 ACPI_GENERIC_STATE
*control_state
;
627 switch (op
->opcode
) {
632 * IF/WHILE: Create a new control state to manage these
633 * constructs. We need to manage these as a stack, in order
637 control_state
= acpi_cm_create_control_state ();
638 if (!control_state
) {
639 status
= AE_NO_MEMORY
;
643 acpi_cm_push_generic_state (&walk_state
->control_state
, control_state
);
646 * Save a pointer to the predicate for multiple executions
649 walk_state
->control_state
->control
.aml_predicate_start
=
650 walk_state
->parser_state
->aml
- 1;
651 /* TBD: can this be removed? */
652 /*Acpi_ps_pkg_length_encoding_size (GET8 (Walk_state->Parser_state->Aml));*/
658 /* Predicate is in the state object */
659 /* If predicate is true, the IF was executed, ignore ELSE part */
661 if (walk_state
->last_predicate
) {
662 status
= AE_CTRL_TRUE
;
681 /*******************************************************************************
683 * FUNCTION: Acpi_ds_exec_end_control_op
685 * PARAMETERS: Walk_list - The list that owns the walk stack
686 * Op - The control Op
690 * DESCRIPTION: Handles all control ops encountered during control method
694 ******************************************************************************/
697 acpi_ds_exec_end_control_op (
698 ACPI_WALK_STATE
*walk_state
,
699 ACPI_PARSE_OBJECT
*op
)
701 ACPI_STATUS status
= AE_OK
;
702 ACPI_GENERIC_STATE
*control_state
;
705 switch (op
->opcode
) {
709 * Save the result of the predicate in case there is an
713 walk_state
->last_predicate
=
714 (u8
) walk_state
->control_state
->common
.value
;
717 * Pop the control state that was created at the start
718 * of the IF and free it
722 acpi_cm_pop_generic_state (&walk_state
->control_state
);
724 acpi_cm_delete_generic_state (control_state
);
736 if (walk_state
->control_state
->common
.value
) {
737 /* Predicate was true, go back and evaluate it again! */
739 status
= AE_CTRL_PENDING
;
743 /* Pop this control state and free it */
746 acpi_cm_pop_generic_state (&walk_state
->control_state
);
748 walk_state
->aml_last_while
= control_state
->control
.aml_predicate_start
;
749 acpi_cm_delete_generic_state (control_state
);
758 * One optional operand -- the return value
759 * It can be either an immediate operand or a result that
760 * has been bubbled up the tree
763 /* Return statement has an immediate operand */
765 status
= acpi_ds_create_operands (walk_state
, op
->value
.arg
);
766 if (ACPI_FAILURE (status
)) {
771 * If value being returned is a Reference (such as
772 * an arg or local), resolve it now because it may
773 * cease to exist at the end of the method.
775 status
= acpi_aml_resolve_to_value (&walk_state
->operands
[0], walk_state
);
776 if (ACPI_FAILURE (status
)) {
781 * Get the return value and save as the last result
782 * value. This is the only place where Walk_state->Return_desc
783 * is set to anything other than zero!
786 walk_state
->return_desc
= walk_state
->operands
[0];
789 else if ((walk_state
->results
) &&
790 (walk_state
->results
->results
.num_results
> 0)) {
792 * The return value has come from a previous calculation.
794 * If value being returned is a Reference (such as
795 * an arg or local), resolve it now because it may
796 * cease to exist at the end of the method.
798 * Allow references created by the Index operator to return unchanged.
801 if (VALID_DESCRIPTOR_TYPE (walk_state
->results
->results
.obj_desc
[0], ACPI_DESC_TYPE_INTERNAL
) &&
802 ((walk_state
->results
->results
.obj_desc
[0])->common
.type
== INTERNAL_TYPE_REFERENCE
) &&
803 ((walk_state
->results
->results
.obj_desc
[0])->reference
.opcode
!= AML_INDEX_OP
)) {
804 status
= acpi_aml_resolve_to_value (&walk_state
->results
->results
.obj_desc
[0], walk_state
);
805 if (ACPI_FAILURE (status
)) {
810 walk_state
->return_desc
= walk_state
->results
->results
.obj_desc
[0];
814 /* No return operand */
816 if (walk_state
->num_operands
) {
817 acpi_cm_remove_reference (walk_state
->operands
[0]);
820 walk_state
->operands
[0] = NULL
;
821 walk_state
->num_operands
= 0;
822 walk_state
->return_desc
= NULL
;
826 /* End the control method execution right now */
827 status
= AE_CTRL_TERMINATE
;
833 /* Just do nothing! */
837 case AML_BREAK_POINT_OP
:
839 /* Call up to the OS dependent layer to handle this */
841 acpi_os_breakpoint (NULL
);
843 /* If it returns, we are done! */
851 * As per the ACPI specification:
852 * "The break operation causes the current package
853 * execution to complete"
854 * "Break -- Stop executing the current code package
857 * Returning AE_FALSE here will cause termination of
858 * the current package, and execution will continue one
859 * level up, starting with the completion of the parent Op.
862 status
= AE_CTRL_FALSE
;
868 status
= AE_AML_BAD_OPCODE
;