linux/drivers/acpi/acpica/exmisc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
   5 *
   6 * Copyright (C) 2000 - 2020, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "acinterp.h"
  13#include "amlcode.h"
  14
  15#define _COMPONENT          ACPI_EXECUTER
  16ACPI_MODULE_NAME("exmisc")
  17
  18/*******************************************************************************
  19 *
  20 * FUNCTION:    acpi_ex_get_object_reference
  21 *
  22 * PARAMETERS:  obj_desc            - Create a reference to this object
  23 *              return_desc         - Where to store the reference
  24 *              walk_state          - Current state
  25 *
  26 * RETURN:      Status
  27 *
  28 * DESCRIPTION: Obtain and return a "reference" to the target object
  29 *              Common code for the ref_of_op and the cond_ref_of_op.
  30 *
  31 ******************************************************************************/
  32acpi_status
  33acpi_ex_get_object_reference(union acpi_operand_object *obj_desc,
  34                             union acpi_operand_object **return_desc,
  35                             struct acpi_walk_state *walk_state)
  36{
  37        union acpi_operand_object *reference_obj;
  38        union acpi_operand_object *referenced_obj;
  39
  40        ACPI_FUNCTION_TRACE_PTR(ex_get_object_reference, obj_desc);
  41
  42        *return_desc = NULL;
  43
  44        switch (ACPI_GET_DESCRIPTOR_TYPE(obj_desc)) {
  45        case ACPI_DESC_TYPE_OPERAND:
  46
  47                if (obj_desc->common.type != ACPI_TYPE_LOCAL_REFERENCE) {
  48                        return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
  49                }
  50
  51                /*
  52                 * Must be a reference to a Local or Arg
  53                 */
  54                switch (obj_desc->reference.class) {
  55                case ACPI_REFCLASS_LOCAL:
  56                case ACPI_REFCLASS_ARG:
  57                case ACPI_REFCLASS_DEBUG:
  58
  59                        /* The referenced object is the pseudo-node for the local/arg */
  60
  61                        referenced_obj = obj_desc->reference.object;
  62                        break;
  63
  64                default:
  65
  66                        ACPI_ERROR((AE_INFO, "Invalid Reference Class 0x%2.2X",
  67                                    obj_desc->reference.class));
  68                        return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
  69                }
  70                break;
  71
  72        case ACPI_DESC_TYPE_NAMED:
  73                /*
  74                 * A named reference that has already been resolved to a Node
  75                 */
  76                referenced_obj = obj_desc;
  77                break;
  78
  79        default:
  80
  81                ACPI_ERROR((AE_INFO, "Invalid descriptor type 0x%X",
  82                            ACPI_GET_DESCRIPTOR_TYPE(obj_desc)));
  83                return_ACPI_STATUS(AE_TYPE);
  84        }
  85
  86        /* Create a new reference object */
  87
  88        reference_obj =
  89            acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
  90        if (!reference_obj) {
  91                return_ACPI_STATUS(AE_NO_MEMORY);
  92        }
  93
  94        reference_obj->reference.class = ACPI_REFCLASS_REFOF;
  95        reference_obj->reference.object = referenced_obj;
  96        *return_desc = reference_obj;
  97
  98        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
  99                          "Object %p Type [%s], returning Reference %p\n",
 100                          obj_desc, acpi_ut_get_object_type_name(obj_desc),
 101                          *return_desc));
 102
 103        return_ACPI_STATUS(AE_OK);
 104}
 105
 106/*******************************************************************************
 107 *
 108 * FUNCTION:    acpi_ex_do_math_op
 109 *
 110 * PARAMETERS:  opcode              - AML opcode
 111 *              integer0            - Integer operand #0
 112 *              integer1            - Integer operand #1
 113 *
 114 * RETURN:      Integer result of the operation
 115 *
 116 * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
 117 *              math functions here is to prevent a lot of pointer dereferencing
 118 *              to obtain the operands.
 119 *
 120 ******************************************************************************/
 121
 122u64 acpi_ex_do_math_op(u16 opcode, u64 integer0, u64 integer1)
 123{
 124
 125        ACPI_FUNCTION_ENTRY();
 126
 127        switch (opcode) {
 128        case AML_ADD_OP:        /* Add (Integer0, Integer1, Result) */
 129
 130                return (integer0 + integer1);
 131
 132        case AML_BIT_AND_OP:    /* And (Integer0, Integer1, Result) */
 133
 134                return (integer0 & integer1);
 135
 136        case AML_BIT_NAND_OP:   /* NAnd (Integer0, Integer1, Result) */
 137
 138                return (~(integer0 & integer1));
 139
 140        case AML_BIT_OR_OP:     /* Or (Integer0, Integer1, Result) */
 141
 142                return (integer0 | integer1);
 143
 144        case AML_BIT_NOR_OP:    /* NOr (Integer0, Integer1, Result) */
 145
 146                return (~(integer0 | integer1));
 147
 148        case AML_BIT_XOR_OP:    /* XOr (Integer0, Integer1, Result) */
 149
 150                return (integer0 ^ integer1);
 151
 152        case AML_MULTIPLY_OP:   /* Multiply (Integer0, Integer1, Result) */
 153
 154                return (integer0 * integer1);
 155
 156        case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */
 157
 158                /*
 159                 * We need to check if the shiftcount is larger than the integer bit
 160                 * width since the behavior of this is not well-defined in the C language.
 161                 */
 162                if (integer1 >= acpi_gbl_integer_bit_width) {
 163                        return (0);
 164                }
 165                return (integer0 << integer1);
 166
 167        case AML_SHIFT_RIGHT_OP:        /* shift_right (Operand, shift_count, Result) */
 168
 169                /*
 170                 * We need to check if the shiftcount is larger than the integer bit
 171                 * width since the behavior of this is not well-defined in the C language.
 172                 */
 173                if (integer1 >= acpi_gbl_integer_bit_width) {
 174                        return (0);
 175                }
 176                return (integer0 >> integer1);
 177
 178        case AML_SUBTRACT_OP:   /* Subtract (Integer0, Integer1, Result) */
 179
 180                return (integer0 - integer1);
 181
 182        default:
 183
 184                return (0);
 185        }
 186}
 187
 188/*******************************************************************************
 189 *
 190 * FUNCTION:    acpi_ex_do_logical_numeric_op
 191 *
 192 * PARAMETERS:  opcode              - AML opcode
 193 *              integer0            - Integer operand #0
 194 *              integer1            - Integer operand #1
 195 *              logical_result      - TRUE/FALSE result of the operation
 196 *
 197 * RETURN:      Status
 198 *
 199 * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
 200 *              operators (LAnd and LOr), both operands must be integers.
 201 *
 202 *              Note: cleanest machine code seems to be produced by the code
 203 *              below, rather than using statements of the form:
 204 *                  Result = (Integer0 && Integer1);
 205 *
 206 ******************************************************************************/
 207
 208acpi_status
 209acpi_ex_do_logical_numeric_op(u16 opcode,
 210                              u64 integer0, u64 integer1, u8 *logical_result)
 211{
 212        acpi_status status = AE_OK;
 213        u8 local_result = FALSE;
 214
 215        ACPI_FUNCTION_TRACE(ex_do_logical_numeric_op);
 216
 217        switch (opcode) {
 218        case AML_LOGICAL_AND_OP:        /* LAnd (Integer0, Integer1) */
 219
 220                if (integer0 && integer1) {
 221                        local_result = TRUE;
 222                }
 223                break;
 224
 225        case AML_LOGICAL_OR_OP: /* LOr (Integer0, Integer1) */
 226
 227                if (integer0 || integer1) {
 228                        local_result = TRUE;
 229                }
 230                break;
 231
 232        default:
 233
 234                ACPI_ERROR((AE_INFO,
 235                            "Invalid numeric logical opcode: %X", opcode));
 236                status = AE_AML_INTERNAL;
 237                break;
 238        }
 239
 240        /* Return the logical result and status */
 241
 242        *logical_result = local_result;
 243        return_ACPI_STATUS(status);
 244}
 245
 246/*******************************************************************************
 247 *
 248 * FUNCTION:    acpi_ex_do_logical_op
 249 *
 250 * PARAMETERS:  opcode              - AML opcode
 251 *              operand0            - operand #0
 252 *              operand1            - operand #1
 253 *              logical_result      - TRUE/FALSE result of the operation
 254 *
 255 * RETURN:      Status
 256 *
 257 * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
 258 *              functions here is to prevent a lot of pointer dereferencing
 259 *              to obtain the operands and to simplify the generation of the
 260 *              logical value. For the Numeric operators (LAnd and LOr), both
 261 *              operands must be integers. For the other logical operators,
 262 *              operands can be any combination of Integer/String/Buffer. The
 263 *              first operand determines the type to which the second operand
 264 *              will be converted.
 265 *
 266 *              Note: cleanest machine code seems to be produced by the code
 267 *              below, rather than using statements of the form:
 268 *                  Result = (Operand0 == Operand1);
 269 *
 270 ******************************************************************************/
 271
 272acpi_status
 273acpi_ex_do_logical_op(u16 opcode,
 274                      union acpi_operand_object *operand0,
 275                      union acpi_operand_object *operand1, u8 * logical_result)
 276{
 277        union acpi_operand_object *local_operand1 = operand1;
 278        u64 integer0;
 279        u64 integer1;
 280        u32 length0;
 281        u32 length1;
 282        acpi_status status = AE_OK;
 283        u8 local_result = FALSE;
 284        int compare;
 285
 286        ACPI_FUNCTION_TRACE(ex_do_logical_op);
 287
 288        /*
 289         * Convert the second operand if necessary. The first operand
 290         * determines the type of the second operand, (See the Data Types
 291         * section of the ACPI 3.0+ specification.)  Both object types are
 292         * guaranteed to be either Integer/String/Buffer by the operand
 293         * resolution mechanism.
 294         */
 295        switch (operand0->common.type) {
 296        case ACPI_TYPE_INTEGER:
 297
 298                status = acpi_ex_convert_to_integer(operand1, &local_operand1,
 299                                                    ACPI_IMPLICIT_CONVERSION);
 300                break;
 301
 302        case ACPI_TYPE_STRING:
 303
 304                status =
 305                    acpi_ex_convert_to_string(operand1, &local_operand1,
 306                                              ACPI_IMPLICIT_CONVERT_HEX);
 307                break;
 308
 309        case ACPI_TYPE_BUFFER:
 310
 311                status = acpi_ex_convert_to_buffer(operand1, &local_operand1);
 312                break;
 313
 314        default:
 315
 316                ACPI_ERROR((AE_INFO,
 317                            "Invalid object type for logical operator: %X",
 318                            operand0->common.type));
 319                status = AE_AML_INTERNAL;
 320                break;
 321        }
 322
 323        if (ACPI_FAILURE(status)) {
 324                goto cleanup;
 325        }
 326
 327        /*
 328         * Two cases: 1) Both Integers, 2) Both Strings or Buffers
 329         */
 330        if (operand0->common.type == ACPI_TYPE_INTEGER) {
 331                /*
 332                 * 1) Both operands are of type integer
 333                 *    Note: local_operand1 may have changed above
 334                 */
 335                integer0 = operand0->integer.value;
 336                integer1 = local_operand1->integer.value;
 337
 338                switch (opcode) {
 339                case AML_LOGICAL_EQUAL_OP:      /* LEqual (Operand0, Operand1) */
 340
 341                        if (integer0 == integer1) {
 342                                local_result = TRUE;
 343                        }
 344                        break;
 345
 346                case AML_LOGICAL_GREATER_OP:    /* LGreater (Operand0, Operand1) */
 347
 348                        if (integer0 > integer1) {
 349                                local_result = TRUE;
 350                        }
 351                        break;
 352
 353                case AML_LOGICAL_LESS_OP:       /* LLess (Operand0, Operand1) */
 354
 355                        if (integer0 < integer1) {
 356                                local_result = TRUE;
 357                        }
 358                        break;
 359
 360                default:
 361
 362                        ACPI_ERROR((AE_INFO,
 363                                    "Invalid comparison opcode: %X", opcode));
 364                        status = AE_AML_INTERNAL;
 365                        break;
 366                }
 367        } else {
 368                /*
 369                 * 2) Both operands are Strings or both are Buffers
 370                 *    Note: Code below takes advantage of common Buffer/String
 371                 *          object fields. local_operand1 may have changed above. Use
 372                 *          memcmp to handle nulls in buffers.
 373                 */
 374                length0 = operand0->buffer.length;
 375                length1 = local_operand1->buffer.length;
 376
 377                /* Lexicographic compare: compare the data bytes */
 378
 379                compare = memcmp(operand0->buffer.pointer,
 380                                 local_operand1->buffer.pointer,
 381                                 (length0 > length1) ? length1 : length0);
 382
 383                switch (opcode) {
 384                case AML_LOGICAL_EQUAL_OP:      /* LEqual (Operand0, Operand1) */
 385
 386                        /* Length and all bytes must be equal */
 387
 388                        if ((length0 == length1) && (compare == 0)) {
 389
 390                                /* Length and all bytes match ==> TRUE */
 391
 392                                local_result = TRUE;
 393                        }
 394                        break;
 395
 396                case AML_LOGICAL_GREATER_OP:    /* LGreater (Operand0, Operand1) */
 397
 398                        if (compare > 0) {
 399                                local_result = TRUE;
 400                                goto cleanup;   /* TRUE */
 401                        }
 402                        if (compare < 0) {
 403                                goto cleanup;   /* FALSE */
 404                        }
 405
 406                        /* Bytes match (to shortest length), compare lengths */
 407
 408                        if (length0 > length1) {
 409                                local_result = TRUE;
 410                        }
 411                        break;
 412
 413                case AML_LOGICAL_LESS_OP:       /* LLess (Operand0, Operand1) */
 414
 415                        if (compare > 0) {
 416                                goto cleanup;   /* FALSE */
 417                        }
 418                        if (compare < 0) {
 419                                local_result = TRUE;
 420                                goto cleanup;   /* TRUE */
 421                        }
 422
 423                        /* Bytes match (to shortest length), compare lengths */
 424
 425                        if (length0 < length1) {
 426                                local_result = TRUE;
 427                        }
 428                        break;
 429
 430                default:
 431
 432                        ACPI_ERROR((AE_INFO,
 433                                    "Invalid comparison opcode: %X", opcode));
 434                        status = AE_AML_INTERNAL;
 435                        break;
 436                }
 437        }
 438
 439cleanup:
 440
 441        /* New object was created if implicit conversion performed - delete */
 442
 443        if (local_operand1 != operand1) {
 444                acpi_ut_remove_reference(local_operand1);
 445        }
 446
 447        /* Return the logical result and status */
 448
 449        *logical_result = local_result;
 450        return_ACPI_STATUS(status);
 451}
 452