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