exmisc.c (11917B)
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 - 2022, 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}