xref: /titanic_50/usr/src/uts/intel/io/acpica/executer/exmisc.c (revision 2a52a1627973d84afe3af6de87c1fe00ac3d087e)
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, 16);
364         break;
365 
366     case ACPI_TYPE_STRING:
367 
368         Status = AcpiExConvertToString (
369             Operand1, &LocalOperand1, ACPI_IMPLICIT_CONVERT_HEX);
370         break;
371 
372     case ACPI_TYPE_BUFFER:
373 
374         Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
375         break;
376 
377     default:
378 
379         Status = AE_AML_INTERNAL;
380         break;
381     }
382 
383     if (ACPI_FAILURE (Status))
384     {
385         goto Cleanup;
386     }
387 
388     /*
389      * Two cases: 1) Both Integers, 2) Both Strings or Buffers
390      */
391     if (Operand0->Common.Type == ACPI_TYPE_INTEGER)
392     {
393         /*
394          * 1) Both operands are of type integer
395          *    Note: LocalOperand1 may have changed above
396          */
397         Integer0 = Operand0->Integer.Value;
398         Integer1 = LocalOperand1->Integer.Value;
399 
400         switch (Opcode)
401         {
402         case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
403 
404             if (Integer0 == Integer1)
405             {
406                 LocalResult = TRUE;
407             }
408             break;
409 
410         case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
411 
412             if (Integer0 > Integer1)
413             {
414                 LocalResult = TRUE;
415             }
416             break;
417 
418         case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
419 
420             if (Integer0 < Integer1)
421             {
422                 LocalResult = TRUE;
423             }
424             break;
425 
426         default:
427 
428             Status = AE_AML_INTERNAL;
429             break;
430         }
431     }
432     else
433     {
434         /*
435          * 2) Both operands are Strings or both are Buffers
436          *    Note: Code below takes advantage of common Buffer/String
437          *          object fields. LocalOperand1 may have changed above. Use
438          *          memcmp to handle nulls in buffers.
439          */
440         Length0 = Operand0->Buffer.Length;
441         Length1 = LocalOperand1->Buffer.Length;
442 
443         /* Lexicographic compare: compare the data bytes */
444 
445         Compare = memcmp (Operand0->Buffer.Pointer,
446             LocalOperand1->Buffer.Pointer,
447             (Length0 > Length1) ? Length1 : Length0);
448 
449         switch (Opcode)
450         {
451         case AML_LEQUAL_OP:             /* LEqual (Operand0, Operand1) */
452 
453             /* Length and all bytes must be equal */
454 
455             if ((Length0 == Length1) &&
456                 (Compare == 0))
457             {
458                 /* Length and all bytes match ==> TRUE */
459 
460                 LocalResult = TRUE;
461             }
462             break;
463 
464         case AML_LGREATER_OP:           /* LGreater (Operand0, Operand1) */
465 
466             if (Compare > 0)
467             {
468                 LocalResult = TRUE;
469                 goto Cleanup;   /* TRUE */
470             }
471             if (Compare < 0)
472             {
473                 goto Cleanup;   /* FALSE */
474             }
475 
476             /* Bytes match (to shortest length), compare lengths */
477 
478             if (Length0 > Length1)
479             {
480                 LocalResult = TRUE;
481             }
482             break;
483 
484         case AML_LLESS_OP:              /* LLess (Operand0, Operand1) */
485 
486             if (Compare > 0)
487             {
488                 goto Cleanup;   /* FALSE */
489             }
490             if (Compare < 0)
491             {
492                 LocalResult = TRUE;
493                 goto Cleanup;   /* TRUE */
494             }
495 
496             /* Bytes match (to shortest length), compare lengths */
497 
498             if (Length0 < Length1)
499             {
500                 LocalResult = TRUE;
501             }
502             break;
503 
504         default:
505 
506             Status = AE_AML_INTERNAL;
507             break;
508         }
509     }
510 
511 Cleanup:
512 
513     /* New object was created if implicit conversion performed - delete */
514 
515     if (LocalOperand1 != Operand1)
516     {
517         AcpiUtRemoveReference (LocalOperand1);
518     }
519 
520     /* Return the logical result and status */
521 
522     *LogicalResult = LocalResult;
523     return_ACPI_STATUS (Status);
524 }
525