Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acinterp.h"
0013 #include "amlcode.h"
0014 
0015 #define _COMPONENT          ACPI_EXECUTER
0016 ACPI_MODULE_NAME("exmisc")
0017 
0018 /*******************************************************************************
0019  *
0020  * FUNCTION:    acpi_ex_get_object_reference
0021  *
0022  * PARAMETERS:  obj_desc            - Create a reference to this object
0023  *              return_desc         - Where to store the reference
0024  *              walk_state          - Current state
0025  *
0026  * RETURN:      Status
0027  *
0028  * DESCRIPTION: Obtain and return a "reference" to the target object
0029  *              Common code for the ref_of_op and the cond_ref_of_op.
0030  *
0031  ******************************************************************************/
0032 acpi_status
0033 acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
0034                  union acpi_operand_object **return_desc,
0035                  struct acpi_walk_state *walk_state)
0036 {
0037     union acpi_operand_object *reference_obj;
0038     union acpi_operand_object *referenced_obj;
0039 
0040     ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc);
0041 
0042     *return_desc = NULL;
0043 
0044     switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
0045     case ACPI_DESC_TYPE_OPERAND:
0046 
0047         if (obj_desc->common.type != ACPI_TYPE_LOCAL_REFERENCE) {
0048             return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0049         }
0050 
0051         /*
0052          * Must be a reference to a Local or Arg
0053          */
0054         switch (obj_desc->reference.class) {
0055         case ACPI_REFCLASS_LOCAL:
0056         case ACPI_REFCLASS_ARG:
0057         case ACPI_REFCLASS_DEBUG:
0058 
0059             /* The referenced object is the pseudo-node for the local/arg */
0060 
0061             referenced_obj = obj_desc->reference.object;
0062             break;
0063 
0064         default:
0065 
0066             ACPI_ERROR((AE_INFO, "Invalid Reference Class 0x%2.2X",
0067                     obj_desc->reference.class));
0068             return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0069         }
0070         break;
0071 
0072     case ACPI_DESC_TYPE_NAMED:
0073         /*
0074          * A named reference that has already been resolved to a Node
0075          */
0076         referenced_obj = obj_desc;
0077         break;
0078 
0079     default:
0080 
0081         ACPI_ERROR((AE_INFO, "Invalid descriptor type 0x%X",
0082                 ACPI_GET_DESCRIPTOR_TYPE(obj_desc)));
0083         return_ACPI_STATUS(AE_TYPE);
0084     }
0085 
0086     /* Create a new reference object */
0087 
0088     reference_obj =
0089         acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
0090     if (!reference_obj) {
0091         return_ACPI_STATUS(AE_NO_MEMORY);
0092     }
0093 
0094     reference_obj->reference.class = ACPI_REFCLASS_REFOF;
0095     reference_obj->reference.object = referenced_obj;
0096     *return_desc = reference_obj;
0097 
0098     ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0099               "Object %p Type [%s], returning Reference %p\n",
0100               obj_desc, acpi_ut_get_object_type_name(obj_desc),
0101               *return_desc));
0102 
0103     return_ACPI_STATUS(AE_OK);
0104 }
0105 
0106 /*******************************************************************************
0107  *
0108  * FUNCTION:    acpi_ex_do_math_op
0109  *
0110  * PARAMETERS:  opcode              - AML opcode
0111  *              integer0            - Integer operand #0
0112  *              integer1            - Integer operand #1
0113  *
0114  * RETURN:      Integer result of the operation
0115  *
0116  * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
0117  *              math functions here is to prevent a lot of pointer dereferencing
0118  *              to obtain the operands.
0119  *
0120  ******************************************************************************/
0121 
0122 u64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1)
0123 {
0124 
0125     ACPI_FUNCTION_ENTRY();
0126 
0127     switch (opcode) {
0128     case AML_ADD_OP:    /* Add (Integer0, Integer1, Result) */
0129 
0130         return (integer0 + integer1);
0131 
0132     case AML_BIT_AND_OP:    /* And (Integer0, Integer1, Result) */
0133 
0134         return (integer0 & integer1);
0135 
0136     case AML_BIT_NAND_OP:   /* NAnd (Integer0, Integer1, Result) */
0137 
0138         return (~(integer0 & integer1));
0139 
0140     case AML_BIT_OR_OP: /* Or (Integer0, Integer1, Result) */
0141 
0142         return (integer0 | integer1);
0143 
0144     case AML_BIT_NOR_OP:    /* NOr (Integer0, Integer1, Result) */
0145 
0146         return (~(integer0 | integer1));
0147 
0148     case AML_BIT_XOR_OP:    /* XOr (Integer0, Integer1, Result) */
0149 
0150         return (integer0 ^ integer1);
0151 
0152     case AML_MULTIPLY_OP:   /* Multiply (Integer0, Integer1, Result) */
0153 
0154         return (integer0 * integer1);
0155 
0156     case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */
0157 
0158         /*
0159          * We need to check if the shiftcount is larger than the integer bit
0160          * width since the behavior of this is not well-defined in the C language.
0161          */
0162         if (integer1 >= acpi_gbl_integer_bit_width) {
0163             return (0);
0164         }
0165         return (integer0 << integer1);
0166 
0167     case AML_SHIFT_RIGHT_OP:    /* shift_right (Operand, shift_count, Result) */
0168 
0169         /*
0170          * We need to check if the shiftcount is larger than the integer bit
0171          * width since the behavior of this is not well-defined in the C language.
0172          */
0173         if (integer1 >= acpi_gbl_integer_bit_width) {
0174             return (0);
0175         }
0176         return (integer0 >> integer1);
0177 
0178     case AML_SUBTRACT_OP:   /* Subtract (Integer0, Integer1, Result) */
0179 
0180         return (integer0 - integer1);
0181 
0182     default:
0183 
0184         return (0);
0185     }
0186 }
0187 
0188 /*******************************************************************************
0189  *
0190  * FUNCTION:    acpi_ex_do_logical_numeric_op
0191  *
0192  * PARAMETERS:  opcode              - AML opcode
0193  *              integer0            - Integer operand #0
0194  *              integer1            - Integer operand #1
0195  *              logical_result      - TRUE/FALSE result of the operation
0196  *
0197  * RETURN:      Status
0198  *
0199  * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
0200  *              operators (LAnd and LOr), both operands must be integers.
0201  *
0202  *              Note: cleanest machine code seems to be produced by the code
0203  *              below, rather than using statements of the form:
0204  *                  Result = (Integer0 && Integer1);
0205  *
0206  ******************************************************************************/
0207 
0208 acpi_status
0209 acpi_ex_do_logical_numeric_op(u16 opcode,
0210                   u64 integer0, u64 integer1, u8 *logical_result)
0211 {
0212     acpi_status status = AE_OK;
0213     u8 local_result = FALSE;
0214 
0215     ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op);
0216 
0217     switch (opcode) {
0218     case AML_LOGICAL_AND_OP:    /* LAnd (Integer0, Integer1) */
0219 
0220         if (integer0 && integer1) {
0221             local_result = TRUE;
0222         }
0223         break;
0224 
0225     case AML_LOGICAL_OR_OP: /* LOr (Integer0, Integer1) */
0226 
0227         if (integer0 || integer1) {
0228             local_result = TRUE;
0229         }
0230         break;
0231 
0232     default:
0233 
0234         ACPI_ERROR((AE_INFO,
0235                 "Invalid numeric logical opcode: %X", opcode));
0236         status = AE_AML_INTERNAL;
0237         break;
0238     }
0239 
0240     /* Return the logical result and status */
0241 
0242     *logical_result = local_result;
0243     return_ACPI_STATUS(status);
0244 }
0245 
0246 /*******************************************************************************
0247  *
0248  * FUNCTION:    acpi_ex_do_logical_op
0249  *
0250  * PARAMETERS:  opcode              - AML opcode
0251  *              operand0            - operand #0
0252  *              operand1            - operand #1
0253  *              logical_result      - TRUE/FALSE result of the operation
0254  *
0255  * RETURN:      Status
0256  *
0257  * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
0258  *              functions here is to prevent a lot of pointer dereferencing
0259  *              to obtain the operands and to simplify the generation of the
0260  *              logical value. For the Numeric operators (LAnd and LOr), both
0261  *              operands must be integers. For the other logical operators,
0262  *              operands can be any combination of Integer/String/Buffer. The
0263  *              first operand determines the type to which the second operand
0264  *              will be converted.
0265  *
0266  *              Note: cleanest machine code seems to be produced by the code
0267  *              below, rather than using statements of the form:
0268  *                  Result = (Operand0 == Operand1);
0269  *
0270  ******************************************************************************/
0271 
0272 acpi_status
0273 acpi_ex_do_logical_op(u16 opcode,
0274               union acpi_operand_object *operand0,
0275               union acpi_operand_object *operand1, u8 * logical_result)
0276 {
0277     union acpi_operand_object *local_operand1 = operand1;
0278     u64 integer0;
0279     u64 integer1;
0280     u32 length0;
0281     u32 length1;
0282     acpi_status status = AE_OK;
0283     u8 local_result = FALSE;
0284     int compare;
0285 
0286     ACPI_FUNCTION_TRACE(ex_do_logical_op);
0287 
0288     /*
0289      * Convert the second operand if necessary. The first operand
0290      * determines the type of the second operand, (See the Data Types
0291      * section of the ACPI 3.0+ specification.)  Both object types are
0292      * guaranteed to be either Integer/String/Buffer by the operand
0293      * resolution mechanism.
0294      */
0295     switch (operand0->common.type) {
0296     case ACPI_TYPE_INTEGER:
0297 
0298         status = acpi_ex_convert_to_integer(operand1, &local_operand1,
0299                             ACPI_IMPLICIT_CONVERSION);
0300         break;
0301 
0302     case ACPI_TYPE_STRING:
0303 
0304         status =
0305             acpi_ex_convert_to_string(operand1, &local_operand1,
0306                           ACPI_IMPLICIT_CONVERT_HEX);
0307         break;
0308 
0309     case ACPI_TYPE_BUFFER:
0310 
0311         status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
0312         break;
0313 
0314     default:
0315 
0316         ACPI_ERROR((AE_INFO,
0317                 "Invalid object type for logical operator: %X",
0318                 operand0->common.type));
0319         status = AE_AML_INTERNAL;
0320         break;
0321     }
0322 
0323     if (ACPI_FAILURE(status)) {
0324         goto cleanup;
0325     }
0326 
0327     /*
0328      * Two cases: 1) Both Integers, 2) Both Strings or Buffers
0329      */
0330     if (operand0->common.type == ACPI_TYPE_INTEGER) {
0331         /*
0332          * 1) Both operands are of type integer
0333          *    Note: local_operand1 may have changed above
0334          */
0335         integer0 = operand0->integer.value;
0336         integer1 = local_operand1->integer.value;
0337 
0338         switch (opcode) {
0339         case AML_LOGICAL_EQUAL_OP:  /* LEqual (Operand0, Operand1) */
0340 
0341             if (integer0 == integer1) {
0342                 local_result = TRUE;
0343             }
0344             break;
0345 
0346         case AML_LOGICAL_GREATER_OP:    /* LGreater (Operand0, Operand1) */
0347 
0348             if (integer0 > integer1) {
0349                 local_result = TRUE;
0350             }
0351             break;
0352 
0353         case AML_LOGICAL_LESS_OP:   /* LLess (Operand0, Operand1) */
0354 
0355             if (integer0 < integer1) {
0356                 local_result = TRUE;
0357             }
0358             break;
0359 
0360         default:
0361 
0362             ACPI_ERROR((AE_INFO,
0363                     "Invalid comparison opcode: %X", opcode));
0364             status = AE_AML_INTERNAL;
0365             break;
0366         }
0367     } else {
0368         /*
0369          * 2) Both operands are Strings or both are Buffers
0370          *    Note: Code below takes advantage of common Buffer/String
0371          *          object fields. local_operand1 may have changed above. Use
0372          *          memcmp to handle nulls in buffers.
0373          */
0374         length0 = operand0->buffer.length;
0375         length1 = local_operand1->buffer.length;
0376 
0377         /* Lexicographic compare: compare the data bytes */
0378 
0379         compare = memcmp(operand0->buffer.pointer,
0380                  local_operand1->buffer.pointer,
0381                  (length0 > length1) ? length1 : length0);
0382 
0383         switch (opcode) {
0384         case AML_LOGICAL_EQUAL_OP:  /* LEqual (Operand0, Operand1) */
0385 
0386             /* Length and all bytes must be equal */
0387 
0388             if ((length0 == length1) && (compare == 0)) {
0389 
0390                 /* Length and all bytes match ==> TRUE */
0391 
0392                 local_result = TRUE;
0393             }
0394             break;
0395 
0396         case AML_LOGICAL_GREATER_OP:    /* LGreater (Operand0, Operand1) */
0397 
0398             if (compare > 0) {
0399                 local_result = TRUE;
0400                 goto cleanup;   /* TRUE */
0401             }
0402             if (compare < 0) {
0403                 goto cleanup;   /* FALSE */
0404             }
0405 
0406             /* Bytes match (to shortest length), compare lengths */
0407 
0408             if (length0 > length1) {
0409                 local_result = TRUE;
0410             }
0411             break;
0412 
0413         case AML_LOGICAL_LESS_OP:   /* LLess (Operand0, Operand1) */
0414 
0415             if (compare > 0) {
0416                 goto cleanup;   /* FALSE */
0417             }
0418             if (compare < 0) {
0419                 local_result = TRUE;
0420                 goto cleanup;   /* TRUE */
0421             }
0422 
0423             /* Bytes match (to shortest length), compare lengths */
0424 
0425             if (length0 < length1) {
0426                 local_result = TRUE;
0427             }
0428             break;
0429 
0430         default:
0431 
0432             ACPI_ERROR((AE_INFO,
0433                     "Invalid comparison opcode: %X", opcode));
0434             status = AE_AML_INTERNAL;
0435             break;
0436         }
0437     }
0438 
0439 cleanup:
0440 
0441     /* New object was created if implicit conversion performed - delete */
0442 
0443     if (local_operand1 != operand1) {
0444         acpi_ut_remove_reference(local_operand1);
0445     }
0446 
0447     /* Return the logical result and status */
0448 
0449     *logical_result = local_result;
0450     return_ACPI_STATUS(status);
0451 }