1 | /****************************************************************************** |
2 | * |
3 | * Module Name: exoparg2 - AML execution - opcodes with 2 arguments |
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 "acinterp.h" |
48 | #include "acevents.h" |
49 | #include "amlcode.h" |
50 | |
51 | |
52 | #define _COMPONENT ACPI_EXECUTER |
53 | ACPI_MODULE_NAME ("exoparg2" ) |
54 | |
55 | |
56 | /*! |
57 | * Naming convention for AML interpreter execution routines. |
58 | * |
59 | * The routines that begin execution of AML opcodes are named with a common |
60 | * convention based upon the number of arguments, the number of target operands, |
61 | * and whether or not a value is returned: |
62 | * |
63 | * AcpiExOpcode_xA_yT_zR |
64 | * |
65 | * Where: |
66 | * |
67 | * xA - ARGUMENTS: The number of arguments (input operands) that are |
68 | * required for this opcode type (1 through 6 args). |
69 | * yT - TARGETS: The number of targets (output operands) that are required |
70 | * for this opcode type (0, 1, or 2 targets). |
71 | * zR - RETURN VALUE: Indicates whether this opcode type returns a value |
72 | * as the function return (0 or 1). |
73 | * |
74 | * The AcpiExOpcode* functions are called via the Dispatcher component with |
75 | * fully resolved operands. |
76 | !*/ |
77 | |
78 | |
79 | /******************************************************************************* |
80 | * |
81 | * FUNCTION: AcpiExOpcode_2A_0T_0R |
82 | * |
83 | * PARAMETERS: WalkState - Current walk state |
84 | * |
85 | * RETURN: Status |
86 | * |
87 | * DESCRIPTION: Execute opcode with two arguments, no target, and no return |
88 | * value. |
89 | * |
90 | * ALLOCATION: Deletes both operands |
91 | * |
92 | ******************************************************************************/ |
93 | |
94 | ACPI_STATUS |
95 | AcpiExOpcode_2A_0T_0R ( |
96 | ACPI_WALK_STATE *WalkState) |
97 | { |
98 | ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; |
99 | ACPI_NAMESPACE_NODE *Node; |
100 | UINT32 Value; |
101 | ACPI_STATUS Status = AE_OK; |
102 | |
103 | |
104 | ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_0T_0R, |
105 | AcpiPsGetOpcodeName (WalkState->Opcode)); |
106 | |
107 | |
108 | /* Examine the opcode */ |
109 | |
110 | switch (WalkState->Opcode) |
111 | { |
112 | case AML_NOTIFY_OP: /* Notify (NotifyObject, NotifyValue) */ |
113 | |
114 | /* The first operand is a namespace node */ |
115 | |
116 | Node = (ACPI_NAMESPACE_NODE *) Operand[0]; |
117 | |
118 | /* Second value is the notify value */ |
119 | |
120 | Value = (UINT32) Operand[1]->Integer.Value; |
121 | |
122 | /* Are notifies allowed on this object? */ |
123 | |
124 | if (!AcpiEvIsNotifyObject (Node)) |
125 | { |
126 | ACPI_ERROR ((AE_INFO, |
127 | "Unexpected notify object type [%s]" , |
128 | AcpiUtGetTypeName (Node->Type))); |
129 | |
130 | Status = AE_AML_OPERAND_TYPE; |
131 | break; |
132 | } |
133 | |
134 | /* |
135 | * Dispatch the notify to the appropriate handler |
136 | * NOTE: the request is queued for execution after this method |
137 | * completes. The notify handlers are NOT invoked synchronously |
138 | * from this thread -- because handlers may in turn run other |
139 | * control methods. |
140 | */ |
141 | Status = AcpiEvQueueNotifyRequest (Node, Value); |
142 | break; |
143 | |
144 | default: |
145 | |
146 | ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X" , |
147 | WalkState->Opcode)); |
148 | Status = AE_AML_BAD_OPCODE; |
149 | } |
150 | |
151 | return_ACPI_STATUS (Status); |
152 | } |
153 | |
154 | |
155 | /******************************************************************************* |
156 | * |
157 | * FUNCTION: AcpiExOpcode_2A_2T_1R |
158 | * |
159 | * PARAMETERS: WalkState - Current walk state |
160 | * |
161 | * RETURN: Status |
162 | * |
163 | * DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets |
164 | * and one implicit return value. |
165 | * |
166 | ******************************************************************************/ |
167 | |
168 | ACPI_STATUS |
169 | AcpiExOpcode_2A_2T_1R ( |
170 | ACPI_WALK_STATE *WalkState) |
171 | { |
172 | ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; |
173 | ACPI_OPERAND_OBJECT *ReturnDesc1 = NULL; |
174 | ACPI_OPERAND_OBJECT *ReturnDesc2 = NULL; |
175 | ACPI_STATUS Status; |
176 | |
177 | |
178 | ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_2T_1R, |
179 | AcpiPsGetOpcodeName (WalkState->Opcode)); |
180 | |
181 | |
182 | /* Execute the opcode */ |
183 | |
184 | switch (WalkState->Opcode) |
185 | { |
186 | case AML_DIVIDE_OP: |
187 | |
188 | /* Divide (Dividend, Divisor, RemainderResult QuotientResult) */ |
189 | |
190 | ReturnDesc1 = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); |
191 | if (!ReturnDesc1) |
192 | { |
193 | Status = AE_NO_MEMORY; |
194 | goto Cleanup; |
195 | } |
196 | |
197 | ReturnDesc2 = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); |
198 | if (!ReturnDesc2) |
199 | { |
200 | Status = AE_NO_MEMORY; |
201 | goto Cleanup; |
202 | } |
203 | |
204 | /* Quotient to ReturnDesc1, remainder to ReturnDesc2 */ |
205 | |
206 | Status = AcpiUtDivide ( |
207 | Operand[0]->Integer.Value, |
208 | Operand[1]->Integer.Value, |
209 | &ReturnDesc1->Integer.Value, |
210 | &ReturnDesc2->Integer.Value); |
211 | if (ACPI_FAILURE (Status)) |
212 | { |
213 | goto Cleanup; |
214 | } |
215 | break; |
216 | |
217 | default: |
218 | |
219 | ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X" , |
220 | WalkState->Opcode)); |
221 | |
222 | Status = AE_AML_BAD_OPCODE; |
223 | goto Cleanup; |
224 | } |
225 | |
226 | /* Store the results to the target reference operands */ |
227 | |
228 | Status = AcpiExStore (ReturnDesc2, Operand[2], WalkState); |
229 | if (ACPI_FAILURE (Status)) |
230 | { |
231 | goto Cleanup; |
232 | } |
233 | |
234 | Status = AcpiExStore (ReturnDesc1, Operand[3], WalkState); |
235 | if (ACPI_FAILURE (Status)) |
236 | { |
237 | goto Cleanup; |
238 | } |
239 | |
240 | Cleanup: |
241 | /* |
242 | * Since the remainder is not returned indirectly, remove a reference to |
243 | * it. Only the quotient is returned indirectly. |
244 | */ |
245 | AcpiUtRemoveReference (ReturnDesc2); |
246 | |
247 | if (ACPI_FAILURE (Status)) |
248 | { |
249 | /* Delete the return object */ |
250 | |
251 | AcpiUtRemoveReference (ReturnDesc1); |
252 | } |
253 | |
254 | /* Save return object (the remainder) on success */ |
255 | |
256 | else |
257 | { |
258 | WalkState->ResultObj = ReturnDesc1; |
259 | } |
260 | |
261 | return_ACPI_STATUS (Status); |
262 | } |
263 | |
264 | |
265 | /******************************************************************************* |
266 | * |
267 | * FUNCTION: AcpiExOpcode_2A_1T_1R |
268 | * |
269 | * PARAMETERS: WalkState - Current walk state |
270 | * |
271 | * RETURN: Status |
272 | * |
273 | * DESCRIPTION: Execute opcode with two arguments, one target, and a return |
274 | * value. |
275 | * |
276 | ******************************************************************************/ |
277 | |
278 | ACPI_STATUS |
279 | AcpiExOpcode_2A_1T_1R ( |
280 | ACPI_WALK_STATE *WalkState) |
281 | { |
282 | ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; |
283 | ACPI_OPERAND_OBJECT *ReturnDesc = NULL; |
284 | UINT64 Index; |
285 | ACPI_STATUS Status = AE_OK; |
286 | ACPI_SIZE Length = 0; |
287 | |
288 | |
289 | ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_1T_1R, |
290 | AcpiPsGetOpcodeName (WalkState->Opcode)); |
291 | |
292 | |
293 | /* Execute the opcode */ |
294 | |
295 | if (WalkState->OpInfo->Flags & AML_MATH) |
296 | { |
297 | /* All simple math opcodes (add, etc.) */ |
298 | |
299 | ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); |
300 | if (!ReturnDesc) |
301 | { |
302 | Status = AE_NO_MEMORY; |
303 | goto Cleanup; |
304 | } |
305 | |
306 | ReturnDesc->Integer.Value = AcpiExDoMathOp ( |
307 | WalkState->Opcode, |
308 | Operand[0]->Integer.Value, |
309 | Operand[1]->Integer.Value); |
310 | goto StoreResultToTarget; |
311 | } |
312 | |
313 | switch (WalkState->Opcode) |
314 | { |
315 | case AML_MOD_OP: /* Mod (Dividend, Divisor, RemainderResult (ACPI 2.0) */ |
316 | |
317 | ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); |
318 | if (!ReturnDesc) |
319 | { |
320 | Status = AE_NO_MEMORY; |
321 | goto Cleanup; |
322 | } |
323 | |
324 | /* ReturnDesc will contain the remainder */ |
325 | |
326 | Status = AcpiUtDivide ( |
327 | Operand[0]->Integer.Value, |
328 | Operand[1]->Integer.Value, |
329 | NULL, |
330 | &ReturnDesc->Integer.Value); |
331 | break; |
332 | |
333 | case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ |
334 | |
335 | Status = AcpiExDoConcatenate ( |
336 | Operand[0], Operand[1], &ReturnDesc, WalkState); |
337 | break; |
338 | |
339 | case AML_TO_STRING_OP: /* ToString (Buffer, Length, Result) (ACPI 2.0) */ |
340 | /* |
341 | * Input object is guaranteed to be a buffer at this point (it may have |
342 | * been converted.) Copy the raw buffer data to a new object of |
343 | * type String. |
344 | */ |
345 | |
346 | /* |
347 | * Get the length of the new string. It is the smallest of: |
348 | * 1) Length of the input buffer |
349 | * 2) Max length as specified in the ToString operator |
350 | * 3) Length of input buffer up to a zero byte (null terminator) |
351 | * |
352 | * NOTE: A length of zero is ok, and will create a zero-length, null |
353 | * terminated string. |
354 | */ |
355 | while ((Length < Operand[0]->Buffer.Length) && |
356 | (Length < Operand[1]->Integer.Value) && |
357 | (Operand[0]->Buffer.Pointer[Length])) |
358 | { |
359 | Length++; |
360 | } |
361 | |
362 | /* Allocate a new string object */ |
363 | |
364 | ReturnDesc = AcpiUtCreateStringObject (Length); |
365 | if (!ReturnDesc) |
366 | { |
367 | Status = AE_NO_MEMORY; |
368 | goto Cleanup; |
369 | } |
370 | |
371 | /* |
372 | * Copy the raw buffer data with no transform. |
373 | * (NULL terminated already) |
374 | */ |
375 | memcpy (ReturnDesc->String.Pointer, |
376 | Operand[0]->Buffer.Pointer, Length); |
377 | break; |
378 | |
379 | case AML_CONCAT_RES_OP: |
380 | |
381 | /* ConcatenateResTemplate (Buffer, Buffer, Result) (ACPI 2.0) */ |
382 | |
383 | Status = AcpiExConcatTemplate ( |
384 | Operand[0], Operand[1], &ReturnDesc, WalkState); |
385 | break; |
386 | |
387 | case AML_INDEX_OP: /* Index (Source Index Result) */ |
388 | |
389 | /* Create the internal return object */ |
390 | |
391 | ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); |
392 | if (!ReturnDesc) |
393 | { |
394 | Status = AE_NO_MEMORY; |
395 | goto Cleanup; |
396 | } |
397 | |
398 | /* Initialize the Index reference object */ |
399 | |
400 | Index = Operand[1]->Integer.Value; |
401 | ReturnDesc->Reference.Value = (UINT32) Index; |
402 | ReturnDesc->Reference.Class = ACPI_REFCLASS_INDEX; |
403 | |
404 | /* |
405 | * At this point, the Source operand is a String, Buffer, or Package. |
406 | * Verify that the index is within range. |
407 | */ |
408 | switch ((Operand[0])->Common.Type) |
409 | { |
410 | case ACPI_TYPE_STRING: |
411 | |
412 | if (Index >= Operand[0]->String.Length) |
413 | { |
414 | Length = Operand[0]->String.Length; |
415 | Status = AE_AML_STRING_LIMIT; |
416 | } |
417 | |
418 | ReturnDesc->Reference.TargetType = ACPI_TYPE_BUFFER_FIELD; |
419 | ReturnDesc->Reference.IndexPointer = |
420 | &(Operand[0]->Buffer.Pointer [Index]); |
421 | break; |
422 | |
423 | case ACPI_TYPE_BUFFER: |
424 | |
425 | if (Index >= Operand[0]->Buffer.Length) |
426 | { |
427 | Length = Operand[0]->Buffer.Length; |
428 | Status = AE_AML_BUFFER_LIMIT; |
429 | } |
430 | |
431 | ReturnDesc->Reference.TargetType = ACPI_TYPE_BUFFER_FIELD; |
432 | ReturnDesc->Reference.IndexPointer = |
433 | &(Operand[0]->Buffer.Pointer [Index]); |
434 | break; |
435 | |
436 | case ACPI_TYPE_PACKAGE: |
437 | |
438 | if (Index >= Operand[0]->Package.Count) |
439 | { |
440 | Length = Operand[0]->Package.Count; |
441 | Status = AE_AML_PACKAGE_LIMIT; |
442 | } |
443 | |
444 | ReturnDesc->Reference.TargetType = ACPI_TYPE_PACKAGE; |
445 | ReturnDesc->Reference.Where = |
446 | &Operand[0]->Package.Elements [Index]; |
447 | break; |
448 | |
449 | default: |
450 | |
451 | Status = AE_AML_INTERNAL; |
452 | goto Cleanup; |
453 | } |
454 | |
455 | /* Failure means that the Index was beyond the end of the object */ |
456 | |
457 | if (ACPI_FAILURE (Status)) |
458 | { |
459 | ACPI_EXCEPTION ((AE_INFO, Status, |
460 | "Index (0x%X%8.8X) is beyond end of object (length 0x%X)" , |
461 | ACPI_FORMAT_UINT64 (Index), (UINT32) Length)); |
462 | goto Cleanup; |
463 | } |
464 | |
465 | /* |
466 | * Save the target object and add a reference to it for the life |
467 | * of the index |
468 | */ |
469 | ReturnDesc->Reference.Object = Operand[0]; |
470 | AcpiUtAddReference (Operand[0]); |
471 | |
472 | /* Store the reference to the Target */ |
473 | |
474 | Status = AcpiExStore (ReturnDesc, Operand[2], WalkState); |
475 | |
476 | /* Return the reference */ |
477 | |
478 | WalkState->ResultObj = ReturnDesc; |
479 | goto Cleanup; |
480 | |
481 | default: |
482 | |
483 | ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X" , |
484 | WalkState->Opcode)); |
485 | Status = AE_AML_BAD_OPCODE; |
486 | break; |
487 | } |
488 | |
489 | |
490 | StoreResultToTarget: |
491 | |
492 | if (ACPI_SUCCESS (Status)) |
493 | { |
494 | /* |
495 | * Store the result of the operation (which is now in ReturnDesc) into |
496 | * the Target descriptor. |
497 | */ |
498 | Status = AcpiExStore (ReturnDesc, Operand[2], WalkState); |
499 | if (ACPI_FAILURE (Status)) |
500 | { |
501 | goto Cleanup; |
502 | } |
503 | |
504 | if (!WalkState->ResultObj) |
505 | { |
506 | WalkState->ResultObj = ReturnDesc; |
507 | } |
508 | } |
509 | |
510 | |
511 | Cleanup: |
512 | |
513 | /* Delete return object on error */ |
514 | |
515 | if (ACPI_FAILURE (Status)) |
516 | { |
517 | AcpiUtRemoveReference (ReturnDesc); |
518 | WalkState->ResultObj = NULL; |
519 | } |
520 | |
521 | return_ACPI_STATUS (Status); |
522 | } |
523 | |
524 | |
525 | /******************************************************************************* |
526 | * |
527 | * FUNCTION: AcpiExOpcode_2A_0T_1R |
528 | * |
529 | * PARAMETERS: WalkState - Current walk state |
530 | * |
531 | * RETURN: Status |
532 | * |
533 | * DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value |
534 | * |
535 | ******************************************************************************/ |
536 | |
537 | ACPI_STATUS |
538 | AcpiExOpcode_2A_0T_1R ( |
539 | ACPI_WALK_STATE *WalkState) |
540 | { |
541 | ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; |
542 | ACPI_OPERAND_OBJECT *ReturnDesc = NULL; |
543 | ACPI_STATUS Status = AE_OK; |
544 | BOOLEAN LogicalResult = FALSE; |
545 | |
546 | |
547 | ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_0T_1R, |
548 | AcpiPsGetOpcodeName (WalkState->Opcode)); |
549 | |
550 | |
551 | /* Create the internal return object */ |
552 | |
553 | ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); |
554 | if (!ReturnDesc) |
555 | { |
556 | Status = AE_NO_MEMORY; |
557 | goto Cleanup; |
558 | } |
559 | |
560 | /* Execute the Opcode */ |
561 | |
562 | if (WalkState->OpInfo->Flags & AML_LOGICAL_NUMERIC) |
563 | { |
564 | /* LogicalOp (Operand0, Operand1) */ |
565 | |
566 | Status = AcpiExDoLogicalNumericOp (WalkState->Opcode, |
567 | Operand[0]->Integer.Value, Operand[1]->Integer.Value, |
568 | &LogicalResult); |
569 | goto StoreLogicalResult; |
570 | } |
571 | else if (WalkState->OpInfo->Flags & AML_LOGICAL) |
572 | { |
573 | /* LogicalOp (Operand0, Operand1) */ |
574 | |
575 | Status = AcpiExDoLogicalOp (WalkState->Opcode, Operand[0], |
576 | Operand[1], &LogicalResult); |
577 | goto StoreLogicalResult; |
578 | } |
579 | |
580 | switch (WalkState->Opcode) |
581 | { |
582 | case AML_ACQUIRE_OP: /* Acquire (MutexObject, Timeout) */ |
583 | |
584 | Status = AcpiExAcquireMutex (Operand[1], Operand[0], WalkState); |
585 | if (Status == AE_TIME) |
586 | { |
587 | LogicalResult = TRUE; /* TRUE = Acquire timed out */ |
588 | Status = AE_OK; |
589 | } |
590 | break; |
591 | |
592 | |
593 | case AML_WAIT_OP: /* Wait (EventObject, Timeout) */ |
594 | |
595 | Status = AcpiExSystemWaitEvent (Operand[1], Operand[0]); |
596 | if (Status == AE_TIME) |
597 | { |
598 | LogicalResult = TRUE; /* TRUE, Wait timed out */ |
599 | Status = AE_OK; |
600 | } |
601 | break; |
602 | |
603 | default: |
604 | |
605 | ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X" , |
606 | WalkState->Opcode)); |
607 | |
608 | Status = AE_AML_BAD_OPCODE; |
609 | goto Cleanup; |
610 | } |
611 | |
612 | |
613 | StoreLogicalResult: |
614 | /* |
615 | * Set return value to according to LogicalResult. logical TRUE (all ones) |
616 | * Default is FALSE (zero) |
617 | */ |
618 | if (LogicalResult) |
619 | { |
620 | ReturnDesc->Integer.Value = ACPI_UINT64_MAX; |
621 | } |
622 | |
623 | Cleanup: |
624 | |
625 | /* Delete return object on error */ |
626 | |
627 | if (ACPI_FAILURE (Status)) |
628 | { |
629 | AcpiUtRemoveReference (ReturnDesc); |
630 | } |
631 | |
632 | /* Save return object on success */ |
633 | |
634 | else |
635 | { |
636 | WalkState->ResultObj = ReturnDesc; |
637 | } |
638 | |
639 | return_ACPI_STATUS (Status); |
640 | } |
641 | |