1 | /****************************************************************************** |
2 | * |
3 | * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes |
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 "acinterp.h" |
47 | #include "amlcode.h" |
48 | |
49 | |
50 | #define _COMPONENT ACPI_EXECUTER |
51 | ACPI_MODULE_NAME ("exmisc" ) |
52 | |
53 | |
54 | /******************************************************************************* |
55 | * |
56 | * FUNCTION: AcpiExGetObjectReference |
57 | * |
58 | * PARAMETERS: ObjDesc - Create a reference to this object |
59 | * ReturnDesc - Where to store the reference |
60 | * WalkState - Current state |
61 | * |
62 | * RETURN: Status |
63 | * |
64 | * DESCRIPTION: Obtain and return a "reference" to the target object |
65 | * Common code for the RefOfOp and the CondRefOfOp. |
66 | * |
67 | ******************************************************************************/ |
68 | |
69 | ACPI_STATUS |
70 | AcpiExGetObjectReference ( |
71 | ACPI_OPERAND_OBJECT *ObjDesc, |
72 | ACPI_OPERAND_OBJECT **ReturnDesc, |
73 | ACPI_WALK_STATE *WalkState) |
74 | { |
75 | ACPI_OPERAND_OBJECT *ReferenceObj; |
76 | ACPI_OPERAND_OBJECT *ReferencedObj; |
77 | |
78 | |
79 | ACPI_FUNCTION_TRACE_PTR (ExGetObjectReference, ObjDesc); |
80 | |
81 | |
82 | *ReturnDesc = NULL; |
83 | |
84 | switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)) |
85 | { |
86 | case ACPI_DESC_TYPE_OPERAND: |
87 | |
88 | if (ObjDesc->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) |
89 | { |
90 | return_ACPI_STATUS (AE_AML_OPERAND_TYPE); |
91 | } |
92 | |
93 | /* |
94 | * Must be a reference to a Local or Arg |
95 | */ |
96 | switch (ObjDesc->Reference.Class) |
97 | { |
98 | case ACPI_REFCLASS_LOCAL: |
99 | case ACPI_REFCLASS_ARG: |
100 | case ACPI_REFCLASS_DEBUG: |
101 | |
102 | /* The referenced object is the pseudo-node for the local/arg */ |
103 | |
104 | ReferencedObj = ObjDesc->Reference.Object; |
105 | break; |
106 | |
107 | default: |
108 | |
109 | ACPI_ERROR ((AE_INFO, "Invalid Reference Class 0x%2.2X" , |
110 | ObjDesc->Reference.Class)); |
111 | return_ACPI_STATUS (AE_AML_OPERAND_TYPE); |
112 | } |
113 | break; |
114 | |
115 | case ACPI_DESC_TYPE_NAMED: |
116 | /* |
117 | * A named reference that has already been resolved to a Node |
118 | */ |
119 | ReferencedObj = ObjDesc; |
120 | break; |
121 | |
122 | default: |
123 | |
124 | ACPI_ERROR ((AE_INFO, "Invalid descriptor type 0x%X" , |
125 | ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))); |
126 | return_ACPI_STATUS (AE_TYPE); |
127 | } |
128 | |
129 | |
130 | /* Create a new reference object */ |
131 | |
132 | ReferenceObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); |
133 | if (!ReferenceObj) |
134 | { |
135 | return_ACPI_STATUS (AE_NO_MEMORY); |
136 | } |
137 | |
138 | ReferenceObj->Reference.Class = ACPI_REFCLASS_REFOF; |
139 | ReferenceObj->Reference.Object = ReferencedObj; |
140 | *ReturnDesc = ReferenceObj; |
141 | |
142 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, |
143 | "Object %p Type [%s], returning Reference %p\n" , |
144 | ObjDesc, AcpiUtGetObjectTypeName (ObjDesc), *ReturnDesc)); |
145 | |
146 | return_ACPI_STATUS (AE_OK); |
147 | } |
148 | |
149 | |
150 | /******************************************************************************* |
151 | * |
152 | * FUNCTION: AcpiExDoMathOp |
153 | * |
154 | * PARAMETERS: Opcode - AML opcode |
155 | * Integer0 - Integer operand #0 |
156 | * Integer1 - Integer operand #1 |
157 | * |
158 | * RETURN: Integer result of the operation |
159 | * |
160 | * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the |
161 | * math functions here is to prevent a lot of pointer dereferencing |
162 | * to obtain the operands. |
163 | * |
164 | ******************************************************************************/ |
165 | |
166 | UINT64 |
167 | AcpiExDoMathOp ( |
168 | UINT16 Opcode, |
169 | UINT64 Integer0, |
170 | UINT64 Integer1) |
171 | { |
172 | |
173 | ACPI_FUNCTION_ENTRY (); |
174 | |
175 | |
176 | switch (Opcode) |
177 | { |
178 | case AML_ADD_OP: /* Add (Integer0, Integer1, Result) */ |
179 | |
180 | return (Integer0 + Integer1); |
181 | |
182 | case AML_BIT_AND_OP: /* And (Integer0, Integer1, Result) */ |
183 | |
184 | return (Integer0 & Integer1); |
185 | |
186 | case AML_BIT_NAND_OP: /* NAnd (Integer0, Integer1, Result) */ |
187 | |
188 | return (~(Integer0 & Integer1)); |
189 | |
190 | case AML_BIT_OR_OP: /* Or (Integer0, Integer1, Result) */ |
191 | |
192 | return (Integer0 | Integer1); |
193 | |
194 | case AML_BIT_NOR_OP: /* NOr (Integer0, Integer1, Result) */ |
195 | |
196 | return (~(Integer0 | Integer1)); |
197 | |
198 | case AML_BIT_XOR_OP: /* XOr (Integer0, Integer1, Result) */ |
199 | |
200 | return (Integer0 ^ Integer1); |
201 | |
202 | case AML_MULTIPLY_OP: /* Multiply (Integer0, Integer1, Result) */ |
203 | |
204 | return (Integer0 * Integer1); |
205 | |
206 | case AML_SHIFT_LEFT_OP: /* ShiftLeft (Operand, ShiftCount, Result)*/ |
207 | |
208 | /* |
209 | * We need to check if the shiftcount is larger than the integer bit |
210 | * width since the behavior of this is not well-defined in the C language. |
211 | */ |
212 | if (Integer1 >= AcpiGbl_IntegerBitWidth) |
213 | { |
214 | return (0); |
215 | } |
216 | return (Integer0 << Integer1); |
217 | |
218 | case AML_SHIFT_RIGHT_OP: /* ShiftRight (Operand, ShiftCount, Result) */ |
219 | |
220 | /* |
221 | * We need to check if the shiftcount is larger than the integer bit |
222 | * width since the behavior of this is not well-defined in the C language. |
223 | */ |
224 | if (Integer1 >= AcpiGbl_IntegerBitWidth) |
225 | { |
226 | return (0); |
227 | } |
228 | return (Integer0 >> Integer1); |
229 | |
230 | case AML_SUBTRACT_OP: /* Subtract (Integer0, Integer1, Result) */ |
231 | |
232 | return (Integer0 - Integer1); |
233 | |
234 | default: |
235 | |
236 | return (0); |
237 | } |
238 | } |
239 | |
240 | |
241 | /******************************************************************************* |
242 | * |
243 | * FUNCTION: AcpiExDoLogicalNumericOp |
244 | * |
245 | * PARAMETERS: Opcode - AML opcode |
246 | * Integer0 - Integer operand #0 |
247 | * Integer1 - Integer operand #1 |
248 | * LogicalResult - TRUE/FALSE result of the operation |
249 | * |
250 | * RETURN: Status |
251 | * |
252 | * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric |
253 | * operators (LAnd and LOr), both operands must be integers. |
254 | * |
255 | * Note: cleanest machine code seems to be produced by the code |
256 | * below, rather than using statements of the form: |
257 | * Result = (Integer0 && Integer1); |
258 | * |
259 | ******************************************************************************/ |
260 | |
261 | ACPI_STATUS |
262 | AcpiExDoLogicalNumericOp ( |
263 | UINT16 Opcode, |
264 | UINT64 Integer0, |
265 | UINT64 Integer1, |
266 | BOOLEAN *LogicalResult) |
267 | { |
268 | ACPI_STATUS Status = AE_OK; |
269 | BOOLEAN LocalResult = FALSE; |
270 | |
271 | |
272 | ACPI_FUNCTION_TRACE (ExDoLogicalNumericOp); |
273 | |
274 | |
275 | switch (Opcode) |
276 | { |
277 | case AML_LAND_OP: /* LAnd (Integer0, Integer1) */ |
278 | |
279 | if (Integer0 && Integer1) |
280 | { |
281 | LocalResult = TRUE; |
282 | } |
283 | break; |
284 | |
285 | case AML_LOR_OP: /* LOr (Integer0, Integer1) */ |
286 | |
287 | if (Integer0 || Integer1) |
288 | { |
289 | LocalResult = TRUE; |
290 | } |
291 | break; |
292 | |
293 | default: |
294 | |
295 | Status = AE_AML_INTERNAL; |
296 | break; |
297 | } |
298 | |
299 | /* Return the logical result and status */ |
300 | |
301 | *LogicalResult = LocalResult; |
302 | return_ACPI_STATUS (Status); |
303 | } |
304 | |
305 | |
306 | /******************************************************************************* |
307 | * |
308 | * FUNCTION: AcpiExDoLogicalOp |
309 | * |
310 | * PARAMETERS: Opcode - AML opcode |
311 | * Operand0 - operand #0 |
312 | * Operand1 - operand #1 |
313 | * LogicalResult - TRUE/FALSE result of the operation |
314 | * |
315 | * RETURN: Status |
316 | * |
317 | * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the |
318 | * functions here is to prevent a lot of pointer dereferencing |
319 | * to obtain the operands and to simplify the generation of the |
320 | * logical value. For the Numeric operators (LAnd and LOr), both |
321 | * operands must be integers. For the other logical operators, |
322 | * operands can be any combination of Integer/String/Buffer. The |
323 | * first operand determines the type to which the second operand |
324 | * will be converted. |
325 | * |
326 | * Note: cleanest machine code seems to be produced by the code |
327 | * below, rather than using statements of the form: |
328 | * Result = (Operand0 == Operand1); |
329 | * |
330 | ******************************************************************************/ |
331 | |
332 | ACPI_STATUS |
333 | AcpiExDoLogicalOp ( |
334 | UINT16 Opcode, |
335 | ACPI_OPERAND_OBJECT *Operand0, |
336 | ACPI_OPERAND_OBJECT *Operand1, |
337 | BOOLEAN *LogicalResult) |
338 | { |
339 | ACPI_OPERAND_OBJECT *LocalOperand1 = Operand1; |
340 | UINT64 Integer0; |
341 | UINT64 Integer1; |
342 | UINT32 Length0; |
343 | UINT32 Length1; |
344 | ACPI_STATUS Status = AE_OK; |
345 | BOOLEAN LocalResult = FALSE; |
346 | int Compare; |
347 | |
348 | |
349 | ACPI_FUNCTION_TRACE (ExDoLogicalOp); |
350 | |
351 | |
352 | /* |
353 | * Convert the second operand if necessary. The first operand |
354 | * determines the type of the second operand, (See the Data Types |
355 | * section of the ACPI 3.0+ specification.) Both object types are |
356 | * guaranteed to be either Integer/String/Buffer by the operand |
357 | * resolution mechanism. |
358 | */ |
359 | switch (Operand0->Common.Type) |
360 | { |
361 | case ACPI_TYPE_INTEGER: |
362 | |
363 | Status = AcpiExConvertToInteger (Operand1, &LocalOperand1, |
364 | ACPI_STRTOUL_BASE16); |
365 | break; |
366 | |
367 | case ACPI_TYPE_STRING: |
368 | |
369 | Status = AcpiExConvertToString ( |
370 | Operand1, &LocalOperand1, ACPI_IMPLICIT_CONVERT_HEX); |
371 | break; |
372 | |
373 | case ACPI_TYPE_BUFFER: |
374 | |
375 | Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1); |
376 | break; |
377 | |
378 | default: |
379 | |
380 | Status = AE_AML_INTERNAL; |
381 | break; |
382 | } |
383 | |
384 | if (ACPI_FAILURE (Status)) |
385 | { |
386 | goto Cleanup; |
387 | } |
388 | |
389 | /* |
390 | * Two cases: 1) Both Integers, 2) Both Strings or Buffers |
391 | */ |
392 | if (Operand0->Common.Type == ACPI_TYPE_INTEGER) |
393 | { |
394 | /* |
395 | * 1) Both operands are of type integer |
396 | * Note: LocalOperand1 may have changed above |
397 | */ |
398 | Integer0 = Operand0->Integer.Value; |
399 | Integer1 = LocalOperand1->Integer.Value; |
400 | |
401 | switch (Opcode) |
402 | { |
403 | case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ |
404 | |
405 | if (Integer0 == Integer1) |
406 | { |
407 | LocalResult = TRUE; |
408 | } |
409 | break; |
410 | |
411 | case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ |
412 | |
413 | if (Integer0 > Integer1) |
414 | { |
415 | LocalResult = TRUE; |
416 | } |
417 | break; |
418 | |
419 | case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ |
420 | |
421 | if (Integer0 < Integer1) |
422 | { |
423 | LocalResult = TRUE; |
424 | } |
425 | break; |
426 | |
427 | default: |
428 | |
429 | Status = AE_AML_INTERNAL; |
430 | break; |
431 | } |
432 | } |
433 | else |
434 | { |
435 | /* |
436 | * 2) Both operands are Strings or both are Buffers |
437 | * Note: Code below takes advantage of common Buffer/String |
438 | * object fields. LocalOperand1 may have changed above. Use |
439 | * memcmp to handle nulls in buffers. |
440 | */ |
441 | Length0 = Operand0->Buffer.Length; |
442 | Length1 = LocalOperand1->Buffer.Length; |
443 | |
444 | /* Lexicographic compare: compare the data bytes */ |
445 | |
446 | Compare = memcmp (Operand0->Buffer.Pointer, |
447 | LocalOperand1->Buffer.Pointer, |
448 | (Length0 > Length1) ? Length1 : Length0); |
449 | |
450 | switch (Opcode) |
451 | { |
452 | case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */ |
453 | |
454 | /* Length and all bytes must be equal */ |
455 | |
456 | if ((Length0 == Length1) && |
457 | (Compare == 0)) |
458 | { |
459 | /* Length and all bytes match ==> TRUE */ |
460 | |
461 | LocalResult = TRUE; |
462 | } |
463 | break; |
464 | |
465 | case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */ |
466 | |
467 | if (Compare > 0) |
468 | { |
469 | LocalResult = TRUE; |
470 | goto Cleanup; /* TRUE */ |
471 | } |
472 | if (Compare < 0) |
473 | { |
474 | goto Cleanup; /* FALSE */ |
475 | } |
476 | |
477 | /* Bytes match (to shortest length), compare lengths */ |
478 | |
479 | if (Length0 > Length1) |
480 | { |
481 | LocalResult = TRUE; |
482 | } |
483 | break; |
484 | |
485 | case AML_LLESS_OP: /* LLess (Operand0, Operand1) */ |
486 | |
487 | if (Compare > 0) |
488 | { |
489 | goto Cleanup; /* FALSE */ |
490 | } |
491 | if (Compare < 0) |
492 | { |
493 | LocalResult = TRUE; |
494 | goto Cleanup; /* TRUE */ |
495 | } |
496 | |
497 | /* Bytes match (to shortest length), compare lengths */ |
498 | |
499 | if (Length0 < Length1) |
500 | { |
501 | LocalResult = TRUE; |
502 | } |
503 | break; |
504 | |
505 | default: |
506 | |
507 | Status = AE_AML_INTERNAL; |
508 | break; |
509 | } |
510 | } |
511 | |
512 | Cleanup: |
513 | |
514 | /* New object was created if implicit conversion performed - delete */ |
515 | |
516 | if (LocalOperand1 != Operand1) |
517 | { |
518 | AcpiUtRemoveReference (LocalOperand1); |
519 | } |
520 | |
521 | /* Return the logical result and status */ |
522 | |
523 | *LogicalResult = LocalResult; |
524 | return_ACPI_STATUS (Status); |
525 | } |
526 | |