Branch data Line data Source code
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 - 2020, 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 17 : : ACPI_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 : : ******************************************************************************/ 51 : 0 : acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state) 52 : : { 53 : 0 : union acpi_operand_object **operand = &walk_state->operands[0]; 54 : 0 : struct acpi_signal_fatal_info *fatal; 55 : 0 : acpi_status status = AE_OK; 56 : : 57 : : ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_0T_0R, 58 : 0 : acpi_ps_get_opcode_name(walk_state->opcode)); 59 : : 60 [ # # # ]: 0 : switch (walk_state->opcode) { 61 : 0 : 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 : 0 : (u32)operand[2]->integer.value)); 69 : : 70 : 0 : fatal = ACPI_ALLOCATE(sizeof(struct acpi_signal_fatal_info)); 71 [ # # ]: 0 : if (fatal) { 72 : 0 : fatal->type = (u32) operand[0]->integer.value; 73 : 0 : fatal->code = (u32) operand[1]->integer.value; 74 : 0 : fatal->argument = (u32) operand[2]->integer.value; 75 : : } 76 : : 77 : : /* Always signal the OS! */ 78 : : 79 : 0 : status = acpi_os_signal(ACPI_SIGNAL_FATAL, fatal); 80 : : 81 : : /* Might return while OS is shutting down, just continue */ 82 : : 83 : 0 : ACPI_FREE(fatal); 84 : 0 : goto cleanup; 85 : : 86 : 0 : 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 : 0 : ACPI_ERROR((AE_INFO, "Executed External Op")); 96 : 0 : status = AE_OK; 97 : 0 : goto cleanup; 98 : : 99 : 0 : default: 100 : : 101 : 0 : ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 102 : : walk_state->opcode)); 103 : : 104 : 0 : status = AE_AML_BAD_OPCODE; 105 : 0 : goto cleanup; 106 : : } 107 : : 108 : 0 : cleanup: 109 : : 110 : 0 : 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 : : 125 : 0 : acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) 126 : : { 127 : 0 : union acpi_operand_object **operand = &walk_state->operands[0]; 128 : 0 : union acpi_operand_object *return_desc = NULL; 129 : 0 : char *buffer = NULL; 130 : 0 : acpi_status status = AE_OK; 131 : 0 : u64 index; 132 : 0 : acpi_size length; 133 : : 134 : : ACPI_FUNCTION_TRACE_STR(ex_opcode_3A_1T_1R, 135 : 0 : acpi_ps_get_opcode_name(walk_state->opcode)); 136 : : 137 [ # # ]: 0 : switch (walk_state->opcode) { 138 : 0 : 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 : 0 : return_desc = acpi_ut_create_internal_object((operand[0])-> 144 : : common.type); 145 [ # # ]: 0 : if (!return_desc) { 146 : 0 : status = AE_NO_MEMORY; 147 : 0 : goto cleanup; 148 : : } 149 : : 150 : : /* Get the Integer values from the objects */ 151 : : 152 : 0 : index = operand[1]->integer.value; 153 : 0 : 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 [ # # ]: 0 : if (index >= operand[0]->string.length) { 160 : : length = 0; 161 : : } 162 : : 163 : : /* Truncate request if larger than the actual String/Buffer */ 164 : : 165 [ # # ]: 0 : else if ((index + length) > operand[0]->string.length) { 166 : 0 : 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 [ # # # ]: 0 : switch ((operand[0])->common.type) { 174 : 0 : case ACPI_TYPE_STRING: 175 : : 176 : : /* Always allocate a new buffer for the String */ 177 : : 178 : 0 : buffer = ACPI_ALLOCATE_ZEROED((acpi_size)length + 1); 179 [ # # ]: 0 : if (!buffer) { 180 : 0 : status = AE_NO_MEMORY; 181 : 0 : goto cleanup; 182 : : } 183 : : break; 184 : : 185 : 0 : case ACPI_TYPE_BUFFER: 186 : : 187 : : /* If the requested length is zero, don't allocate a buffer */ 188 : : 189 [ # # ]: 0 : if (length > 0) { 190 : : 191 : : /* Allocate a new buffer for the Buffer */ 192 : : 193 : 0 : buffer = ACPI_ALLOCATE_ZEROED(length); 194 [ # # ]: 0 : if (!buffer) { 195 : 0 : status = AE_NO_MEMORY; 196 : 0 : goto cleanup; 197 : : } 198 : : } 199 : : break; 200 : : 201 : 0 : default: /* Should not happen */ 202 : : 203 : 0 : status = AE_AML_OPERAND_TYPE; 204 : 0 : goto cleanup; 205 : : } 206 : : 207 [ # # ]: 0 : if (buffer) { 208 : : 209 : : /* We have a buffer, copy the portion requested */ 210 : : 211 : 0 : memcpy(buffer, 212 : 0 : operand[0]->string.pointer + index, length); 213 : : } 214 : : 215 : : /* Set the length of the new String/Buffer */ 216 : : 217 : 0 : return_desc->string.pointer = buffer; 218 : 0 : return_desc->string.length = (u32) length; 219 : : 220 : : /* Mark buffer initialized */ 221 : : 222 : 0 : return_desc->buffer.flags |= AOPOBJ_DATA_VALID; 223 : 0 : break; 224 : : 225 : 0 : default: 226 : : 227 : 0 : ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 228 : : walk_state->opcode)); 229 : : 230 : 0 : status = AE_AML_BAD_OPCODE; 231 : 0 : goto cleanup; 232 : : } 233 : : 234 : : /* Store the result in the target */ 235 : : 236 : 0 : status = acpi_ex_store(return_desc, operand[3], walk_state); 237 : : 238 : : cleanup: 239 : : 240 : : /* Delete return object on error */ 241 : : 242 [ # # # # ]: 0 : if (ACPI_FAILURE(status) || walk_state->result_obj) { 243 : 0 : acpi_ut_remove_reference(return_desc); 244 : 0 : walk_state->result_obj = NULL; 245 : : } else { 246 : : /* Set the return object and exit */ 247 : : 248 : 0 : walk_state->result_obj = return_desc; 249 : : } 250 : : 251 : 0 : return_ACPI_STATUS(status); 252 : : }