1 /******************************************************************************
2  *
3  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, 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 MERCHANTABILITY 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_LOGICAL_AND_OP:        /* LAnd (Integer0, Integer1) */
278 
279         if (Integer0 && Integer1)
280         {
281             LocalResult = TRUE;
282         }
283         break;
284 
285     case AML_LOGICAL_OR_OP:         /* LOr (Integer0, Integer1) */
286 
287         if (Integer0 || Integer1)
288         {
289             LocalResult = TRUE;
290         }
291         break;
292 
293     default:
294 
295         ACPI_ERROR ((AE_INFO,
296             "Invalid numeric logical opcode: %X", Opcode));
297         Status = AE_AML_INTERNAL;
298         break;
299     }
300 
301     /* Return the logical result and status */
302 
303     *LogicalResult = LocalResult;
304     return_ACPI_STATUS (Status);
305 }
306 
307 
308 /*******************************************************************************
309  *
310  * FUNCTION:    AcpiExDoLogicalOp
311  *
312  * PARAMETERS:  Opcode              - AML opcode
313  *              Operand0            - operand #0
314  *              Operand1            - operand #1
315  *              LogicalResult       - TRUE/FALSE result of the operation
316  *
317  * RETURN:      Status
318  *
319  * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
320  *              functions here is to prevent a lot of pointer dereferencing
321  *              to obtain the operands and to simplify the generation of the
322  *              logical value. For the Numeric operators (LAnd and LOr), both
323  *              operands must be integers. For the other logical operators,
324  *              operands can be any combination of Integer/String/Buffer. The
325  *              first operand determines the type to which the second operand
326  *              will be converted.
327  *
328  *              Note: cleanest machine code seems to be produced by the code
329  *              below, rather than using statements of the form:
330  *                  Result = (Operand0 == Operand1);
331  *
332  ******************************************************************************/
333 
334 ACPI_STATUS
335 AcpiExDoLogicalOp (
336     UINT16                  Opcode,
337     ACPI_OPERAND_OBJECT     *Operand0,
338     ACPI_OPERAND_OBJECT     *Operand1,
339     BOOLEAN                 *LogicalResult)
340 {
341     ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
342     UINT64                  Integer0;
343     UINT64                  Integer1;
344     UINT32                  Length0;
345     UINT32                  Length1;
346     ACPI_STATUS             Status = AE_OK;
347     BOOLEAN                 LocalResult = FALSE;
348     int                     Compare;
349 
350 
351     ACPI_FUNCTION_TRACE (ExDoLogicalOp);
352 
353 
354     /*
355      * Convert the second operand if necessary. The first operand
356      * determines the type of the second operand, (See the Data Types
357      * section of the ACPI 3.0+ specification.)  Both object types are
358      * guaranteed to be either Integer/String/Buffer by the operand
359      * resolution mechanism.
360      */
361     switch (Operand0->Common.Type)
362     {
363     case ACPI_TYPE_INTEGER:
364 
365         Status = AcpiExConvertToInteger (Operand1, &LocalOperand1,
366             ACPI_IMPLICIT_CONVERSION);
367         break;
368 
369     case ACPI_TYPE_STRING:
370 
371         Status = AcpiExConvertToString (
372             Operand1, &LocalOperand1, ACPI_IMPLICIT_CONVERT_HEX);
373         break;
374 
375     case ACPI_TYPE_BUFFER:
376 
377         Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
378         break;
379 
380     default:
381 
382         ACPI_ERROR ((AE_INFO,
383             "Invalid object type for logical operator: %X",
384             Operand0->Common.Type));
385         Status = AE_AML_INTERNAL;
386         break;
387     }
388 
389     if (ACPI_FAILURE (Status))
390     {
391         goto Cleanup;
392     }
393 
394     /*
395      * Two cases: 1) Both Integers, 2) Both Strings or Buffers
396      */
397     if (Operand0->Common.Type == ACPI_TYPE_INTEGER)
398     {
399         /*
400          * 1) Both operands are of type integer
401          *    Note: LocalOperand1 may have changed above
402          */
403         Integer0 = Operand0->Integer.Value;
404         Integer1 = LocalOperand1->Integer.Value;
405 
406         switch (Opcode)
407         {
408         case AML_LOGICAL_EQUAL_OP:          /* LEqual (Operand0, Operand1) */
409 
410             if (Integer0 == Integer1)
411             {
412                 LocalResult = TRUE;
413             }
414             break;
415 
416         case AML_LOGICAL_GREATER_OP:        /* LGreater (Operand0, Operand1) */
417 
418             if (Integer0 > Integer1)
419             {
420                 LocalResult = TRUE;
421             }
422             break;
423 
424         case AML_LOGICAL_LESS_OP:           /* LLess (Operand0, Operand1) */
425 
426             if (Integer0 < Integer1)
427             {
428                 LocalResult = TRUE;
429             }
430             break;
431 
432         default:
433 
434             ACPI_ERROR ((AE_INFO,
435                 "Invalid comparison opcode: %X", Opcode));
436             Status = AE_AML_INTERNAL;
437             break;
438         }
439     }
440     else
441     {
442         /*
443          * 2) Both operands are Strings or both are Buffers
444          *    Note: Code below takes advantage of common Buffer/String
445          *          object fields. LocalOperand1 may have changed above. Use
446          *          memcmp to handle nulls in buffers.
447          */
448         Length0 = Operand0->Buffer.Length;
449         Length1 = LocalOperand1->Buffer.Length;
450 
451         /* Lexicographic compare: compare the data bytes */
452 
453         Compare = memcmp (Operand0->Buffer.Pointer,
454             LocalOperand1->Buffer.Pointer,
455             (Length0 > Length1) ? Length1 : Length0);
456 
457         switch (Opcode)
458         {
459         case AML_LOGICAL_EQUAL_OP:      /* LEqual (Operand0, Operand1) */
460 
461             /* Length and all bytes must be equal */
462 
463             if ((Length0 == Length1) &&
464                 (Compare == 0))
465             {
466                 /* Length and all bytes match ==> TRUE */
467 
468                 LocalResult = TRUE;
469             }
470             break;
471 
472         case AML_LOGICAL_GREATER_OP:    /* LGreater (Operand0, Operand1) */
473 
474             if (Compare > 0)
475             {
476                 LocalResult = TRUE;
477                 goto Cleanup;   /* TRUE */
478             }
479             if (Compare < 0)
480             {
481                 goto Cleanup;   /* FALSE */
482             }
483 
484             /* Bytes match (to shortest length), compare lengths */
485 
486             if (Length0 > Length1)
487             {
488                 LocalResult = TRUE;
489             }
490             break;
491 
492         case AML_LOGICAL_LESS_OP:       /* LLess (Operand0, Operand1) */
493 
494             if (Compare > 0)
495             {
496                 goto Cleanup;   /* FALSE */
497             }
498             if (Compare < 0)
499             {
500                 LocalResult = TRUE;
501                 goto Cleanup;   /* TRUE */
502             }
503 
504             /* Bytes match (to shortest length), compare lengths */
505 
506             if (Length0 < Length1)
507             {
508                 LocalResult = TRUE;
509             }
510             break;
511 
512         default:
513 
514             ACPI_ERROR ((AE_INFO,
515                 "Invalid comparison opcode: %X", Opcode));
516             Status = AE_AML_INTERNAL;
517             break;
518         }
519     }
520 
521 Cleanup:
522 
523     /* New object was created if implicit conversion performed - delete */
524 
525     if (LocalOperand1 != Operand1)
526     {
527         AcpiUtRemoveReference (LocalOperand1);
528     }
529 
530     /* Return the logical result and status */
531 
532     *LogicalResult = LocalResult;
533     return_ACPI_STATUS (Status);
534 }
535