1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /****************************************************************************** 3 * 4 * Module Name: exoparg2 - AML execution - opcodes with 2 arguments 5 * 6 * Copyright (C) 2000 - 2023, Intel Corp. 7 * 8 *****************************************************************************/ 9 10 #include <acpi/acpi.h> 11 #include "accommon.h" 12 #include "acparser.h" 13 #include "acinterp.h" 14 #include "acevents.h" 15 #include "amlcode.h" 16 17 #define _COMPONENT ACPI_EXECUTER 18 ACPI_MODULE_NAME("exoparg2") 19 20 /*! 21 * Naming convention for AML interpreter execution routines. 22 * 23 * The routines that begin execution of AML opcodes are named with a common 24 * convention based upon the number of arguments, the number of target operands, 25 * and whether or not a value is returned: 26 * 27 * AcpiExOpcode_xA_yT_zR 28 * 29 * Where: 30 * 31 * xA - ARGUMENTS: The number of arguments (input operands) that are 32 * required for this opcode type (1 through 6 args). 33 * yT - TARGETS: The number of targets (output operands) that are required 34 * for this opcode type (0, 1, or 2 targets). 35 * zR - RETURN VALUE: Indicates whether this opcode type returns a value 36 * as the function return (0 or 1). 37 * 38 * The AcpiExOpcode* functions are called via the Dispatcher component with 39 * fully resolved operands. 40 !*/ 41 /******************************************************************************* 42 * 43 * FUNCTION: acpi_ex_opcode_2A_0T_0R 44 * 45 * PARAMETERS: walk_state - Current walk state 46 * 47 * RETURN: Status 48 * 49 * DESCRIPTION: Execute opcode with two arguments, no target, and no return 50 * value. 51 * 52 * ALLOCATION: Deletes both operands 53 * 54 ******************************************************************************/ 55 acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state) 56 { 57 union acpi_operand_object **operand = &walk_state->operands[0]; 58 struct acpi_namespace_node *node; 59 u32 value; 60 acpi_status status = AE_OK; 61 62 ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_0R, 63 acpi_ps_get_opcode_name(walk_state->opcode)); 64 65 /* Examine the opcode */ 66 67 switch (walk_state->opcode) { 68 case AML_NOTIFY_OP: /* Notify (notify_object, notify_value) */ 69 70 /* The first operand is a namespace node */ 71 72 node = (struct acpi_namespace_node *)operand[0]; 73 74 /* Second value is the notify value */ 75 76 value = (u32) operand[1]->integer.value; 77 78 /* Are notifies allowed on this object? */ 79 80 if (!acpi_ev_is_notify_object(node)) { 81 ACPI_ERROR((AE_INFO, 82 "Unexpected notify object type [%s]", 83 acpi_ut_get_type_name(node->type))); 84 85 status = AE_AML_OPERAND_TYPE; 86 break; 87 } 88 89 /* 90 * Dispatch the notify to the appropriate handler 91 * NOTE: the request is queued for execution after this method 92 * completes. The notify handlers are NOT invoked synchronously 93 * from this thread -- because handlers may in turn run other 94 * control methods. 95 */ 96 status = acpi_ev_queue_notify_request(node, value); 97 break; 98 99 default: 100 101 ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 102 walk_state->opcode)); 103 status = AE_AML_BAD_OPCODE; 104 } 105 106 return_ACPI_STATUS(status); 107 } 108 109 /******************************************************************************* 110 * 111 * FUNCTION: acpi_ex_opcode_2A_2T_1R 112 * 113 * PARAMETERS: walk_state - Current walk state 114 * 115 * RETURN: Status 116 * 117 * DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets 118 * and one implicit return value. 119 * 120 ******************************************************************************/ 121 122 acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state) 123 { 124 union acpi_operand_object **operand = &walk_state->operands[0]; 125 union acpi_operand_object *return_desc1 = NULL; 126 union acpi_operand_object *return_desc2 = NULL; 127 acpi_status status; 128 129 ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_2T_1R, 130 acpi_ps_get_opcode_name(walk_state->opcode)); 131 132 /* Execute the opcode */ 133 134 switch (walk_state->opcode) { 135 case AML_DIVIDE_OP: 136 137 /* Divide (Dividend, Divisor, remainder_result quotient_result) */ 138 139 return_desc1 = 140 acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 141 if (!return_desc1) { 142 status = AE_NO_MEMORY; 143 goto cleanup; 144 } 145 146 return_desc2 = 147 acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 148 if (!return_desc2) { 149 status = AE_NO_MEMORY; 150 goto cleanup; 151 } 152 153 /* Quotient to return_desc1, remainder to return_desc2 */ 154 155 status = acpi_ut_divide(operand[0]->integer.value, 156 operand[1]->integer.value, 157 &return_desc1->integer.value, 158 &return_desc2->integer.value); 159 if (ACPI_FAILURE(status)) { 160 goto cleanup; 161 } 162 break; 163 164 default: 165 166 ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 167 walk_state->opcode)); 168 169 status = AE_AML_BAD_OPCODE; 170 goto cleanup; 171 } 172 173 /* Store the results to the target reference operands */ 174 175 status = acpi_ex_store(return_desc2, operand[2], walk_state); 176 if (ACPI_FAILURE(status)) { 177 goto cleanup; 178 } 179 180 status = acpi_ex_store(return_desc1, operand[3], walk_state); 181 if (ACPI_FAILURE(status)) { 182 goto cleanup; 183 } 184 185 cleanup: 186 /* 187 * Since the remainder is not returned indirectly, remove a reference to 188 * it. Only the quotient is returned indirectly. 189 */ 190 acpi_ut_remove_reference(return_desc2); 191 192 if (ACPI_FAILURE(status)) { 193 194 /* Delete the return object */ 195 196 acpi_ut_remove_reference(return_desc1); 197 } 198 199 /* Save return object (the remainder) on success */ 200 201 else { 202 walk_state->result_obj = return_desc1; 203 } 204 205 return_ACPI_STATUS(status); 206 } 207 208 /******************************************************************************* 209 * 210 * FUNCTION: acpi_ex_opcode_2A_1T_1R 211 * 212 * PARAMETERS: walk_state - Current walk state 213 * 214 * RETURN: Status 215 * 216 * DESCRIPTION: Execute opcode with two arguments, one target, and a return 217 * value. 218 * 219 ******************************************************************************/ 220 221 acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state) 222 { 223 union acpi_operand_object **operand = &walk_state->operands[0]; 224 union acpi_operand_object *return_desc = NULL; 225 u64 index; 226 acpi_status status = AE_OK; 227 acpi_size length = 0; 228 229 ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_1T_1R, 230 acpi_ps_get_opcode_name(walk_state->opcode)); 231 232 /* Execute the opcode */ 233 234 if (walk_state->op_info->flags & AML_MATH) { 235 236 /* All simple math opcodes (add, etc.) */ 237 238 return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 239 if (!return_desc) { 240 status = AE_NO_MEMORY; 241 goto cleanup; 242 } 243 244 return_desc->integer.value = 245 acpi_ex_do_math_op(walk_state->opcode, 246 operand[0]->integer.value, 247 operand[1]->integer.value); 248 goto store_result_to_target; 249 } 250 251 switch (walk_state->opcode) { 252 case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */ 253 254 return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 255 if (!return_desc) { 256 status = AE_NO_MEMORY; 257 goto cleanup; 258 } 259 260 /* return_desc will contain the remainder */ 261 262 status = acpi_ut_divide(operand[0]->integer.value, 263 operand[1]->integer.value, 264 NULL, &return_desc->integer.value); 265 break; 266 267 case AML_CONCATENATE_OP: /* Concatenate (Data1, Data2, Result) */ 268 269 status = 270 acpi_ex_do_concatenate(operand[0], operand[1], &return_desc, 271 walk_state); 272 break; 273 274 case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */ 275 /* 276 * Input object is guaranteed to be a buffer at this point (it may have 277 * been converted.) Copy the raw buffer data to a new object of 278 * type String. 279 */ 280 281 /* 282 * Get the length of the new string. It is the smallest of: 283 * 1) Length of the input buffer 284 * 2) Max length as specified in the to_string operator 285 * 3) Length of input buffer up to a zero byte (null terminator) 286 * 287 * NOTE: A length of zero is ok, and will create a zero-length, null 288 * terminated string. 289 */ 290 while ((length < operand[0]->buffer.length) && /* Length of input buffer */ 291 (length < operand[1]->integer.value) && /* Length operand */ 292 (operand[0]->buffer.pointer[length])) { /* Null terminator */ 293 length++; 294 } 295 296 /* Allocate a new string object */ 297 298 return_desc = acpi_ut_create_string_object(length); 299 if (!return_desc) { 300 status = AE_NO_MEMORY; 301 goto cleanup; 302 } 303 304 /* 305 * Copy the raw buffer data with no transform. 306 * (NULL terminated already) 307 */ 308 memcpy(return_desc->string.pointer, 309 operand[0]->buffer.pointer, length); 310 break; 311 312 case AML_CONCATENATE_TEMPLATE_OP: 313 314 /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */ 315 316 status = 317 acpi_ex_concat_template(operand[0], operand[1], 318 &return_desc, walk_state); 319 break; 320 321 case AML_INDEX_OP: /* Index (Source Index Result) */ 322 323 /* Create the internal return object */ 324 325 return_desc = 326 acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE); 327 if (!return_desc) { 328 status = AE_NO_MEMORY; 329 goto cleanup; 330 } 331 332 /* Initialize the Index reference object */ 333 334 index = operand[1]->integer.value; 335 return_desc->reference.value = (u32) index; 336 return_desc->reference.class = ACPI_REFCLASS_INDEX; 337 338 /* 339 * At this point, the Source operand is a String, Buffer, or Package. 340 * Verify that the index is within range. 341 */ 342 switch ((operand[0])->common.type) { 343 case ACPI_TYPE_STRING: 344 345 if (index >= operand[0]->string.length) { 346 length = operand[0]->string.length; 347 status = AE_AML_STRING_LIMIT; 348 } 349 350 return_desc->reference.target_type = 351 ACPI_TYPE_BUFFER_FIELD; 352 return_desc->reference.index_pointer = 353 &(operand[0]->buffer.pointer[index]); 354 break; 355 356 case ACPI_TYPE_BUFFER: 357 358 if (index >= operand[0]->buffer.length) { 359 length = operand[0]->buffer.length; 360 status = AE_AML_BUFFER_LIMIT; 361 } 362 363 return_desc->reference.target_type = 364 ACPI_TYPE_BUFFER_FIELD; 365 return_desc->reference.index_pointer = 366 &(operand[0]->buffer.pointer[index]); 367 break; 368 369 case ACPI_TYPE_PACKAGE: 370 371 if (index >= operand[0]->package.count) { 372 length = operand[0]->package.count; 373 status = AE_AML_PACKAGE_LIMIT; 374 } 375 376 return_desc->reference.target_type = ACPI_TYPE_PACKAGE; 377 return_desc->reference.where = 378 &operand[0]->package.elements[index]; 379 break; 380 381 default: 382 383 ACPI_ERROR((AE_INFO, 384 "Invalid object type: %X", 385 (operand[0])->common.type)); 386 status = AE_AML_INTERNAL; 387 goto cleanup; 388 } 389 390 /* Failure means that the Index was beyond the end of the object */ 391 392 if (ACPI_FAILURE(status)) { 393 ACPI_BIOS_EXCEPTION((AE_INFO, status, 394 "Index (0x%X%8.8X) is beyond end of object (length 0x%X)", 395 ACPI_FORMAT_UINT64(index), 396 (u32)length)); 397 goto cleanup; 398 } 399 400 /* 401 * Save the target object and add a reference to it for the life 402 * of the index 403 */ 404 return_desc->reference.object = operand[0]; 405 acpi_ut_add_reference(operand[0]); 406 407 /* Store the reference to the Target */ 408 409 status = acpi_ex_store(return_desc, operand[2], walk_state); 410 411 /* Return the reference */ 412 413 walk_state->result_obj = return_desc; 414 goto cleanup; 415 416 default: 417 418 ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 419 walk_state->opcode)); 420 status = AE_AML_BAD_OPCODE; 421 break; 422 } 423 424 store_result_to_target: 425 426 if (ACPI_SUCCESS(status)) { 427 /* 428 * Store the result of the operation (which is now in return_desc) into 429 * the Target descriptor. 430 */ 431 status = acpi_ex_store(return_desc, operand[2], walk_state); 432 if (ACPI_FAILURE(status)) { 433 goto cleanup; 434 } 435 436 if (!walk_state->result_obj) { 437 walk_state->result_obj = return_desc; 438 } 439 } 440 441 cleanup: 442 443 /* Delete return object on error */ 444 445 if (ACPI_FAILURE(status)) { 446 acpi_ut_remove_reference(return_desc); 447 walk_state->result_obj = NULL; 448 } 449 450 return_ACPI_STATUS(status); 451 } 452 453 /******************************************************************************* 454 * 455 * FUNCTION: acpi_ex_opcode_2A_0T_1R 456 * 457 * PARAMETERS: walk_state - Current walk state 458 * 459 * RETURN: Status 460 * 461 * DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value 462 * 463 ******************************************************************************/ 464 465 acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state) 466 { 467 union acpi_operand_object **operand = &walk_state->operands[0]; 468 union acpi_operand_object *return_desc = NULL; 469 acpi_status status = AE_OK; 470 u8 logical_result = FALSE; 471 472 ACPI_FUNCTION_TRACE_STR(ex_opcode_2A_0T_1R, 473 acpi_ps_get_opcode_name(walk_state->opcode)); 474 475 /* Create the internal return object */ 476 477 return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); 478 if (!return_desc) { 479 status = AE_NO_MEMORY; 480 goto cleanup; 481 } 482 483 /* Execute the Opcode */ 484 485 if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) { 486 487 /* logical_op (Operand0, Operand1) */ 488 489 status = acpi_ex_do_logical_numeric_op(walk_state->opcode, 490 operand[0]->integer. 491 value, 492 operand[1]->integer. 493 value, &logical_result); 494 goto store_logical_result; 495 } else if (walk_state->op_info->flags & AML_LOGICAL) { 496 497 /* logical_op (Operand0, Operand1) */ 498 499 status = acpi_ex_do_logical_op(walk_state->opcode, operand[0], 500 operand[1], &logical_result); 501 goto store_logical_result; 502 } 503 504 switch (walk_state->opcode) { 505 case AML_ACQUIRE_OP: /* Acquire (mutex_object, Timeout) */ 506 507 status = 508 acpi_ex_acquire_mutex(operand[1], operand[0], walk_state); 509 if (status == AE_TIME) { 510 logical_result = TRUE; /* TRUE = Acquire timed out */ 511 status = AE_OK; 512 } 513 break; 514 515 case AML_WAIT_OP: /* Wait (event_object, Timeout) */ 516 517 status = acpi_ex_system_wait_event(operand[1], operand[0]); 518 if (status == AE_TIME) { 519 logical_result = TRUE; /* TRUE, Wait timed out */ 520 status = AE_OK; 521 } 522 break; 523 524 default: 525 526 ACPI_ERROR((AE_INFO, "Unknown AML opcode 0x%X", 527 walk_state->opcode)); 528 529 status = AE_AML_BAD_OPCODE; 530 goto cleanup; 531 } 532 533 store_logical_result: 534 /* 535 * Set return value to according to logical_result. logical TRUE (all ones) 536 * Default is FALSE (zero) 537 */ 538 if (logical_result) { 539 return_desc->integer.value = ACPI_UINT64_MAX; 540 } 541 542 cleanup: 543 544 /* Delete return object on error */ 545 546 if (ACPI_FAILURE(status)) { 547 acpi_ut_remove_reference(return_desc); 548 } 549 550 /* Save return object on success */ 551 552 else { 553 walk_state->result_obj = return_desc; 554 } 555 556 return_ACPI_STATUS(status); 557 } 558