]>
Commit | Line | Data |
---|---|---|
95857638 | 1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
1da177e4 LT |
2 | /****************************************************************************** |
3 | * | |
4 | * Module Name: exoparg1 - AML execution - opcodes with 1 argument | |
5 | * | |
800ba7c5 | 6 | * Copyright (C) 2000 - 2020, Intel Corp. |
1da177e4 | 7 | * |
95857638 | 8 | *****************************************************************************/ |
1da177e4 | 9 | |
1da177e4 | 10 | #include <acpi/acpi.h> |
e2f7a777 LB |
11 | #include "accommon.h" |
12 | #include "acparser.h" | |
13 | #include "acdispat.h" | |
14 | #include "acinterp.h" | |
15 | #include "amlcode.h" | |
16 | #include "acnamesp.h" | |
1da177e4 | 17 | |
1da177e4 | 18 | #define _COMPONENT ACPI_EXECUTER |
4be44fcd | 19 | ACPI_MODULE_NAME("exoparg1") |
1da177e4 LT |
20 | |
21 | /*! | |
22 | * Naming convention for AML interpreter execution routines. | |
23 | * | |
24 | * The routines that begin execution of AML opcodes are named with a common | |
25 | * convention based upon the number of arguments, the number of target operands, | |
26 | * and whether or not a value is returned: | |
27 | * | |
28 | * AcpiExOpcode_xA_yT_zR | |
29 | * | |
30 | * Where: | |
31 | * | |
32 | * xA - ARGUMENTS: The number of arguments (input operands) that are | |
33 | * required for this opcode type (0 through 6 args). | |
34 | * yT - TARGETS: The number of targets (output operands) that are required | |
35 | * for this opcode type (0, 1, or 2 targets). | |
36 | * zR - RETURN VALUE: Indicates whether this opcode type returns a value | |
37 | * as the function return (0 or 1). | |
38 | * | |
39 | * The AcpiExOpcode* functions are called via the Dispatcher component with | |
40 | * fully resolved operands. | |
41 | !*/ | |
1da177e4 LT |
42 | /******************************************************************************* |
43 | * | |
44 | * FUNCTION: acpi_ex_opcode_0A_0T_1R | |
45 | * | |
46 | * PARAMETERS: walk_state - Current state (contains AML opcode) | |
47 | * | |
48 | * RETURN: Status | |
49 | * | |
50 | * DESCRIPTION: Execute operator with no operands, one return value | |
51 | * | |
52 | ******************************************************************************/ | |
4be44fcd | 53 | acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state) |
1da177e4 | 54 | { |
4be44fcd LB |
55 | acpi_status status = AE_OK; |
56 | union acpi_operand_object *return_desc = NULL; | |
1da177e4 | 57 | |
b229cf92 | 58 | ACPI_FUNCTION_TRACE_STR(ex_opcode_0A_0T_1R, |
4be44fcd | 59 | acpi_ps_get_opcode_name(walk_state->opcode)); |
1da177e4 LT |
60 | |
61 | /* Examine the AML opcode */ | |
62 | ||
63 | switch (walk_state->opcode) { | |
4be44fcd | 64 | case AML_TIMER_OP: /* Timer () */ |
1da177e4 LT |
65 | |
66 | /* Create a return object of type Integer */ | |
67 | ||
dc95a270 BM |
68 | return_desc = |
69 | acpi_ut_create_integer_object(acpi_os_get_timer()); | |
1da177e4 LT |
70 | if (!return_desc) { |
71 | status = AE_NO_MEMORY; | |
72 | goto cleanup; | |
73 | } | |
1da177e4 LT |
74 | break; |
75 | ||
4be44fcd | 76 | default: /* Unknown opcode */ |
1da177e4 | 77 | |
f6a22b0b | 78 | ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
b8e4d893 | 79 | walk_state->opcode)); |
1da177e4 LT |
80 | status = AE_AML_BAD_OPCODE; |
81 | break; | |
82 | } | |
83 | ||
10622bf8 | 84 | cleanup: |
1da177e4 | 85 | |
1da177e4 LT |
86 | /* Delete return object on error */ |
87 | ||
4be44fcd LB |
88 | if ((ACPI_FAILURE(status)) || walk_state->result_obj) { |
89 | acpi_ut_remove_reference(return_desc); | |
4b6e16cf | 90 | walk_state->result_obj = NULL; |
4be44fcd | 91 | } else { |
88ac00f5 RM |
92 | /* Save the return value */ |
93 | ||
94 | walk_state->result_obj = return_desc; | |
95 | } | |
1da177e4 | 96 | |
4be44fcd | 97 | return_ACPI_STATUS(status); |
1da177e4 LT |
98 | } |
99 | ||
1da177e4 LT |
100 | /******************************************************************************* |
101 | * | |
102 | * FUNCTION: acpi_ex_opcode_1A_0T_0R | |
103 | * | |
104 | * PARAMETERS: walk_state - Current state (contains AML opcode) | |
105 | * | |
106 | * RETURN: Status | |
107 | * | |
108 | * DESCRIPTION: Execute Type 1 monadic operator with numeric operand on | |
109 | * object stack | |
110 | * | |
111 | ******************************************************************************/ | |
112 | ||
4be44fcd | 113 | acpi_status acpi_ex_opcode_1A_0T_0R(struct acpi_walk_state *walk_state) |
1da177e4 | 114 | { |
4be44fcd LB |
115 | union acpi_operand_object **operand = &walk_state->operands[0]; |
116 | acpi_status status = AE_OK; | |
1da177e4 | 117 | |
b229cf92 | 118 | ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_0R, |
4be44fcd | 119 | acpi_ps_get_opcode_name(walk_state->opcode)); |
1da177e4 LT |
120 | |
121 | /* Examine the AML opcode */ | |
122 | ||
123 | switch (walk_state->opcode) { | |
4be44fcd | 124 | case AML_RELEASE_OP: /* Release (mutex_object) */ |
1da177e4 | 125 | |
4be44fcd | 126 | status = acpi_ex_release_mutex(operand[0], walk_state); |
1da177e4 LT |
127 | break; |
128 | ||
4be44fcd | 129 | case AML_RESET_OP: /* Reset (event_object) */ |
1da177e4 | 130 | |
4be44fcd | 131 | status = acpi_ex_system_reset_event(operand[0]); |
1da177e4 LT |
132 | break; |
133 | ||
4be44fcd | 134 | case AML_SIGNAL_OP: /* Signal (event_object) */ |
1da177e4 | 135 | |
4be44fcd | 136 | status = acpi_ex_system_signal_event(operand[0]); |
1da177e4 LT |
137 | break; |
138 | ||
4be44fcd | 139 | case AML_SLEEP_OP: /* Sleep (msec_time) */ |
1da177e4 | 140 | |
ada241dc | 141 | status = acpi_ex_system_do_sleep(operand[0]->integer.value); |
1da177e4 LT |
142 | break; |
143 | ||
4be44fcd | 144 | case AML_STALL_OP: /* Stall (usec_time) */ |
1da177e4 | 145 | |
4be44fcd LB |
146 | status = |
147 | acpi_ex_system_do_stall((u32) operand[0]->integer.value); | |
1da177e4 LT |
148 | break; |
149 | ||
4be44fcd | 150 | case AML_UNLOAD_OP: /* Unload (Handle) */ |
1da177e4 | 151 | |
4be44fcd | 152 | status = acpi_ex_unload_table(operand[0]); |
1da177e4 LT |
153 | break; |
154 | ||
4be44fcd | 155 | default: /* Unknown opcode */ |
1da177e4 | 156 | |
f6a22b0b | 157 | ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
b8e4d893 | 158 | walk_state->opcode)); |
1da177e4 LT |
159 | status = AE_AML_BAD_OPCODE; |
160 | break; | |
161 | } | |
162 | ||
4be44fcd | 163 | return_ACPI_STATUS(status); |
1da177e4 LT |
164 | } |
165 | ||
1da177e4 LT |
166 | /******************************************************************************* |
167 | * | |
168 | * FUNCTION: acpi_ex_opcode_1A_1T_0R | |
169 | * | |
170 | * PARAMETERS: walk_state - Current state (contains AML opcode) | |
171 | * | |
172 | * RETURN: Status | |
173 | * | |
174 | * DESCRIPTION: Execute opcode with one argument, one target, and no | |
175 | * return value. | |
176 | * | |
177 | ******************************************************************************/ | |
178 | ||
4be44fcd | 179 | acpi_status acpi_ex_opcode_1A_1T_0R(struct acpi_walk_state *walk_state) |
1da177e4 | 180 | { |
4be44fcd LB |
181 | acpi_status status = AE_OK; |
182 | union acpi_operand_object **operand = &walk_state->operands[0]; | |
1da177e4 | 183 | |
b229cf92 | 184 | ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_0R, |
4be44fcd | 185 | acpi_ps_get_opcode_name(walk_state->opcode)); |
1da177e4 LT |
186 | |
187 | /* Examine the AML opcode */ | |
188 | ||
189 | switch (walk_state->opcode) { | |
190 | case AML_LOAD_OP: | |
191 | ||
4be44fcd | 192 | status = acpi_ex_load_op(operand[0], operand[1], walk_state); |
1da177e4 LT |
193 | break; |
194 | ||
4be44fcd | 195 | default: /* Unknown opcode */ |
1da177e4 | 196 | |
f6a22b0b | 197 | ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
b8e4d893 | 198 | walk_state->opcode)); |
1da177e4 LT |
199 | status = AE_AML_BAD_OPCODE; |
200 | goto cleanup; | |
201 | } | |
202 | ||
10622bf8 | 203 | cleanup: |
1da177e4 | 204 | |
4be44fcd | 205 | return_ACPI_STATUS(status); |
1da177e4 LT |
206 | } |
207 | ||
1da177e4 LT |
208 | /******************************************************************************* |
209 | * | |
210 | * FUNCTION: acpi_ex_opcode_1A_1T_1R | |
211 | * | |
212 | * PARAMETERS: walk_state - Current state (contains AML opcode) | |
213 | * | |
214 | * RETURN: Status | |
215 | * | |
216 | * DESCRIPTION: Execute opcode with one argument, one target, and a | |
217 | * return value. | |
218 | * | |
219 | ******************************************************************************/ | |
220 | ||
4be44fcd | 221 | acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) |
1da177e4 | 222 | { |
4be44fcd LB |
223 | acpi_status status = AE_OK; |
224 | union acpi_operand_object **operand = &walk_state->operands[0]; | |
225 | union acpi_operand_object *return_desc = NULL; | |
226 | union acpi_operand_object *return_desc2 = NULL; | |
227 | u32 temp32; | |
228 | u32 i; | |
5df7e6cb BM |
229 | u64 power_of_ten; |
230 | u64 digit; | |
4be44fcd | 231 | |
b229cf92 | 232 | ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_1R, |
4be44fcd | 233 | acpi_ps_get_opcode_name(walk_state->opcode)); |
1da177e4 LT |
234 | |
235 | /* Examine the AML opcode */ | |
236 | ||
237 | switch (walk_state->opcode) { | |
238 | case AML_BIT_NOT_OP: | |
239 | case AML_FIND_SET_LEFT_BIT_OP: | |
240 | case AML_FIND_SET_RIGHT_BIT_OP: | |
241 | case AML_FROM_BCD_OP: | |
242 | case AML_TO_BCD_OP: | |
9ff5a21a | 243 | case AML_CONDITIONAL_REF_OF_OP: |
1da177e4 LT |
244 | |
245 | /* Create a return object of type Integer for these opcodes */ | |
246 | ||
4be44fcd | 247 | return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
1da177e4 LT |
248 | if (!return_desc) { |
249 | status = AE_NO_MEMORY; | |
250 | goto cleanup; | |
251 | } | |
252 | ||
253 | switch (walk_state->opcode) { | |
4be44fcd | 254 | case AML_BIT_NOT_OP: /* Not (Operand, Result) */ |
1da177e4 LT |
255 | |
256 | return_desc->integer.value = ~operand[0]->integer.value; | |
257 | break; | |
258 | ||
4be44fcd | 259 | case AML_FIND_SET_LEFT_BIT_OP: /* find_set_left_bit (Operand, Result) */ |
1da177e4 LT |
260 | |
261 | return_desc->integer.value = operand[0]->integer.value; | |
262 | ||
263 | /* | |
264 | * Acpi specification describes Integer type as a little | |
265 | * endian unsigned value, so this boundary condition is valid. | |
266 | */ | |
267 | for (temp32 = 0; return_desc->integer.value && | |
4be44fcd | 268 | temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { |
1da177e4 LT |
269 | return_desc->integer.value >>= 1; |
270 | } | |
271 | ||
272 | return_desc->integer.value = temp32; | |
273 | break; | |
274 | ||
4be44fcd | 275 | case AML_FIND_SET_RIGHT_BIT_OP: /* find_set_right_bit (Operand, Result) */ |
1da177e4 LT |
276 | |
277 | return_desc->integer.value = operand[0]->integer.value; | |
278 | ||
279 | /* | |
280 | * The Acpi specification describes Integer type as a little | |
281 | * endian unsigned value, so this boundary condition is valid. | |
282 | */ | |
283 | for (temp32 = 0; return_desc->integer.value && | |
4be44fcd | 284 | temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { |
1da177e4 LT |
285 | return_desc->integer.value <<= 1; |
286 | } | |
287 | ||
288 | /* Since the bit position is one-based, subtract from 33 (65) */ | |
289 | ||
4c90ece2 BM |
290 | return_desc->integer.value = |
291 | temp32 == | |
292 | 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - temp32; | |
1da177e4 LT |
293 | break; |
294 | ||
4be44fcd | 295 | case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */ |
1da177e4 LT |
296 | /* |
297 | * The 64-bit ACPI integer can hold 16 4-bit BCD characters | |
298 | * (if table is 32-bit, integer can hold 8 BCD characters) | |
299 | * Convert each 4-bit BCD value | |
300 | */ | |
301 | power_of_ten = 1; | |
302 | return_desc->integer.value = 0; | |
303 | digit = operand[0]->integer.value; | |
304 | ||
305 | /* Convert each BCD digit (each is one nybble wide) */ | |
306 | ||
4be44fcd LB |
307 | for (i = 0; |
308 | (i < acpi_gbl_integer_nybble_width) && (digit > 0); | |
309 | i++) { | |
52fc0b02 | 310 | |
1da177e4 LT |
311 | /* Get the least significant 4-bit BCD digit */ |
312 | ||
313 | temp32 = ((u32) digit) & 0xF; | |
314 | ||
315 | /* Check the range of the digit */ | |
316 | ||
317 | if (temp32 > 9) { | |
b8e4d893 BM |
318 | ACPI_ERROR((AE_INFO, |
319 | "BCD digit too large (not decimal): 0x%X", | |
320 | temp32)); | |
1da177e4 LT |
321 | |
322 | status = AE_AML_NUMERIC_OVERFLOW; | |
323 | goto cleanup; | |
324 | } | |
325 | ||
326 | /* Sum the digit into the result with the current power of 10 */ | |
327 | ||
4be44fcd | 328 | return_desc->integer.value += |
5df7e6cb | 329 | (((u64) temp32) * power_of_ten); |
1da177e4 LT |
330 | |
331 | /* Shift to next BCD digit */ | |
332 | ||
333 | digit >>= 4; | |
334 | ||
335 | /* Next power of 10 */ | |
336 | ||
337 | power_of_ten *= 10; | |
338 | } | |
339 | break; | |
340 | ||
4be44fcd | 341 | case AML_TO_BCD_OP: /* to_bcd (Operand, Result) */ |
1da177e4 LT |
342 | |
343 | return_desc->integer.value = 0; | |
344 | digit = operand[0]->integer.value; | |
345 | ||
346 | /* Each BCD digit is one nybble wide */ | |
347 | ||
4be44fcd LB |
348 | for (i = 0; |
349 | (i < acpi_gbl_integer_nybble_width) && (digit > 0); | |
350 | i++) { | |
351 | (void)acpi_ut_short_divide(digit, 10, &digit, | |
352 | &temp32); | |
1da177e4 | 353 | |
44f6c012 RM |
354 | /* |
355 | * Insert the BCD digit that resides in the | |
356 | * remainder from above | |
357 | */ | |
4be44fcd | 358 | return_desc->integer.value |= |
5df7e6cb | 359 | (((u64) temp32) << ACPI_MUL_4(i)); |
1da177e4 LT |
360 | } |
361 | ||
362 | /* Overflow if there is any data left in Digit */ | |
363 | ||
364 | if (digit > 0) { | |
b8e4d893 | 365 | ACPI_ERROR((AE_INFO, |
f6a22b0b | 366 | "Integer too large to convert to BCD: 0x%8.8X%8.8X", |
b8e4d893 BM |
367 | ACPI_FORMAT_UINT64(operand[0]-> |
368 | integer.value))); | |
1da177e4 LT |
369 | status = AE_AML_NUMERIC_OVERFLOW; |
370 | goto cleanup; | |
371 | } | |
372 | break; | |
373 | ||
9ff5a21a | 374 | case AML_CONDITIONAL_REF_OF_OP: /* cond_ref_of (source_object, Result) */ |
1da177e4 LT |
375 | /* |
376 | * This op is a little strange because the internal return value is | |
377 | * different than the return value stored in the result descriptor | |
378 | * (There are really two return values) | |
379 | */ | |
4be44fcd LB |
380 | if ((struct acpi_namespace_node *)operand[0] == |
381 | acpi_gbl_root_node) { | |
1da177e4 LT |
382 | /* |
383 | * This means that the object does not exist in the namespace, | |
384 | * return FALSE | |
385 | */ | |
386 | return_desc->integer.value = 0; | |
387 | goto cleanup; | |
388 | } | |
389 | ||
390 | /* Get the object reference, store it, and remove our reference */ | |
391 | ||
4be44fcd LB |
392 | status = acpi_ex_get_object_reference(operand[0], |
393 | &return_desc2, | |
394 | walk_state); | |
395 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
396 | goto cleanup; |
397 | } | |
398 | ||
4be44fcd LB |
399 | status = |
400 | acpi_ex_store(return_desc2, operand[1], walk_state); | |
401 | acpi_ut_remove_reference(return_desc2); | |
1da177e4 LT |
402 | |
403 | /* The object exists in the namespace, return TRUE */ | |
404 | ||
5df7e6cb | 405 | return_desc->integer.value = ACPI_UINT64_MAX; |
1da177e4 LT |
406 | goto cleanup; |
407 | ||
1da177e4 | 408 | default: |
1d1ea1b7 | 409 | |
1da177e4 | 410 | /* No other opcodes get here */ |
1d1ea1b7 | 411 | |
1da177e4 LT |
412 | break; |
413 | } | |
414 | break; | |
415 | ||
4be44fcd | 416 | case AML_STORE_OP: /* Store (Source, Target) */ |
1da177e4 LT |
417 | /* |
418 | * A store operand is typically a number, string, buffer or lvalue | |
419 | * Be careful about deleting the source object, | |
420 | * since the object itself may have been stored. | |
421 | */ | |
4be44fcd LB |
422 | status = acpi_ex_store(operand[0], operand[1], walk_state); |
423 | if (ACPI_FAILURE(status)) { | |
424 | return_ACPI_STATUS(status); | |
1da177e4 LT |
425 | } |
426 | ||
427 | /* It is possible that the Store already produced a return object */ | |
428 | ||
429 | if (!walk_state->result_obj) { | |
430 | /* | |
44f6c012 RM |
431 | * Normally, we would remove a reference on the Operand[0] |
432 | * parameter; But since it is being used as the internal return | |
433 | * object (meaning we would normally increment it), the two | |
434 | * cancel out, and we simply don't do anything. | |
1da177e4 LT |
435 | */ |
436 | walk_state->result_obj = operand[0]; | |
4be44fcd | 437 | walk_state->operands[0] = NULL; /* Prevent deletion */ |
1da177e4 | 438 | } |
4be44fcd | 439 | return_ACPI_STATUS(status); |
1da177e4 | 440 | |
4be44fcd LB |
441 | /* |
442 | * ACPI 2.0 Opcodes | |
443 | */ | |
9ff5a21a | 444 | case AML_COPY_OBJECT_OP: /* copy_object (Source, Target) */ |
1da177e4 | 445 | |
4be44fcd LB |
446 | status = |
447 | acpi_ut_copy_iobject_to_iobject(operand[0], &return_desc, | |
448 | walk_state); | |
1da177e4 LT |
449 | break; |
450 | ||
9ff5a21a | 451 | case AML_TO_DECIMAL_STRING_OP: /* to_decimal_string (Data, Result) */ |
1da177e4 | 452 | |
1fad8738 BM |
453 | status = |
454 | acpi_ex_convert_to_string(operand[0], &return_desc, | |
455 | ACPI_EXPLICIT_CONVERT_DECIMAL); | |
1da177e4 | 456 | if (return_desc == operand[0]) { |
52fc0b02 | 457 | |
1da177e4 | 458 | /* No conversion performed, add ref to handle return value */ |
1fad8738 | 459 | |
4be44fcd | 460 | acpi_ut_add_reference(return_desc); |
1da177e4 LT |
461 | } |
462 | break; | |
463 | ||
9ff5a21a | 464 | case AML_TO_HEX_STRING_OP: /* to_hex_string (Data, Result) */ |
1da177e4 | 465 | |
1fad8738 BM |
466 | status = |
467 | acpi_ex_convert_to_string(operand[0], &return_desc, | |
468 | ACPI_EXPLICIT_CONVERT_HEX); | |
1da177e4 | 469 | if (return_desc == operand[0]) { |
52fc0b02 | 470 | |
1da177e4 | 471 | /* No conversion performed, add ref to handle return value */ |
1fad8738 | 472 | |
4be44fcd | 473 | acpi_ut_add_reference(return_desc); |
1da177e4 LT |
474 | } |
475 | break; | |
476 | ||
4be44fcd | 477 | case AML_TO_BUFFER_OP: /* to_buffer (Data, Result) */ |
1da177e4 | 478 | |
4be44fcd | 479 | status = acpi_ex_convert_to_buffer(operand[0], &return_desc); |
1da177e4 | 480 | if (return_desc == operand[0]) { |
52fc0b02 | 481 | |
1da177e4 | 482 | /* No conversion performed, add ref to handle return value */ |
1fad8738 | 483 | |
4be44fcd | 484 | acpi_ut_add_reference(return_desc); |
1da177e4 LT |
485 | } |
486 | break; | |
487 | ||
4be44fcd | 488 | case AML_TO_INTEGER_OP: /* to_integer (Data, Result) */ |
1da177e4 | 489 | |
5ebd2eaa BM |
490 | /* Perform "explicit" conversion */ |
491 | ||
1fad8738 | 492 | status = |
5ebd2eaa | 493 | acpi_ex_convert_to_integer(operand[0], &return_desc, 0); |
1da177e4 | 494 | if (return_desc == operand[0]) { |
52fc0b02 | 495 | |
1da177e4 | 496 | /* No conversion performed, add ref to handle return value */ |
1fad8738 | 497 | |
4be44fcd | 498 | acpi_ut_add_reference(return_desc); |
1da177e4 LT |
499 | } |
500 | break; | |
501 | ||
4be44fcd LB |
502 | case AML_SHIFT_LEFT_BIT_OP: /* shift_left_bit (Source, bit_num) */ |
503 | case AML_SHIFT_RIGHT_BIT_OP: /* shift_right_bit (Source, bit_num) */ | |
1da177e4 | 504 | |
44f6c012 RM |
505 | /* These are two obsolete opcodes */ |
506 | ||
b8e4d893 BM |
507 | ACPI_ERROR((AE_INFO, |
508 | "%s is obsolete and not implemented", | |
509 | acpi_ps_get_opcode_name(walk_state->opcode))); | |
1da177e4 LT |
510 | status = AE_SUPPORT; |
511 | goto cleanup; | |
512 | ||
4be44fcd | 513 | default: /* Unknown opcode */ |
1da177e4 | 514 | |
f6a22b0b | 515 | ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
b8e4d893 | 516 | walk_state->opcode)); |
1da177e4 LT |
517 | status = AE_AML_BAD_OPCODE; |
518 | goto cleanup; | |
519 | } | |
520 | ||
4be44fcd | 521 | if (ACPI_SUCCESS(status)) { |
52fc0b02 | 522 | |
44f6c012 RM |
523 | /* Store the return value computed above into the target object */ |
524 | ||
4be44fcd | 525 | status = acpi_ex_store(return_desc, operand[1], walk_state); |
1da177e4 LT |
526 | } |
527 | ||
10622bf8 | 528 | cleanup: |
1da177e4 | 529 | |
1da177e4 LT |
530 | /* Delete return object on error */ |
531 | ||
4be44fcd LB |
532 | if (ACPI_FAILURE(status)) { |
533 | acpi_ut_remove_reference(return_desc); | |
1da177e4 LT |
534 | } |
535 | ||
8313524a BM |
536 | /* Save return object on success */ |
537 | ||
538 | else if (!walk_state->result_obj) { | |
539 | walk_state->result_obj = return_desc; | |
540 | } | |
541 | ||
4be44fcd | 542 | return_ACPI_STATUS(status); |
1da177e4 LT |
543 | } |
544 | ||
1da177e4 LT |
545 | /******************************************************************************* |
546 | * | |
547 | * FUNCTION: acpi_ex_opcode_1A_0T_1R | |
548 | * | |
549 | * PARAMETERS: walk_state - Current state (contains AML opcode) | |
550 | * | |
551 | * RETURN: Status | |
552 | * | |
553 | * DESCRIPTION: Execute opcode with one argument, no target, and a return value | |
554 | * | |
555 | ******************************************************************************/ | |
556 | ||
4be44fcd | 557 | acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) |
1da177e4 | 558 | { |
4be44fcd LB |
559 | union acpi_operand_object **operand = &walk_state->operands[0]; |
560 | union acpi_operand_object *temp_desc; | |
561 | union acpi_operand_object *return_desc = NULL; | |
562 | acpi_status status = AE_OK; | |
563 | u32 type; | |
5df7e6cb | 564 | u64 value; |
1da177e4 | 565 | |
b229cf92 | 566 | ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_1R, |
4be44fcd | 567 | acpi_ps_get_opcode_name(walk_state->opcode)); |
1da177e4 LT |
568 | |
569 | /* Examine the AML opcode */ | |
570 | ||
571 | switch (walk_state->opcode) { | |
9ff5a21a | 572 | case AML_LOGICAL_NOT_OP: /* LNot (Operand) */ |
1da177e4 | 573 | |
dc95a270 | 574 | return_desc = acpi_ut_create_integer_object((u64) 0); |
1da177e4 LT |
575 | if (!return_desc) { |
576 | status = AE_NO_MEMORY; | |
577 | goto cleanup; | |
578 | } | |
579 | ||
580 | /* | |
73a3090a | 581 | * Set result to ONES (TRUE) if Value == 0. Note: |
1da177e4 LT |
582 | * return_desc->Integer.Value is initially == 0 (FALSE) from above. |
583 | */ | |
584 | if (!operand[0]->integer.value) { | |
5df7e6cb | 585 | return_desc->integer.value = ACPI_UINT64_MAX; |
1da177e4 LT |
586 | } |
587 | break; | |
588 | ||
4be44fcd LB |
589 | case AML_DECREMENT_OP: /* Decrement (Operand) */ |
590 | case AML_INCREMENT_OP: /* Increment (Operand) */ | |
1da177e4 | 591 | /* |
73a3090a | 592 | * Create a new integer. Can't just get the base integer and |
1da177e4 LT |
593 | * increment it because it may be an Arg or Field. |
594 | */ | |
4be44fcd | 595 | return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); |
1da177e4 LT |
596 | if (!return_desc) { |
597 | status = AE_NO_MEMORY; | |
598 | goto cleanup; | |
599 | } | |
600 | ||
601 | /* | |
602 | * Since we are expecting a Reference operand, it can be either a | |
603 | * NS Node or an internal object. | |
604 | */ | |
605 | temp_desc = operand[0]; | |
4be44fcd LB |
606 | if (ACPI_GET_DESCRIPTOR_TYPE(temp_desc) == |
607 | ACPI_DESC_TYPE_OPERAND) { | |
52fc0b02 | 608 | |
1da177e4 LT |
609 | /* Internal reference object - prevent deletion */ |
610 | ||
4be44fcd | 611 | acpi_ut_add_reference(temp_desc); |
1da177e4 LT |
612 | } |
613 | ||
614 | /* | |
615 | * Convert the Reference operand to an Integer (This removes a | |
616 | * reference on the Operand[0] object) | |
617 | * | |
618 | * NOTE: We use LNOT_OP here in order to force resolution of the | |
619 | * reference operand to an actual integer. | |
620 | */ | |
9ff5a21a BM |
621 | status = acpi_ex_resolve_operands(AML_LOGICAL_NOT_OP, |
622 | &temp_desc, walk_state); | |
4be44fcd | 623 | if (ACPI_FAILURE(status)) { |
b8e4d893 BM |
624 | ACPI_EXCEPTION((AE_INFO, status, |
625 | "While resolving operands for [%s]", | |
626 | acpi_ps_get_opcode_name(walk_state-> | |
627 | opcode))); | |
1da177e4 LT |
628 | |
629 | goto cleanup; | |
630 | } | |
631 | ||
632 | /* | |
633 | * temp_desc is now guaranteed to be an Integer object -- | |
634 | * Perform the actual increment or decrement | |
635 | */ | |
636 | if (walk_state->opcode == AML_INCREMENT_OP) { | |
4be44fcd LB |
637 | return_desc->integer.value = |
638 | temp_desc->integer.value + 1; | |
639 | } else { | |
640 | return_desc->integer.value = | |
641 | temp_desc->integer.value - 1; | |
1da177e4 LT |
642 | } |
643 | ||
644 | /* Finished with this Integer object */ | |
645 | ||
4be44fcd | 646 | acpi_ut_remove_reference(temp_desc); |
1da177e4 LT |
647 | |
648 | /* | |
649 | * Store the result back (indirectly) through the original | |
650 | * Reference object | |
651 | */ | |
4be44fcd | 652 | status = acpi_ex_store(return_desc, operand[0], walk_state); |
1da177e4 LT |
653 | break; |
654 | ||
f70008d3 | 655 | case AML_OBJECT_TYPE_OP: /* object_type (source_object) */ |
1da177e4 LT |
656 | /* |
657 | * Note: The operand is not resolved at this point because we want to | |
73a3090a | 658 | * get the associated object, not its value. For example, we don't |
44f6c012 RM |
659 | * want to resolve a field_unit to its value, we want the actual |
660 | * field_unit object. | |
1da177e4 LT |
661 | */ |
662 | ||
663 | /* Get the type of the base object */ | |
664 | ||
4be44fcd LB |
665 | status = |
666 | acpi_ex_resolve_multiple(walk_state, operand[0], &type, | |
667 | NULL); | |
668 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
669 | goto cleanup; |
670 | } | |
4c90ece2 | 671 | |
1da177e4 LT |
672 | /* Allocate a descriptor to hold the type. */ |
673 | ||
dc95a270 | 674 | return_desc = acpi_ut_create_integer_object((u64) type); |
1da177e4 LT |
675 | if (!return_desc) { |
676 | status = AE_NO_MEMORY; | |
677 | goto cleanup; | |
678 | } | |
1da177e4 LT |
679 | break; |
680 | ||
4be44fcd | 681 | case AML_SIZE_OF_OP: /* size_of (source_object) */ |
1da177e4 LT |
682 | /* |
683 | * Note: The operand is not resolved at this point because we want to | |
684 | * get the associated object, not its value. | |
685 | */ | |
686 | ||
687 | /* Get the base object */ | |
688 | ||
1fad8738 BM |
689 | status = |
690 | acpi_ex_resolve_multiple(walk_state, operand[0], &type, | |
691 | &temp_desc); | |
4be44fcd | 692 | if (ACPI_FAILURE(status)) { |
1da177e4 LT |
693 | goto cleanup; |
694 | } | |
695 | ||
696 | /* | |
697 | * The type of the base object must be integer, buffer, string, or | |
73a3090a | 698 | * package. All others are not supported. |
1da177e4 LT |
699 | * |
700 | * NOTE: Integer is not specifically supported by the ACPI spec, | |
701 | * but is supported implicitly via implicit operand conversion. | |
702 | * rather than bother with conversion, we just use the byte width | |
703 | * global (4 or 8 bytes). | |
704 | */ | |
705 | switch (type) { | |
706 | case ACPI_TYPE_INTEGER: | |
1d1ea1b7 | 707 | |
1da177e4 LT |
708 | value = acpi_gbl_integer_byte_width; |
709 | break; | |
710 | ||
1da177e4 | 711 | case ACPI_TYPE_STRING: |
1d1ea1b7 | 712 | |
1da177e4 LT |
713 | value = temp_desc->string.length; |
714 | break; | |
715 | ||
8246934b LM |
716 | case ACPI_TYPE_BUFFER: |
717 | ||
718 | /* Buffer arguments may not be evaluated at this point */ | |
719 | ||
720 | status = acpi_ds_get_buffer_arguments(temp_desc); | |
721 | value = temp_desc->buffer.length; | |
722 | break; | |
723 | ||
1da177e4 | 724 | case ACPI_TYPE_PACKAGE: |
8246934b LM |
725 | |
726 | /* Package arguments may not be evaluated at this point */ | |
727 | ||
728 | status = acpi_ds_get_package_arguments(temp_desc); | |
1da177e4 LT |
729 | value = temp_desc->package.count; |
730 | break; | |
731 | ||
732 | default: | |
1d1ea1b7 | 733 | |
b8e4d893 | 734 | ACPI_ERROR((AE_INFO, |
1fad8738 BM |
735 | "Operand must be Buffer/Integer/String/Package" |
736 | " - found type %s", | |
b8e4d893 | 737 | acpi_ut_get_type_name(type))); |
1fad8738 | 738 | |
1da177e4 LT |
739 | status = AE_AML_OPERAND_TYPE; |
740 | goto cleanup; | |
741 | } | |
742 | ||
8246934b LM |
743 | if (ACPI_FAILURE(status)) { |
744 | goto cleanup; | |
745 | } | |
746 | ||
1da177e4 LT |
747 | /* |
748 | * Now that we have the size of the object, create a result | |
749 | * object to hold the value | |
750 | */ | |
dc95a270 | 751 | return_desc = acpi_ut_create_integer_object(value); |
1da177e4 LT |
752 | if (!return_desc) { |
753 | status = AE_NO_MEMORY; | |
754 | goto cleanup; | |
755 | } | |
1da177e4 LT |
756 | break; |
757 | ||
4be44fcd | 758 | case AML_REF_OF_OP: /* ref_of (source_object) */ |
1da177e4 | 759 | |
4be44fcd LB |
760 | status = |
761 | acpi_ex_get_object_reference(operand[0], &return_desc, | |
762 | walk_state); | |
763 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
764 | goto cleanup; |
765 | } | |
766 | break; | |
767 | ||
4be44fcd | 768 | case AML_DEREF_OF_OP: /* deref_of (obj_reference | String) */ |
1da177e4 LT |
769 | |
770 | /* Check for a method local or argument, or standalone String */ | |
771 | ||
52fc0b02 | 772 | if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) == |
4be44fcd | 773 | ACPI_DESC_TYPE_NAMED) { |
52fc0b02 BM |
774 | temp_desc = |
775 | acpi_ns_get_attached_object((struct | |
776 | acpi_namespace_node *) | |
777 | operand[0]); | |
778 | if (temp_desc | |
3371c19c BM |
779 | && ((temp_desc->common.type == ACPI_TYPE_STRING) |
780 | || (temp_desc->common.type == | |
781 | ACPI_TYPE_LOCAL_REFERENCE))) { | |
52fc0b02 BM |
782 | operand[0] = temp_desc; |
783 | acpi_ut_add_reference(temp_desc); | |
784 | } else { | |
785 | status = AE_AML_OPERAND_TYPE; | |
786 | goto cleanup; | |
787 | } | |
788 | } else { | |
3371c19c | 789 | switch ((operand[0])->common.type) { |
1da177e4 LT |
790 | case ACPI_TYPE_LOCAL_REFERENCE: |
791 | /* | |
792 | * This is a deref_of (local_x | arg_x) | |
793 | * | |
794 | * Must resolve/dereference the local/arg reference first | |
795 | */ | |
1044f1f6 BM |
796 | switch (operand[0]->reference.class) { |
797 | case ACPI_REFCLASS_LOCAL: | |
798 | case ACPI_REFCLASS_ARG: | |
1da177e4 LT |
799 | |
800 | /* Set Operand[0] to the value of the local/arg */ | |
801 | ||
4be44fcd LB |
802 | status = |
803 | acpi_ds_method_data_get_value | |
1044f1f6 BM |
804 | (operand[0]->reference.class, |
805 | operand[0]->reference.value, | |
4be44fcd LB |
806 | walk_state, &temp_desc); |
807 | if (ACPI_FAILURE(status)) { | |
1da177e4 LT |
808 | goto cleanup; |
809 | } | |
810 | ||
811 | /* | |
812 | * Delete our reference to the input object and | |
813 | * point to the object just retrieved | |
814 | */ | |
4be44fcd | 815 | acpi_ut_remove_reference(operand[0]); |
1da177e4 LT |
816 | operand[0] = temp_desc; |
817 | break; | |
818 | ||
1044f1f6 | 819 | case ACPI_REFCLASS_REFOF: |
1da177e4 LT |
820 | |
821 | /* Get the object to which the reference refers */ | |
822 | ||
4be44fcd LB |
823 | temp_desc = |
824 | operand[0]->reference.object; | |
825 | acpi_ut_remove_reference(operand[0]); | |
1da177e4 LT |
826 | operand[0] = temp_desc; |
827 | break; | |
828 | ||
829 | default: | |
830 | ||
831 | /* Must be an Index op - handled below */ | |
832 | break; | |
833 | } | |
834 | break; | |
835 | ||
1da177e4 | 836 | case ACPI_TYPE_STRING: |
1d1ea1b7 | 837 | |
52fc0b02 | 838 | break; |
1da177e4 | 839 | |
52fc0b02 | 840 | default: |
1d1ea1b7 | 841 | |
52fc0b02 BM |
842 | status = AE_AML_OPERAND_TYPE; |
843 | goto cleanup; | |
844 | } | |
845 | } | |
846 | ||
847 | if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) != | |
848 | ACPI_DESC_TYPE_NAMED) { | |
3371c19c | 849 | if ((operand[0])->common.type == ACPI_TYPE_STRING) { |
1da177e4 | 850 | /* |
44f6c012 RM |
851 | * This is a deref_of (String). The string is a reference |
852 | * to a named ACPI object. | |
1da177e4 LT |
853 | * |
854 | * 1) Find the owning Node | |
52fc0b02 | 855 | * 2) Dereference the node to an actual object. Could be a |
44f6c012 | 856 | * Field, so we need to resolve the node to a value. |
1da177e4 | 857 | */ |
4be44fcd | 858 | status = |
74f51b80 LZ |
859 | acpi_ns_get_node_unlocked(walk_state-> |
860 | scope_info->scope. | |
861 | node, | |
862 | operand[0]-> | |
863 | string.pointer, | |
864 | ACPI_NS_SEARCH_PARENT, | |
865 | ACPI_CAST_INDIRECT_PTR | |
866 | (struct | |
867 | acpi_namespace_node, | |
868 | &return_desc)); | |
4be44fcd | 869 | if (ACPI_FAILURE(status)) { |
1da177e4 LT |
870 | goto cleanup; |
871 | } | |
872 | ||
4be44fcd LB |
873 | status = |
874 | acpi_ex_resolve_node_to_value | |
875 | (ACPI_CAST_INDIRECT_PTR | |
876 | (struct acpi_namespace_node, &return_desc), | |
877 | walk_state); | |
1da177e4 | 878 | goto cleanup; |
1da177e4 LT |
879 | } |
880 | } | |
881 | ||
882 | /* Operand[0] may have changed from the code above */ | |
883 | ||
4be44fcd LB |
884 | if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) == |
885 | ACPI_DESC_TYPE_NAMED) { | |
1da177e4 LT |
886 | /* |
887 | * This is a deref_of (object_reference) | |
888 | * Get the actual object from the Node (This is the dereference). | |
44f6c012 | 889 | * This case may only happen when a local_x or arg_x is |
1d6e9cfa BM |
890 | * dereferenced above, or for references to device and |
891 | * thermal objects. | |
1da177e4 | 892 | */ |
1d6e9cfa BM |
893 | switch (((struct acpi_namespace_node *)operand[0])-> |
894 | type) { | |
895 | case ACPI_TYPE_DEVICE: | |
896 | case ACPI_TYPE_THERMAL: | |
897 | ||
898 | /* These types have no node subobject, return the NS node */ | |
899 | ||
900 | return_desc = operand[0]; | |
901 | break; | |
902 | ||
903 | default: | |
904 | /* For most types, get the object attached to the node */ | |
905 | ||
906 | return_desc = acpi_ns_get_attached_object((struct acpi_namespace_node *)operand[0]); | |
907 | acpi_ut_add_reference(return_desc); | |
908 | break; | |
909 | } | |
4be44fcd | 910 | } else { |
1da177e4 | 911 | /* |
44f6c012 RM |
912 | * This must be a reference object produced by either the |
913 | * Index() or ref_of() operator | |
1da177e4 | 914 | */ |
1044f1f6 BM |
915 | switch (operand[0]->reference.class) { |
916 | case ACPI_REFCLASS_INDEX: | |
1da177e4 LT |
917 | /* |
918 | * The target type for the Index operator must be | |
919 | * either a Buffer or a Package | |
920 | */ | |
921 | switch (operand[0]->reference.target_type) { | |
922 | case ACPI_TYPE_BUFFER_FIELD: | |
923 | ||
4be44fcd LB |
924 | temp_desc = |
925 | operand[0]->reference.object; | |
1da177e4 LT |
926 | |
927 | /* | |
928 | * Create a new object that contains one element of the | |
929 | * buffer -- the element pointed to by the index. | |
930 | * | |
931 | * NOTE: index into a buffer is NOT a pointer to a | |
932 | * sub-buffer of the main buffer, it is only a pointer to a | |
933 | * single element (byte) of the buffer! | |
dc95a270 BM |
934 | * |
935 | * Since we are returning the value of the buffer at the | |
936 | * indexed location, we don't need to add an additional | |
937 | * reference to the buffer itself. | |
1da177e4 | 938 | */ |
4be44fcd | 939 | return_desc = |
dc95a270 | 940 | acpi_ut_create_integer_object((u64) |
3e8214e5 | 941 | temp_desc->buffer.pointer[operand[0]->reference.value]); |
1da177e4 LT |
942 | if (!return_desc) { |
943 | status = AE_NO_MEMORY; | |
944 | goto cleanup; | |
945 | } | |
1da177e4 LT |
946 | break; |
947 | ||
1da177e4 | 948 | case ACPI_TYPE_PACKAGE: |
1da177e4 | 949 | /* |
73a3090a | 950 | * Return the referenced element of the package. We must |
44f6c012 | 951 | * add another reference to the referenced object, however. |
1da177e4 | 952 | */ |
4be44fcd LB |
953 | return_desc = |
954 | *(operand[0]->reference.where); | |
a50abf48 BM |
955 | if (!return_desc) { |
956 | /* | |
957 | * Element is NULL, do not allow the dereference. | |
958 | * This provides compatibility with other ACPI | |
959 | * implementations. | |
960 | */ | |
961 | return_ACPI_STATUS | |
962 | (AE_AML_UNINITIALIZED_ELEMENT); | |
1da177e4 | 963 | } |
a50abf48 BM |
964 | |
965 | acpi_ut_add_reference(return_desc); | |
1da177e4 LT |
966 | break; |
967 | ||
1da177e4 LT |
968 | default: |
969 | ||
b8e4d893 | 970 | ACPI_ERROR((AE_INFO, |
f6a22b0b | 971 | "Unknown Index TargetType 0x%X in reference object %p", |
b8e4d893 BM |
972 | operand[0]->reference. |
973 | target_type, operand[0])); | |
1fad8738 | 974 | |
1da177e4 LT |
975 | status = AE_AML_OPERAND_TYPE; |
976 | goto cleanup; | |
977 | } | |
978 | break; | |
979 | ||
1044f1f6 | 980 | case ACPI_REFCLASS_REFOF: |
1da177e4 LT |
981 | |
982 | return_desc = operand[0]->reference.object; | |
983 | ||
4be44fcd LB |
984 | if (ACPI_GET_DESCRIPTOR_TYPE(return_desc) == |
985 | ACPI_DESC_TYPE_NAMED) { | |
4be44fcd LB |
986 | return_desc = |
987 | acpi_ns_get_attached_object((struct | |
988 | acpi_namespace_node | |
989 | *) | |
990 | return_desc); | |
63660e05 BM |
991 | if (!return_desc) { |
992 | break; | |
993 | } | |
994 | ||
995 | /* | |
996 | * June 2013: | |
997 | * buffer_fields/field_units require additional resolution | |
998 | */ | |
999 | switch (return_desc->common.type) { | |
1000 | case ACPI_TYPE_BUFFER_FIELD: | |
1001 | case ACPI_TYPE_LOCAL_REGION_FIELD: | |
1002 | case ACPI_TYPE_LOCAL_BANK_FIELD: | |
1003 | case ACPI_TYPE_LOCAL_INDEX_FIELD: | |
1004 | ||
1005 | status = | |
1006 | acpi_ex_read_data_from_field | |
1007 | (walk_state, return_desc, | |
1008 | &temp_desc); | |
1009 | if (ACPI_FAILURE(status)) { | |
1010 | goto cleanup; | |
1011 | } | |
1da177e4 | 1012 | |
63660e05 BM |
1013 | return_desc = temp_desc; |
1014 | break; | |
1da177e4 | 1015 | |
63660e05 BM |
1016 | default: |
1017 | ||
1018 | /* Add another reference to the object */ | |
1019 | ||
1020 | acpi_ut_add_reference | |
1021 | (return_desc); | |
1022 | break; | |
1023 | } | |
1024 | } | |
1da177e4 LT |
1025 | break; |
1026 | ||
1da177e4 | 1027 | default: |
1d1ea1b7 | 1028 | |
b8e4d893 | 1029 | ACPI_ERROR((AE_INFO, |
f6a22b0b | 1030 | "Unknown class in reference(%p) - 0x%2.2X", |
b8e4d893 | 1031 | operand[0], |
1044f1f6 | 1032 | operand[0]->reference.class)); |
1da177e4 LT |
1033 | |
1034 | status = AE_TYPE; | |
1035 | goto cleanup; | |
1036 | } | |
1037 | } | |
1038 | break; | |
1039 | ||
1da177e4 LT |
1040 | default: |
1041 | ||
f6a22b0b | 1042 | ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", |
b8e4d893 | 1043 | walk_state->opcode)); |
1fad8738 | 1044 | |
1da177e4 LT |
1045 | status = AE_AML_BAD_OPCODE; |
1046 | goto cleanup; | |
1047 | } | |
1048 | ||
10622bf8 | 1049 | cleanup: |
1da177e4 LT |
1050 | |
1051 | /* Delete return object on error */ | |
1052 | ||
4be44fcd LB |
1053 | if (ACPI_FAILURE(status)) { |
1054 | acpi_ut_remove_reference(return_desc); | |
1da177e4 LT |
1055 | } |
1056 | ||
8313524a BM |
1057 | /* Save return object on success */ |
1058 | ||
1059 | else { | |
1060 | walk_state->result_obj = return_desc; | |
1061 | } | |
1062 | ||
4be44fcd | 1063 | return_ACPI_STATUS(status); |
1da177e4 | 1064 | } |