Home | History | Annotate | Line # | Download | only in executer
exmisc.c revision 1.1.1.12
      1 /******************************************************************************
      2  *
      3  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2017, 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_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