linux/drivers/acpi/acpica/exoparg3.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: exoparg3 - AML execution - opcodes with 3 arguments
   5 *
   6 * Copyright (C) 2000 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "acinterp.h"
  13#include "acparser.h"
  14#include "amlcode.h"
  15
  16#define _COMPONENT          ACPI_EXECUTER
  17ACPI_MODULE_NAME("exoparg3")
  18
  19/*!
  20 * Naming convention for AML interpreter execution routines.
  21 *
  22 * The routines that begin execution of AML opcodes are named with a common
  23 * convention based upon the number of arguments, the number of target operands,
  24 * and whether or not a value is returned:
  25 *
  26 *      AcpiExOpcode_xA_yT_zR
  27 *
  28 * Where:
  29 *
  30 * xA - ARGUMENTS:    The number of arguments (input operands) that are
  31 *                    required for this opcode type (1 through 6 args).
  32 * yT - TARGETS:      The number of targets (output operands) that are required
  33 *                    for this opcode type (0, 1, or 2 targets).
  34 * zR - RETURN VALUE: Indicates whether this opcode type returns a value
  35 *                    as the function return (0 or 1).
  36 *
  37 * The AcpiExOpcode* functions are called via the Dispatcher component with
  38 * fully resolved operands.
  39!*/
  40/*******************************************************************************
  41 *
  42 * FUNCTION:    acpi_ex_opcode_3A_0T_0R
  43 *
  44 * PARAMETERS:  walk_state          - Current walk state
  45 *
  46 * RETURN:      Status
  47 *
  48 * DESCRIPTION: Execute Triadic operator (3 operands)
  49 *
  50 ******************************************************************************/
  51acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state)
  52{
  53        union acpi_operand_object **operand = &walk_state->operands[0];
  54        struct acpi_signal_fatal_info *fatal;
  55        acpi_status status = AE_OK;
  56
  57        ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_0T_0R,
  58                                acpi_ps_get_opcode_name(walk_state->opcode));
  59
  60        switch (walk_state->opcode) {
  61        case AML_FATAL_OP:      /* Fatal (fatal_type fatal_code fatal_arg) */
  62
  63                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
  64                                  "FatalOp: Type %X Code %X Arg %X "
  65                                  "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
  66                                  (u32)operand[0]->integer.value,
  67                                  (u32)operand[1]->integer.value,
  68                                  (u32)operand[2]->integer.value));
  69
  70                fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info));
  71                if (fatal) {
  72                        fatal->type = (u32) operand[0]->integer.value;
  73                        fatal->code = (u32) operand[1]->integer.value;
  74                        fatal->argument = (u32) operand[2]->integer.value;
  75                }
  76
  77                /* Always signal the OS! */
  78
  79                status = acpi_os_signal(ACPI_SIGNAL_FATAL, fatal);
  80
  81                /* Might return while OS is shutting down, just continue */
  82
  83                ACPI_FREE(fatal);
  84                goto cleanup;
  85
  86        case AML_EXTERNAL_OP:
  87                /*
  88                 * If the interpreter sees this opcode, just ignore it. The External
  89                 * op is intended for use by disassemblers in order to properly
  90                 * disassemble control method invocations. The opcode or group of
  91                 * opcodes should be surrounded by an "if (0)" clause to ensure that
  92                 * AML interpreters never see the opcode. Thus, something is
  93                 * wrong if an external opcode ever gets here.
  94                 */
  95                ACPI_ERROR((AE_INFO, "Executed External Op"));
  96                status = AE_OK;
  97                goto cleanup;
  98
  99        default:
 100
 101                ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X",
 102                            walk_state->opcode));
 103
 104                status = AE_AML_BAD_OPCODE;
 105                goto cleanup;
 106        }
 107
 108cleanup:
 109
 110        return_ACPI_STATUS(status);
 111}
 112
 113/*******************************************************************************
 114 *
 115 * FUNCTION:    acpi_ex_opcode_3A_1T_1R
 116 *
 117 * PARAMETERS:  walk_state          - Current walk state
 118 *
 119 * RETURN:      Status
 120 *
 121 * DESCRIPTION: Execute Triadic operator (3 operands)
 122 *
 123 ******************************************************************************/
 124
 125acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state)
 126{
 127        union acpi_operand_object **operand = &walk_state->operands[0];
 128        union acpi_operand_object *return_desc = NULL;
 129        char *buffer = NULL;
 130        acpi_status status = AE_OK;
 131        u64 index;
 132        acpi_size length;
 133
 134        ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R,
 135                                acpi_ps_get_opcode_name(walk_state->opcode));
 136
 137        switch (walk_state->opcode) {
 138        case AML_MID_OP:        /* Mid (Source[0], Index[1], Length[2], Result[3]) */
 139                /*
 140                 * Create the return object. The Source operand is guaranteed to be
 141                 * either a String or a Buffer, so just use its type.
 142                 */
 143                return_desc = acpi_ut_create_internal_object((operand[0])->
 144                                                             common.type);
 145                if (!return_desc) {
 146                        status = AE_NO_MEMORY;
 147                        goto cleanup;
 148                }
 149
 150                /* Get the Integer values from the objects */
 151
 152                index = operand[1]->integer.value;
 153                length = (acpi_size)operand[2]->integer.value;
 154
 155                /*
 156                 * If the index is beyond the length of the String/Buffer, or if the
 157                 * requested length is zero, return a zero-length String/Buffer
 158                 */
 159                if (index >= operand[0]->string.length) {
 160                        length = 0;
 161                }
 162
 163                /* Truncate request if larger than the actual String/Buffer */
 164
 165                else if ((index + length) > operand[0]->string.length) {
 166                        length =
 167                            (acpi_size)operand[0]->string.length -
 168                            (acpi_size)index;
 169                }
 170
 171                /* Strings always have a sub-pointer, not so for buffers */
 172
 173                switch ((operand[0])->common.type) {
 174                case ACPI_TYPE_STRING:
 175
 176                        /* Always allocate a new buffer for the String */
 177
 178                        buffer = ACPI_ALLOCATE_ZEROED((acpi_size)length + 1);
 179                        if (!buffer) {
 180                                status = AE_NO_MEMORY;
 181                                goto cleanup;
 182                        }
 183                        break;
 184
 185                case ACPI_TYPE_BUFFER:
 186
 187                        /* If the requested length is zero, don't allocate a buffer */
 188
 189                        if (length > 0) {
 190
 191                                /* Allocate a new buffer for the Buffer */
 192
 193                                buffer = ACPI_ALLOCATE_ZEROED(length);
 194                                if (!buffer) {
 195                                        status = AE_NO_MEMORY;
 196                                        goto cleanup;
 197                                }
 198                        }
 199                        break;
 200
 201                default:        /* Should not happen */
 202
 203                        status = AE_AML_OPERAND_TYPE;
 204                        goto cleanup;
 205                }
 206
 207                if (buffer) {
 208
 209                        /* We have a buffer, copy the portion requested */
 210
 211                        memcpy(buffer,
 212                               operand[0]->string.pointer + index, length);
 213                }
 214
 215                /* Set the length of the new String/Buffer */
 216
 217                return_desc->string.pointer = buffer;
 218                return_desc->string.length = (u32) length;
 219
 220                /* Mark buffer initialized */
 221
 222                return_desc->buffer.flags |= AOPOBJ_DATA_VALID;
 223                break;
 224
 225        default:
 226
 227                ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X",
 228                            walk_state->opcode));
 229
 230                status = AE_AML_BAD_OPCODE;
 231                goto cleanup;
 232        }
 233
 234        /* Store the result in the target */
 235
 236        status = acpi_ex_store(return_desc, operand[3], walk_state);
 237
 238cleanup:
 239
 240        /* Delete return object on error */
 241
 242        if (ACPI_FAILURE(status) || walk_state->result_obj) {
 243                acpi_ut_remove_reference(return_desc);
 244                walk_state->result_obj = NULL;
 245        } else {
 246                /* Set the return object and exit */
 247
 248                walk_state->result_obj = return_desc;
 249        }
 250
 251        return_ACPI_STATUS(status);
 252}
 253