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