diff options
author | Robert Moore <robert.moore@intel.com> | 2005-05-26 00:00:00 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2005-07-13 16:46:34 -0400 |
commit | 88ac00f5a841dcfc5c682000f4a6add0add8caac (patch) | |
tree | 80dcff8323c6c79e8706f42eb4b7c3884bc03152 /drivers/acpi/parser/psparse.c | |
parent | 6f42ccf2fc50ecee8ea170040627f268430c1648 (diff) |
ACPICA 20050526 from Bob Moore <robert.moore@intel.com>
Implemented support to execute Type 1 and Type 2 AML
opcodes appearing at the module level (not within a control
method.) These opcodes are executed exactly once at the
time the table is loaded. This type of code was legal up
until the release of ACPI 2.0B (2002) and is now supported
within ACPI CA in order to provide backwards compatibility
with earlier BIOS implementations. This eliminates the
"Encountered executable code at module level" warning that
was previously generated upon detection of such code.
Fixed a problem in the interpreter where an AE_NOT_FOUND
exception could inadvertently be generated during the
lookup of namespace objects in the second pass parse of
ACPI tables and control methods. It appears that this
problem could occur during the resolution of forward
references to namespace objects.
Added the ACPI_MUTEX_DEBUG #ifdef to the
acpi_ut_release_mutex function, corresponding to the same
the deadlock detection debug code to be compiled out in
the normal case, improving mutex performance (and overall
subsystem performance) considerably. As suggested by
Alexey Starikovskiy.
Implemented a handful of miscellaneous fixes for possible
memory leaks on error conditions and error handling
control paths. These fixes were suggested by FreeBSD and
the Coverity Prevent source code analysis tool.
Added a check for a null RSDT pointer in
acpi_get_firmware_table (tbxfroot.c) to prevent a fault
in this error case.
Signed-off-by Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/parser/psparse.c')
-rw-r--r-- | drivers/acpi/parser/psparse.c | 109 |
1 files changed, 83 insertions, 26 deletions
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c index bbfdc1a58c27..bdbe0d99486f 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/parser/psparse.c | |||
@@ -66,7 +66,7 @@ static u32 acpi_gbl_depth = 0; | |||
66 | 66 | ||
67 | /* Local prototypes */ | 67 | /* Local prototypes */ |
68 | 68 | ||
69 | static void | 69 | static acpi_status |
70 | acpi_ps_complete_this_op ( | 70 | acpi_ps_complete_this_op ( |
71 | struct acpi_walk_state *walk_state, | 71 | struct acpi_walk_state *walk_state, |
72 | union acpi_parse_object *op); | 72 | union acpi_parse_object *op); |
@@ -152,13 +152,13 @@ acpi_ps_peek_opcode ( | |||
152 | * PARAMETERS: walk_state - Current State | 152 | * PARAMETERS: walk_state - Current State |
153 | * Op - Op to complete | 153 | * Op - Op to complete |
154 | * | 154 | * |
155 | * RETURN: None. | 155 | * RETURN: Status |
156 | * | 156 | * |
157 | * DESCRIPTION: Perform any cleanup at the completion of an Op. | 157 | * DESCRIPTION: Perform any cleanup at the completion of an Op. |
158 | * | 158 | * |
159 | ******************************************************************************/ | 159 | ******************************************************************************/ |
160 | 160 | ||
161 | static void | 161 | static acpi_status |
162 | acpi_ps_complete_this_op ( | 162 | acpi_ps_complete_this_op ( |
163 | struct acpi_walk_state *walk_state, | 163 | struct acpi_walk_state *walk_state, |
164 | union acpi_parse_object *op) | 164 | union acpi_parse_object *op) |
@@ -175,19 +175,26 @@ acpi_ps_complete_this_op ( | |||
175 | /* Check for null Op, can happen if AML code is corrupt */ | 175 | /* Check for null Op, can happen if AML code is corrupt */ |
176 | 176 | ||
177 | if (!op) { | 177 | if (!op) { |
178 | return_VOID; | 178 | return_ACPI_STATUS (AE_OK); /* OK for now */ |
179 | } | 179 | } |
180 | 180 | ||
181 | /* Delete this op and the subtree below it if asked to */ | 181 | /* Delete this op and the subtree below it if asked to */ |
182 | 182 | ||
183 | if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) || | 183 | if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) || |
184 | (walk_state->op_info->class == AML_CLASS_ARGUMENT)) { | 184 | (walk_state->op_info->class == AML_CLASS_ARGUMENT)) { |
185 | return_VOID; | 185 | return_ACPI_STATUS (AE_OK); |
186 | } | 186 | } |
187 | 187 | ||
188 | /* Make sure that we only delete this subtree */ | 188 | /* Make sure that we only delete this subtree */ |
189 | 189 | ||
190 | if (op->common.parent) { | 190 | if (op->common.parent) { |
191 | prev = op->common.parent->common.value.arg; | ||
192 | if (!prev) { | ||
193 | /* Nothing more to do */ | ||
194 | |||
195 | goto cleanup; | ||
196 | } | ||
197 | |||
191 | /* | 198 | /* |
192 | * Check if we need to replace the operator and its subtree | 199 | * Check if we need to replace the operator and its subtree |
193 | * with a return value op (placeholder op) | 200 | * with a return value op (placeholder op) |
@@ -206,7 +213,7 @@ acpi_ps_complete_this_op ( | |||
206 | */ | 213 | */ |
207 | replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); | 214 | replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); |
208 | if (!replacement_op) { | 215 | if (!replacement_op) { |
209 | goto cleanup; | 216 | goto allocate_error; |
210 | } | 217 | } |
211 | break; | 218 | break; |
212 | 219 | ||
@@ -223,18 +230,17 @@ acpi_ps_complete_this_op ( | |||
223 | (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { | 230 | (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { |
224 | replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); | 231 | replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); |
225 | if (!replacement_op) { | 232 | if (!replacement_op) { |
226 | goto cleanup; | 233 | goto allocate_error; |
227 | } | 234 | } |
228 | } | 235 | } |
229 | 236 | else if ((op->common.parent->common.aml_opcode == AML_NAME_OP) && | |
230 | if ((op->common.parent->common.aml_opcode == AML_NAME_OP) && | 237 | (walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2)) { |
231 | (walk_state->descending_callback != acpi_ds_exec_begin_op)) { | ||
232 | if ((op->common.aml_opcode == AML_BUFFER_OP) || | 238 | if ((op->common.aml_opcode == AML_BUFFER_OP) || |
233 | (op->common.aml_opcode == AML_PACKAGE_OP) || | 239 | (op->common.aml_opcode == AML_PACKAGE_OP) || |
234 | (op->common.aml_opcode == AML_VAR_PACKAGE_OP)) { | 240 | (op->common.aml_opcode == AML_VAR_PACKAGE_OP)) { |
235 | replacement_op = acpi_ps_alloc_op (op->common.aml_opcode); | 241 | replacement_op = acpi_ps_alloc_op (op->common.aml_opcode); |
236 | if (!replacement_op) { | 242 | if (!replacement_op) { |
237 | goto cleanup; | 243 | goto allocate_error; |
238 | } | 244 | } |
239 | 245 | ||
240 | replacement_op->named.data = op->named.data; | 246 | replacement_op->named.data = op->named.data; |
@@ -244,15 +250,15 @@ acpi_ps_complete_this_op ( | |||
244 | break; | 250 | break; |
245 | 251 | ||
246 | default: | 252 | default: |
253 | |||
247 | replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); | 254 | replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP); |
248 | if (!replacement_op) { | 255 | if (!replacement_op) { |
249 | goto cleanup; | 256 | goto allocate_error; |
250 | } | 257 | } |
251 | } | 258 | } |
252 | 259 | ||
253 | /* We must unlink this op from the parent tree */ | 260 | /* We must unlink this op from the parent tree */ |
254 | 261 | ||
255 | prev = op->common.parent->common.value.arg; | ||
256 | if (prev == op) { | 262 | if (prev == op) { |
257 | /* This op is the first in the list */ | 263 | /* This op is the first in the list */ |
258 | 264 | ||
@@ -298,7 +304,15 @@ cleanup: | |||
298 | /* Now we can actually delete the subtree rooted at Op */ | 304 | /* Now we can actually delete the subtree rooted at Op */ |
299 | 305 | ||
300 | acpi_ps_delete_parse_tree (op); | 306 | acpi_ps_delete_parse_tree (op); |
301 | return_VOID; | 307 | return_ACPI_STATUS (AE_OK); |
308 | |||
309 | |||
310 | allocate_error: | ||
311 | |||
312 | /* Always delete the subtree, even on error */ | ||
313 | |||
314 | acpi_ps_delete_parse_tree (op); | ||
315 | return_ACPI_STATUS (AE_NO_MEMORY); | ||
302 | } | 316 | } |
303 | 317 | ||
304 | 318 | ||
@@ -443,6 +457,7 @@ acpi_ps_parse_loop ( | |||
443 | struct acpi_walk_state *walk_state) | 457 | struct acpi_walk_state *walk_state) |
444 | { | 458 | { |
445 | acpi_status status = AE_OK; | 459 | acpi_status status = AE_OK; |
460 | acpi_status status2; | ||
446 | union acpi_parse_object *op = NULL; /* current op */ | 461 | union acpi_parse_object *op = NULL; /* current op */ |
447 | union acpi_parse_object *arg = NULL; | 462 | union acpi_parse_object *arg = NULL; |
448 | union acpi_parse_object *pre_op = NULL; | 463 | union acpi_parse_object *pre_op = NULL; |
@@ -744,7 +759,6 @@ acpi_ps_parse_loop ( | |||
744 | break; | 759 | break; |
745 | 760 | ||
746 | default: | 761 | default: |
747 | |||
748 | /* | 762 | /* |
749 | * Op is not a constant or string, append each argument | 763 | * Op is not a constant or string, append each argument |
750 | * to the Op | 764 | * to the Op |
@@ -770,6 +784,23 @@ acpi_ps_parse_loop ( | |||
770 | 784 | ||
771 | /* Special processing for certain opcodes */ | 785 | /* Special processing for certain opcodes */ |
772 | 786 | ||
787 | if (walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) { | ||
788 | switch (op->common.aml_opcode) { | ||
789 | case AML_IF_OP: | ||
790 | case AML_ELSE_OP: | ||
791 | case AML_WHILE_OP: | ||
792 | |||
793 | /* Skip body of if/else/while in pass 1 */ | ||
794 | |||
795 | parser_state->aml = parser_state->pkg_end; | ||
796 | walk_state->arg_count = 0; | ||
797 | break; | ||
798 | |||
799 | default: | ||
800 | break; | ||
801 | } | ||
802 | } | ||
803 | |||
773 | switch (op->common.aml_opcode) { | 804 | switch (op->common.aml_opcode) { |
774 | case AML_METHOD_OP: | 805 | case AML_METHOD_OP: |
775 | 806 | ||
@@ -796,7 +827,7 @@ acpi_ps_parse_loop ( | |||
796 | 827 | ||
797 | if ((op->common.parent) && | 828 | if ((op->common.parent) && |
798 | (op->common.parent->common.aml_opcode == AML_NAME_OP) && | 829 | (op->common.parent->common.aml_opcode == AML_NAME_OP) && |
799 | (walk_state->descending_callback != acpi_ds_exec_begin_op)) { | 830 | (walk_state->pass_number <= ACPI_IMODE_LOAD_PASS2)) { |
800 | /* | 831 | /* |
801 | * Skip parsing of Buffers and Packages | 832 | * Skip parsing of Buffers and Packages |
802 | * because we don't have enough info in the first pass | 833 | * because we don't have enough info in the first pass |
@@ -900,15 +931,21 @@ close_this_op: | |||
900 | */ | 931 | */ |
901 | parser_state->scope->parse_scope.arg_count--; | 932 | parser_state->scope->parse_scope.arg_count--; |
902 | 933 | ||
903 | /* Close this Op (will result in parse subtree deletion) */ | 934 | /* Finished with pre_op */ |
904 | 935 | ||
905 | acpi_ps_complete_this_op (walk_state, op); | ||
906 | op = NULL; | ||
907 | if (pre_op) { | 936 | if (pre_op) { |
908 | acpi_ps_free_op (pre_op); | 937 | acpi_ps_free_op (pre_op); |
909 | pre_op = NULL; | 938 | pre_op = NULL; |
910 | } | 939 | } |
911 | 940 | ||
941 | /* Close this Op (will result in parse subtree deletion) */ | ||
942 | |||
943 | status2 = acpi_ps_complete_this_op (walk_state, op); | ||
944 | if (ACPI_FAILURE (status2)) { | ||
945 | return_ACPI_STATUS (status2); | ||
946 | } | ||
947 | op = NULL; | ||
948 | |||
912 | switch (status) { | 949 | switch (status) { |
913 | case AE_OK: | 950 | case AE_OK: |
914 | break; | 951 | break; |
@@ -936,7 +973,10 @@ close_this_op: | |||
936 | status = walk_state->ascending_callback (walk_state); | 973 | status = walk_state->ascending_callback (walk_state); |
937 | status = acpi_ps_next_parse_state (walk_state, op, status); | 974 | status = acpi_ps_next_parse_state (walk_state, op, status); |
938 | 975 | ||
939 | acpi_ps_complete_this_op (walk_state, op); | 976 | status2 = acpi_ps_complete_this_op (walk_state, op); |
977 | if (ACPI_FAILURE (status2)) { | ||
978 | return_ACPI_STATUS (status2); | ||
979 | } | ||
940 | op = NULL; | 980 | op = NULL; |
941 | } | 981 | } |
942 | status = AE_OK; | 982 | status = AE_OK; |
@@ -962,7 +1002,10 @@ close_this_op: | |||
962 | status = walk_state->ascending_callback (walk_state); | 1002 | status = walk_state->ascending_callback (walk_state); |
963 | status = acpi_ps_next_parse_state (walk_state, op, status); | 1003 | status = acpi_ps_next_parse_state (walk_state, op, status); |
964 | 1004 | ||
965 | acpi_ps_complete_this_op (walk_state, op); | 1005 | status2 = acpi_ps_complete_this_op (walk_state, op); |
1006 | if (ACPI_FAILURE (status2)) { | ||
1007 | return_ACPI_STATUS (status2); | ||
1008 | } | ||
966 | op = NULL; | 1009 | op = NULL; |
967 | 1010 | ||
968 | status = AE_OK; | 1011 | status = AE_OK; |
@@ -976,7 +1019,10 @@ close_this_op: | |||
976 | /* Clean up */ | 1019 | /* Clean up */ |
977 | do { | 1020 | do { |
978 | if (op) { | 1021 | if (op) { |
979 | acpi_ps_complete_this_op (walk_state, op); | 1022 | status2 = acpi_ps_complete_this_op (walk_state, op); |
1023 | if (ACPI_FAILURE (status2)) { | ||
1024 | return_ACPI_STATUS (status2); | ||
1025 | } | ||
980 | } | 1026 | } |
981 | acpi_ps_pop_scope (parser_state, &op, | 1027 | acpi_ps_pop_scope (parser_state, &op, |
982 | &walk_state->arg_types, &walk_state->arg_count); | 1028 | &walk_state->arg_types, &walk_state->arg_count); |
@@ -990,7 +1036,10 @@ close_this_op: | |||
990 | 1036 | ||
991 | do { | 1037 | do { |
992 | if (op) { | 1038 | if (op) { |
993 | acpi_ps_complete_this_op (walk_state, op); | 1039 | status2 = acpi_ps_complete_this_op (walk_state, op); |
1040 | if (ACPI_FAILURE (status2)) { | ||
1041 | return_ACPI_STATUS (status2); | ||
1042 | } | ||
994 | } | 1043 | } |
995 | acpi_ps_pop_scope (parser_state, &op, | 1044 | acpi_ps_pop_scope (parser_state, &op, |
996 | &walk_state->arg_types, &walk_state->arg_count); | 1045 | &walk_state->arg_types, &walk_state->arg_count); |
@@ -1053,7 +1102,10 @@ close_this_op: | |||
1053 | /* Clean up */ | 1102 | /* Clean up */ |
1054 | do { | 1103 | do { |
1055 | if (op) { | 1104 | if (op) { |
1056 | acpi_ps_complete_this_op (walk_state, op); | 1105 | status2 = acpi_ps_complete_this_op (walk_state, op); |
1106 | if (ACPI_FAILURE (status2)) { | ||
1107 | return_ACPI_STATUS (status2); | ||
1108 | } | ||
1057 | } | 1109 | } |
1058 | 1110 | ||
1059 | acpi_ps_pop_scope (parser_state, &op, | 1111 | acpi_ps_pop_scope (parser_state, &op, |
@@ -1065,12 +1117,17 @@ close_this_op: | |||
1065 | } | 1117 | } |
1066 | 1118 | ||
1067 | else if (ACPI_FAILURE (status)) { | 1119 | else if (ACPI_FAILURE (status)) { |
1068 | acpi_ps_complete_this_op (walk_state, op); | 1120 | /* First error is most important */ |
1121 | |||
1122 | (void) acpi_ps_complete_this_op (walk_state, op); | ||
1069 | return_ACPI_STATUS (status); | 1123 | return_ACPI_STATUS (status); |
1070 | } | 1124 | } |
1071 | } | 1125 | } |
1072 | 1126 | ||
1073 | acpi_ps_complete_this_op (walk_state, op); | 1127 | status2 = acpi_ps_complete_this_op (walk_state, op); |
1128 | if (ACPI_FAILURE (status2)) { | ||
1129 | return_ACPI_STATUS (status2); | ||
1130 | } | ||
1074 | } | 1131 | } |
1075 | 1132 | ||
1076 | acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, | 1133 | acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types, |