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