xref: /freebsd/sys/contrib/dev/acpica/components/executer/exmisc.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /******************************************************************************
2  *
3  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
4  *
5  *****************************************************************************/
6 
7 /******************************************************************************
8  *
9  * 1. Copyright Notice
10  *
11  * Some or all of this work - Copyright (c) 1999 - 2023, Intel Corp.
12  * All rights reserved.
13  *
14  * 2. License
15  *
16  * 2.1. This is your license from Intel Corp. under its intellectual property
17  * rights. You may have additional license terms from the party that provided
18  * you this software, covering your right to use that party's intellectual
19  * property rights.
20  *
21  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22  * copy of the source code appearing in this file ("Covered Code") an
23  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24  * base code distributed originally by Intel ("Original Intel Code") to copy,
25  * make derivatives, distribute, use and display any portion of the Covered
26  * Code in any form, with the right to sublicense such rights; and
27  *
28  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29  * license (with the right to sublicense), under only those claims of Intel
30  * patents that are infringed by the Original Intel Code, to make, use, sell,
31  * offer to sell, and import the Covered Code and derivative works thereof
32  * solely to the minimum extent necessary to exercise the above copyright
33  * license, and in no event shall the patent license extend to any additions
34  * to or modifications of the Original Intel Code. No other license or right
35  * is granted directly or by implication, estoppel or otherwise;
36  *
37  * The above copyright and patent license is granted only if the following
38  * conditions are met:
39  *
40  * 3. Conditions
41  *
42  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43  * Redistribution of source code of any substantial portion of the Covered
44  * Code or modification with rights to further distribute source must include
45  * the above Copyright Notice, the above License, this list of Conditions,
46  * and the following Disclaimer and Export Compliance provision. In addition,
47  * Licensee must cause all Covered Code to which Licensee contributes to
48  * contain a file documenting the changes Licensee made to create that Covered
49  * Code and the date of any change. Licensee must include in that file the
50  * documentation of any changes made by any predecessor Licensee. Licensee
51  * must include a prominent statement that the modification is derived,
52  * directly or indirectly, from Original Intel Code.
53  *
54  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55  * Redistribution of source code of any substantial portion of the Covered
56  * Code or modification without rights to further distribute source must
57  * include the following Disclaimer and Export Compliance provision in the
58  * documentation and/or other materials provided with distribution. In
59  * addition, Licensee may not authorize further sublicense of source of any
60  * portion of the Covered Code, and must include terms to the effect that the
61  * license from Licensee to its licensee is limited to the intellectual
62  * property embodied in the software Licensee provides to its licensee, and
63  * not to intellectual property embodied in modifications its licensee may
64  * make.
65  *
66  * 3.3. Redistribution of Executable. Redistribution in executable form of any
67  * substantial portion of the Covered Code or modification must reproduce the
68  * above Copyright Notice, and the following Disclaimer and Export Compliance
69  * provision in the documentation and/or other materials provided with the
70  * distribution.
71  *
72  * 3.4. Intel retains all right, title, and interest in and to the Original
73  * Intel Code.
74  *
75  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76  * Intel shall be used in advertising or otherwise to promote the sale, use or
77  * other dealings in products derived from or relating to the Covered Code
78  * without prior written authorization from Intel.
79  *
80  * 4. Disclaimer and Export Compliance
81  *
82  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83  * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
85  * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
86 
87  * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
88  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
89  * PARTICULAR PURPOSE.
90  *
91  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
92  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
93  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
94  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
95  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
96  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
97  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
98  * LIMITED REMEDY.
99  *
100  * 4.3. Licensee shall not export, either directly or indirectly, any of this
101  * software or system incorporating such software without first obtaining any
102  * required license or other approval from the U. S. Department of Commerce or
103  * any other agency or department of the United States Government. In the
104  * event Licensee exports any such software from the United States or
105  * re-exports any such software from a foreign destination, Licensee shall
106  * ensure that the distribution and export/re-export of the software is in
107  * compliance with all laws, regulations, orders, or other restrictions of the
108  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
109  * any of its subsidiaries will export/re-export any technical data, process,
110  * software, or service, directly or indirectly, to any country for which the
111  * United States government or any agency thereof requires an export license,
112  * other governmental approval, or letter of assurance, without first obtaining
113  * such license, approval or letter.
114  *
115  *****************************************************************************
116  *
117  * Alternatively, you may choose to be licensed under the terms of the
118  * following license:
119  *
120  * Redistribution and use in source and binary forms, with or without
121  * modification, are permitted provided that the following conditions
122  * are met:
123  * 1. Redistributions of source code must retain the above copyright
124  *    notice, this list of conditions, and the following disclaimer,
125  *    without modification.
126  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
127  *    substantially similar to the "NO WARRANTY" disclaimer below
128  *    ("Disclaimer") and any redistribution must be conditioned upon
129  *    including a substantially similar Disclaimer requirement for further
130  *    binary redistribution.
131  * 3. Neither the names of the above-listed copyright holders nor the names
132  *    of any contributors may be used to endorse or promote products derived
133  *    from this software without specific prior written permission.
134  *
135  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
136  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
137  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
138  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
139  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
140  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
141  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
142  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
143  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
144  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
145  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
146  *
147  * Alternatively, you may choose to be licensed under the terms of the
148  * GNU General Public License ("GPL") version 2 as published by the Free
149  * Software Foundation.
150  *
151  *****************************************************************************/
152 
153 #include <contrib/dev/acpica/include/acpi.h>
154 #include <contrib/dev/acpica/include/accommon.h>
155 #include <contrib/dev/acpica/include/acinterp.h>
156 #include <contrib/dev/acpica/include/amlcode.h>
157 
158 
159 #define _COMPONENT          ACPI_EXECUTER
160         ACPI_MODULE_NAME    ("exmisc")
161 
162 
163 /*******************************************************************************
164  *
165  * FUNCTION:    AcpiExGetObjectReference
166  *
167  * PARAMETERS:  ObjDesc             - Create a reference to this object
168  *              ReturnDesc          - Where to store the reference
169  *              WalkState           - Current state
170  *
171  * RETURN:      Status
172  *
173  * DESCRIPTION: Obtain and return a "reference" to the target object
174  *              Common code for the RefOfOp and the CondRefOfOp.
175  *
176  ******************************************************************************/
177 
178 ACPI_STATUS
179 AcpiExGetObjectReference (
180     ACPI_OPERAND_OBJECT     *ObjDesc,
181     ACPI_OPERAND_OBJECT     **ReturnDesc,
182     ACPI_WALK_STATE         *WalkState)
183 {
184     ACPI_OPERAND_OBJECT     *ReferenceObj;
185     ACPI_OPERAND_OBJECT     *ReferencedObj;
186 
187 
188     ACPI_FUNCTION_TRACE_PTR (ExGetObjectReference, ObjDesc);
189 
190 
191     *ReturnDesc = NULL;
192 
193     switch (ACPI_GET_DESCRIPTOR_TYPE (ObjDesc))
194     {
195     case ACPI_DESC_TYPE_OPERAND:
196 
197         if (ObjDesc->Common.Type != ACPI_TYPE_LOCAL_REFERENCE)
198         {
199             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
200         }
201 
202         /*
203          * Must be a reference to a Local or Arg
204          */
205         switch (ObjDesc->Reference.Class)
206         {
207         case ACPI_REFCLASS_LOCAL:
208         case ACPI_REFCLASS_ARG:
209         case ACPI_REFCLASS_DEBUG:
210 
211             /* The referenced object is the pseudo-node for the local/arg */
212 
213             ReferencedObj = ObjDesc->Reference.Object;
214             break;
215 
216         default:
217 
218             ACPI_ERROR ((AE_INFO, "Invalid Reference Class 0x%2.2X",
219                 ObjDesc->Reference.Class));
220             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
221         }
222         break;
223 
224     case ACPI_DESC_TYPE_NAMED:
225         /*
226          * A named reference that has already been resolved to a Node
227          */
228         ReferencedObj = ObjDesc;
229         break;
230 
231     default:
232 
233         ACPI_ERROR ((AE_INFO, "Invalid descriptor type 0x%X",
234             ACPI_GET_DESCRIPTOR_TYPE (ObjDesc)));
235         return_ACPI_STATUS (AE_TYPE);
236     }
237 
238 
239     /* Create a new reference object */
240 
241     ReferenceObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE);
242     if (!ReferenceObj)
243     {
244         return_ACPI_STATUS (AE_NO_MEMORY);
245     }
246 
247     ReferenceObj->Reference.Class = ACPI_REFCLASS_REFOF;
248     ReferenceObj->Reference.Object = ReferencedObj;
249     *ReturnDesc = ReferenceObj;
250 
251     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
252         "Object %p Type [%s], returning Reference %p\n",
253         ObjDesc, AcpiUtGetObjectTypeName (ObjDesc), *ReturnDesc));
254 
255     return_ACPI_STATUS (AE_OK);
256 }
257 
258 
259 /*******************************************************************************
260  *
261  * FUNCTION:    AcpiExDoMathOp
262  *
263  * PARAMETERS:  Opcode              - AML opcode
264  *              Integer0            - Integer operand #0
265  *              Integer1            - Integer operand #1
266  *
267  * RETURN:      Integer result of the operation
268  *
269  * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
270  *              math functions here is to prevent a lot of pointer dereferencing
271  *              to obtain the operands.
272  *
273  ******************************************************************************/
274 
275 UINT64
276 AcpiExDoMathOp (
277     UINT16                  Opcode,
278     UINT64                  Integer0,
279     UINT64                  Integer1)
280 {
281 
282     ACPI_FUNCTION_ENTRY ();
283 
284 
285     switch (Opcode)
286     {
287     case AML_ADD_OP:                /* Add (Integer0, Integer1, Result) */
288 
289         return (Integer0 + Integer1);
290 
291     case AML_BIT_AND_OP:            /* And (Integer0, Integer1, Result) */
292 
293         return (Integer0 & Integer1);
294 
295     case AML_BIT_NAND_OP:           /* NAnd (Integer0, Integer1, Result) */
296 
297         return (~(Integer0 & Integer1));
298 
299     case AML_BIT_OR_OP:             /* Or (Integer0, Integer1, Result) */
300 
301         return (Integer0 | Integer1);
302 
303     case AML_BIT_NOR_OP:            /* NOr (Integer0, Integer1, Result) */
304 
305         return (~(Integer0 | Integer1));
306 
307     case AML_BIT_XOR_OP:            /* XOr (Integer0, Integer1, Result) */
308 
309         return (Integer0 ^ Integer1);
310 
311     case AML_MULTIPLY_OP:           /* Multiply (Integer0, Integer1, Result) */
312 
313         return (Integer0 * Integer1);
314 
315     case AML_SHIFT_LEFT_OP:         /* ShiftLeft (Operand, ShiftCount, Result)*/
316 
317         /*
318          * We need to check if the shiftcount is larger than the integer bit
319          * width since the behavior of this is not well-defined in the C language.
320          */
321         if (Integer1 >= AcpiGbl_IntegerBitWidth)
322         {
323             return (0);
324         }
325         return (Integer0 << Integer1);
326 
327     case AML_SHIFT_RIGHT_OP:        /* ShiftRight (Operand, ShiftCount, Result) */
328 
329         /*
330          * We need to check if the shiftcount is larger than the integer bit
331          * width since the behavior of this is not well-defined in the C language.
332          */
333         if (Integer1 >= AcpiGbl_IntegerBitWidth)
334         {
335             return (0);
336         }
337         return (Integer0 >> Integer1);
338 
339     case AML_SUBTRACT_OP:           /* Subtract (Integer0, Integer1, Result) */
340 
341         return (Integer0 - Integer1);
342 
343     default:
344 
345         return (0);
346     }
347 }
348 
349 
350 /*******************************************************************************
351  *
352  * FUNCTION:    AcpiExDoLogicalNumericOp
353  *
354  * PARAMETERS:  Opcode              - AML opcode
355  *              Integer0            - Integer operand #0
356  *              Integer1            - Integer operand #1
357  *              LogicalResult       - TRUE/FALSE result of the operation
358  *
359  * RETURN:      Status
360  *
361  * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
362  *              operators (LAnd and LOr), both operands must be integers.
363  *
364  *              Note: cleanest machine code seems to be produced by the code
365  *              below, rather than using statements of the form:
366  *                  Result = (Integer0 && Integer1);
367  *
368  ******************************************************************************/
369 
370 ACPI_STATUS
371 AcpiExDoLogicalNumericOp (
372     UINT16                  Opcode,
373     UINT64                  Integer0,
374     UINT64                  Integer1,
375     BOOLEAN                 *LogicalResult)
376 {
377     ACPI_STATUS             Status = AE_OK;
378     BOOLEAN                 LocalResult = FALSE;
379 
380 
381     ACPI_FUNCTION_TRACE (ExDoLogicalNumericOp);
382 
383 
384     switch (Opcode)
385     {
386     case AML_LOGICAL_AND_OP:        /* LAnd (Integer0, Integer1) */
387 
388         if (Integer0 && Integer1)
389         {
390             LocalResult = TRUE;
391         }
392         break;
393 
394     case AML_LOGICAL_OR_OP:         /* LOr (Integer0, Integer1) */
395 
396         if (Integer0 || Integer1)
397         {
398             LocalResult = TRUE;
399         }
400         break;
401 
402     default:
403 
404         ACPI_ERROR ((AE_INFO,
405             "Invalid numeric logical opcode: %X", Opcode));
406         Status = AE_AML_INTERNAL;
407         break;
408     }
409 
410     /* Return the logical result and status */
411 
412     *LogicalResult = LocalResult;
413     return_ACPI_STATUS (Status);
414 }
415 
416 
417 /*******************************************************************************
418  *
419  * FUNCTION:    AcpiExDoLogicalOp
420  *
421  * PARAMETERS:  Opcode              - AML opcode
422  *              Operand0            - operand #0
423  *              Operand1            - operand #1
424  *              LogicalResult       - TRUE/FALSE result of the operation
425  *
426  * RETURN:      Status
427  *
428  * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
429  *              functions here is to prevent a lot of pointer dereferencing
430  *              to obtain the operands and to simplify the generation of the
431  *              logical value. For the Numeric operators (LAnd and LOr), both
432  *              operands must be integers. For the other logical operators,
433  *              operands can be any combination of Integer/String/Buffer. The
434  *              first operand determines the type to which the second operand
435  *              will be converted.
436  *
437  *              Note: cleanest machine code seems to be produced by the code
438  *              below, rather than using statements of the form:
439  *                  Result = (Operand0 == Operand1);
440  *
441  ******************************************************************************/
442 
443 ACPI_STATUS
444 AcpiExDoLogicalOp (
445     UINT16                  Opcode,
446     ACPI_OPERAND_OBJECT     *Operand0,
447     ACPI_OPERAND_OBJECT     *Operand1,
448     BOOLEAN                 *LogicalResult)
449 {
450     ACPI_OPERAND_OBJECT     *LocalOperand1 = Operand1;
451     UINT64                  Integer0;
452     UINT64                  Integer1;
453     UINT32                  Length0;
454     UINT32                  Length1;
455     ACPI_STATUS             Status = AE_OK;
456     BOOLEAN                 LocalResult = FALSE;
457     int                     Compare;
458 
459 
460     ACPI_FUNCTION_TRACE (ExDoLogicalOp);
461 
462 
463     /*
464      * Convert the second operand if necessary. The first operand
465      * determines the type of the second operand, (See the Data Types
466      * section of the ACPI 3.0+ specification.)  Both object types are
467      * guaranteed to be either Integer/String/Buffer by the operand
468      * resolution mechanism.
469      */
470     switch (Operand0->Common.Type)
471     {
472     case ACPI_TYPE_INTEGER:
473 
474         Status = AcpiExConvertToInteger (Operand1, &LocalOperand1,
475             ACPI_IMPLICIT_CONVERSION);
476         break;
477 
478     case ACPI_TYPE_STRING:
479 
480         Status = AcpiExConvertToString (
481             Operand1, &LocalOperand1, ACPI_IMPLICIT_CONVERT_HEX);
482         break;
483 
484     case ACPI_TYPE_BUFFER:
485 
486         Status = AcpiExConvertToBuffer (Operand1, &LocalOperand1);
487         break;
488 
489     default:
490 
491         ACPI_ERROR ((AE_INFO,
492             "Invalid object type for logical operator: %X",
493             Operand0->Common.Type));
494         Status = AE_AML_INTERNAL;
495         break;
496     }
497 
498     if (ACPI_FAILURE (Status))
499     {
500         goto Cleanup;
501     }
502 
503     /*
504      * Two cases: 1) Both Integers, 2) Both Strings or Buffers
505      */
506     if (Operand0->Common.Type == ACPI_TYPE_INTEGER)
507     {
508         /*
509          * 1) Both operands are of type integer
510          *    Note: LocalOperand1 may have changed above
511          */
512         Integer0 = Operand0->Integer.Value;
513         Integer1 = LocalOperand1->Integer.Value;
514 
515         switch (Opcode)
516         {
517         case AML_LOGICAL_EQUAL_OP:          /* LEqual (Operand0, Operand1) */
518 
519             if (Integer0 == Integer1)
520             {
521                 LocalResult = TRUE;
522             }
523             break;
524 
525         case AML_LOGICAL_GREATER_OP:        /* LGreater (Operand0, Operand1) */
526 
527             if (Integer0 > Integer1)
528             {
529                 LocalResult = TRUE;
530             }
531             break;
532 
533         case AML_LOGICAL_LESS_OP:           /* LLess (Operand0, Operand1) */
534 
535             if (Integer0 < Integer1)
536             {
537                 LocalResult = TRUE;
538             }
539             break;
540 
541         default:
542 
543             ACPI_ERROR ((AE_INFO,
544                 "Invalid comparison opcode: %X", Opcode));
545             Status = AE_AML_INTERNAL;
546             break;
547         }
548     }
549     else
550     {
551         /*
552          * 2) Both operands are Strings or both are Buffers
553          *    Note: Code below takes advantage of common Buffer/String
554          *          object fields. LocalOperand1 may have changed above. Use
555          *          memcmp to handle nulls in buffers.
556          */
557         Length0 = Operand0->Buffer.Length;
558         Length1 = LocalOperand1->Buffer.Length;
559 
560         /* Lexicographic compare: compare the data bytes */
561 
562         Compare = memcmp (Operand0->Buffer.Pointer,
563             LocalOperand1->Buffer.Pointer,
564             (Length0 > Length1) ? Length1 : Length0);
565 
566         switch (Opcode)
567         {
568         case AML_LOGICAL_EQUAL_OP:      /* LEqual (Operand0, Operand1) */
569 
570             /* Length and all bytes must be equal */
571 
572             if ((Length0 == Length1) &&
573                 (Compare == 0))
574             {
575                 /* Length and all bytes match ==> TRUE */
576 
577                 LocalResult = TRUE;
578             }
579             break;
580 
581         case AML_LOGICAL_GREATER_OP:    /* LGreater (Operand0, Operand1) */
582 
583             if (Compare > 0)
584             {
585                 LocalResult = TRUE;
586                 goto Cleanup;   /* TRUE */
587             }
588             if (Compare < 0)
589             {
590                 goto Cleanup;   /* FALSE */
591             }
592 
593             /* Bytes match (to shortest length), compare lengths */
594 
595             if (Length0 > Length1)
596             {
597                 LocalResult = TRUE;
598             }
599             break;
600 
601         case AML_LOGICAL_LESS_OP:       /* LLess (Operand0, Operand1) */
602 
603             if (Compare > 0)
604             {
605                 goto Cleanup;   /* FALSE */
606             }
607             if (Compare < 0)
608             {
609                 LocalResult = TRUE;
610                 goto Cleanup;   /* TRUE */
611             }
612 
613             /* Bytes match (to shortest length), compare lengths */
614 
615             if (Length0 < Length1)
616             {
617                 LocalResult = TRUE;
618             }
619             break;
620 
621         default:
622 
623             ACPI_ERROR ((AE_INFO,
624                 "Invalid comparison opcode: %X", Opcode));
625             Status = AE_AML_INTERNAL;
626             break;
627         }
628     }
629 
630 Cleanup:
631 
632     /* New object was created if implicit conversion performed - delete */
633 
634     if (LocalOperand1 != Operand1)
635     {
636         AcpiUtRemoveReference (LocalOperand1);
637     }
638 
639     /* Return the logical result and status */
640 
641     *LogicalResult = LocalResult;
642     return_ACPI_STATUS (Status);
643 }
644