1 /****************************************************************************** 2 * 3 * Module Name: exoparg2 - AML execution - opcodes with 2 arguments 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2011, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 45 #define __EXOPARG2_C__ 46 47 #include "acpi.h" 48 #include "accommon.h" 49 #include "acparser.h" 50 #include "acinterp.h" 51 #include "acevents.h" 52 #include "amlcode.h" 53 54 55 #define _COMPONENT ACPI_EXECUTER 56 ACPI_MODULE_NAME ("exoparg2") 57 58 59 /*! 60 * Naming convention for AML interpreter execution routines. 61 * 62 * The routines that begin execution of AML opcodes are named with a common 63 * convention based upon the number of arguments, the number of target operands, 64 * and whether or not a value is returned: 65 * 66 * AcpiExOpcode_xA_yT_zR 67 * 68 * Where: 69 * 70 * xA - ARGUMENTS: The number of arguments (input operands) that are 71 * required for this opcode type (1 through 6 args). 72 * yT - TARGETS: The number of targets (output operands) that are required 73 * for this opcode type (0, 1, or 2 targets). 74 * zR - RETURN VALUE: Indicates whether this opcode type returns a value 75 * as the function return (0 or 1). 76 * 77 * The AcpiExOpcode* functions are called via the Dispatcher component with 78 * fully resolved operands. 79 !*/ 80 81 82 /******************************************************************************* 83 * 84 * FUNCTION: AcpiExOpcode_2A_0T_0R 85 * 86 * PARAMETERS: WalkState - Current walk state 87 * 88 * RETURN: Status 89 * 90 * DESCRIPTION: Execute opcode with two arguments, no target, and no return 91 * value. 92 * 93 * ALLOCATION: Deletes both operands 94 * 95 ******************************************************************************/ 96 97 ACPI_STATUS 98 AcpiExOpcode_2A_0T_0R ( 99 ACPI_WALK_STATE *WalkState) 100 { 101 ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; 102 ACPI_NAMESPACE_NODE *Node; 103 UINT32 Value; 104 ACPI_STATUS Status = AE_OK; 105 106 107 ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_0T_0R, 108 AcpiPsGetOpcodeName (WalkState->Opcode)); 109 110 111 /* Examine the opcode */ 112 113 switch (WalkState->Opcode) 114 { 115 case AML_NOTIFY_OP: /* Notify (NotifyObject, NotifyValue) */ 116 117 /* The first operand is a namespace node */ 118 119 Node = (ACPI_NAMESPACE_NODE *) Operand[0]; 120 121 /* Second value is the notify value */ 122 123 Value = (UINT32) Operand[1]->Integer.Value; 124 125 /* Are notifies allowed on this object? */ 126 127 if (!AcpiEvIsNotifyObject (Node)) 128 { 129 ACPI_ERROR ((AE_INFO, 130 "Unexpected notify object type [%s]", 131 AcpiUtGetTypeName (Node->Type))); 132 133 Status = AE_AML_OPERAND_TYPE; 134 break; 135 } 136 137 /* 138 * Dispatch the notify to the appropriate handler 139 * NOTE: the request is queued for execution after this method 140 * completes. The notify handlers are NOT invoked synchronously 141 * from this thread -- because handlers may in turn run other 142 * control methods. 143 */ 144 Status = AcpiEvQueueNotifyRequest (Node, Value); 145 break; 146 147 148 default: 149 150 ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", 151 WalkState->Opcode)); 152 Status = AE_AML_BAD_OPCODE; 153 } 154 155 return_ACPI_STATUS (Status); 156 } 157 158 159 /******************************************************************************* 160 * 161 * FUNCTION: AcpiExOpcode_2A_2T_1R 162 * 163 * PARAMETERS: WalkState - Current walk state 164 * 165 * RETURN: Status 166 * 167 * DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets 168 * and one implicit return value. 169 * 170 ******************************************************************************/ 171 172 ACPI_STATUS 173 AcpiExOpcode_2A_2T_1R ( 174 ACPI_WALK_STATE *WalkState) 175 { 176 ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; 177 ACPI_OPERAND_OBJECT *ReturnDesc1 = NULL; 178 ACPI_OPERAND_OBJECT *ReturnDesc2 = NULL; 179 ACPI_STATUS Status; 180 181 182 ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_2T_1R, 183 AcpiPsGetOpcodeName (WalkState->Opcode)); 184 185 186 /* Execute the opcode */ 187 188 switch (WalkState->Opcode) 189 { 190 case AML_DIVIDE_OP: 191 192 /* Divide (Dividend, Divisor, RemainderResult QuotientResult) */ 193 194 ReturnDesc1 = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); 195 if (!ReturnDesc1) 196 { 197 Status = AE_NO_MEMORY; 198 goto Cleanup; 199 } 200 201 ReturnDesc2 = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); 202 if (!ReturnDesc2) 203 { 204 Status = AE_NO_MEMORY; 205 goto Cleanup; 206 } 207 208 /* Quotient to ReturnDesc1, remainder to ReturnDesc2 */ 209 210 Status = AcpiUtDivide (Operand[0]->Integer.Value, 211 Operand[1]->Integer.Value, 212 &ReturnDesc1->Integer.Value, 213 &ReturnDesc2->Integer.Value); 214 if (ACPI_FAILURE (Status)) 215 { 216 goto Cleanup; 217 } 218 break; 219 220 221 default: 222 223 ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", 224 WalkState->Opcode)); 225 Status = AE_AML_BAD_OPCODE; 226 goto Cleanup; 227 } 228 229 /* Store the results to the target reference operands */ 230 231 Status = AcpiExStore (ReturnDesc2, Operand[2], WalkState); 232 if (ACPI_FAILURE (Status)) 233 { 234 goto Cleanup; 235 } 236 237 Status = AcpiExStore (ReturnDesc1, Operand[3], WalkState); 238 if (ACPI_FAILURE (Status)) 239 { 240 goto Cleanup; 241 } 242 243 Cleanup: 244 /* 245 * Since the remainder is not returned indirectly, remove a reference to 246 * it. Only the quotient is returned indirectly. 247 */ 248 AcpiUtRemoveReference (ReturnDesc2); 249 250 if (ACPI_FAILURE (Status)) 251 { 252 /* Delete the return object */ 253 254 AcpiUtRemoveReference (ReturnDesc1); 255 } 256 257 /* Save return object (the remainder) on success */ 258 259 else 260 { 261 WalkState->ResultObj = ReturnDesc1; 262 } 263 264 return_ACPI_STATUS (Status); 265 } 266 267 268 /******************************************************************************* 269 * 270 * FUNCTION: AcpiExOpcode_2A_1T_1R 271 * 272 * PARAMETERS: WalkState - Current walk state 273 * 274 * RETURN: Status 275 * 276 * DESCRIPTION: Execute opcode with two arguments, one target, and a return 277 * value. 278 * 279 ******************************************************************************/ 280 281 ACPI_STATUS 282 AcpiExOpcode_2A_1T_1R ( 283 ACPI_WALK_STATE *WalkState) 284 { 285 ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; 286 ACPI_OPERAND_OBJECT *ReturnDesc = NULL; 287 UINT64 Index; 288 ACPI_STATUS Status = AE_OK; 289 ACPI_SIZE Length; 290 291 292 ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_1T_1R, 293 AcpiPsGetOpcodeName (WalkState->Opcode)); 294 295 296 /* Execute the opcode */ 297 298 if (WalkState->OpInfo->Flags & AML_MATH) 299 { 300 /* All simple math opcodes (add, etc.) */ 301 302 ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); 303 if (!ReturnDesc) 304 { 305 Status = AE_NO_MEMORY; 306 goto Cleanup; 307 } 308 309 ReturnDesc->Integer.Value = AcpiExDoMathOp (WalkState->Opcode, 310 Operand[0]->Integer.Value, 311 Operand[1]->Integer.Value); 312 goto StoreResultToTarget; 313 } 314 315 switch (WalkState->Opcode) 316 { 317 case AML_MOD_OP: /* Mod (Dividend, Divisor, RemainderResult (ACPI 2.0) */ 318 319 ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); 320 if (!ReturnDesc) 321 { 322 Status = AE_NO_MEMORY; 323 goto Cleanup; 324 } 325 326 /* ReturnDesc will contain the remainder */ 327 328 Status = AcpiUtDivide (Operand[0]->Integer.Value, 329 Operand[1]->Integer.Value, 330 NULL, 331 &ReturnDesc->Integer.Value); 332 break; 333 334 335 case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */ 336 337 Status = AcpiExDoConcatenate (Operand[0], Operand[1], 338 &ReturnDesc, WalkState); 339 break; 340 341 342 case AML_TO_STRING_OP: /* ToString (Buffer, Length, Result) (ACPI 2.0) */ 343 344 /* 345 * Input object is guaranteed to be a buffer at this point (it may have 346 * been converted.) Copy the raw buffer data to a new object of 347 * type String. 348 */ 349 350 /* 351 * Get the length of the new string. It is the smallest of: 352 * 1) Length of the input buffer 353 * 2) Max length as specified in the ToString operator 354 * 3) Length of input buffer up to a zero byte (null terminator) 355 * 356 * NOTE: A length of zero is ok, and will create a zero-length, null 357 * terminated string. 358 */ 359 Length = 0; 360 while ((Length < Operand[0]->Buffer.Length) && 361 (Length < Operand[1]->Integer.Value) && 362 (Operand[0]->Buffer.Pointer[Length])) 363 { 364 Length++; 365 } 366 367 /* Allocate a new string object */ 368 369 ReturnDesc = AcpiUtCreateStringObject (Length); 370 if (!ReturnDesc) 371 { 372 Status = AE_NO_MEMORY; 373 goto Cleanup; 374 } 375 376 /* 377 * Copy the raw buffer data with no transform. 378 * (NULL terminated already) 379 */ 380 ACPI_MEMCPY (ReturnDesc->String.Pointer, 381 Operand[0]->Buffer.Pointer, Length); 382 break; 383 384 385 case AML_CONCAT_RES_OP: 386 387 /* ConcatenateResTemplate (Buffer, Buffer, Result) (ACPI 2.0) */ 388 389 Status = AcpiExConcatTemplate (Operand[0], Operand[1], 390 &ReturnDesc, WalkState); 391 break; 392 393 394 case AML_INDEX_OP: /* Index (Source Index Result) */ 395 396 /* Create the internal return object */ 397 398 ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); 399 if (!ReturnDesc) 400 { 401 Status = AE_NO_MEMORY; 402 goto Cleanup; 403 } 404 405 /* Initialize the Index reference object */ 406 407 Index = Operand[1]->Integer.Value; 408 ReturnDesc->Reference.Value = (UINT32) Index; 409 ReturnDesc->Reference.Class = ACPI_REFCLASS_INDEX; 410 411 /* 412 * At this point, the Source operand is a String, Buffer, or Package. 413 * Verify that the index is within range. 414 */ 415 switch ((Operand[0])->Common.Type) 416 { 417 case ACPI_TYPE_STRING: 418 419 if (Index >= Operand[0]->String.Length) 420 { 421 Status = AE_AML_STRING_LIMIT; 422 } 423 424 ReturnDesc->Reference.TargetType = ACPI_TYPE_BUFFER_FIELD; 425 break; 426 427 case ACPI_TYPE_BUFFER: 428 429 if (Index >= Operand[0]->Buffer.Length) 430 { 431 Status = AE_AML_BUFFER_LIMIT; 432 } 433 434 ReturnDesc->Reference.TargetType = ACPI_TYPE_BUFFER_FIELD; 435 break; 436 437 case ACPI_TYPE_PACKAGE: 438 439 if (Index >= Operand[0]->Package.Count) 440 { 441 Status = AE_AML_PACKAGE_LIMIT; 442 } 443 444 ReturnDesc->Reference.TargetType = ACPI_TYPE_PACKAGE; 445 ReturnDesc->Reference.Where = &Operand[0]->Package.Elements [Index]; 446 break; 447 448 default: 449 450 Status = AE_AML_INTERNAL; 451 goto Cleanup; 452 } 453 454 /* Failure means that the Index was beyond the end of the object */ 455 456 if (ACPI_FAILURE (Status)) 457 { 458 ACPI_EXCEPTION ((AE_INFO, Status, 459 "Index (0x%8.8X%8.8X) is beyond end of object", 460 ACPI_FORMAT_UINT64 (Index))); 461 goto Cleanup; 462 } 463 464 /* 465 * Save the target object and add a reference to it for the life 466 * of the index 467 */ 468 ReturnDesc->Reference.Object = Operand[0]; 469 AcpiUtAddReference (Operand[0]); 470 471 /* Store the reference to the Target */ 472 473 Status = AcpiExStore (ReturnDesc, Operand[2], WalkState); 474 475 /* Return the reference */ 476 477 WalkState->ResultObj = ReturnDesc; 478 goto Cleanup; 479 480 481 default: 482 483 ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", 484 WalkState->Opcode)); 485 Status = AE_AML_BAD_OPCODE; 486 break; 487 } 488 489 490 StoreResultToTarget: 491 492 if (ACPI_SUCCESS (Status)) 493 { 494 /* 495 * Store the result of the operation (which is now in ReturnDesc) into 496 * the Target descriptor. 497 */ 498 Status = AcpiExStore (ReturnDesc, Operand[2], WalkState); 499 if (ACPI_FAILURE (Status)) 500 { 501 goto Cleanup; 502 } 503 504 if (!WalkState->ResultObj) 505 { 506 WalkState->ResultObj = ReturnDesc; 507 } 508 } 509 510 511 Cleanup: 512 513 /* Delete return object on error */ 514 515 if (ACPI_FAILURE (Status)) 516 { 517 AcpiUtRemoveReference (ReturnDesc); 518 WalkState->ResultObj = NULL; 519 } 520 521 return_ACPI_STATUS (Status); 522 } 523 524 525 /******************************************************************************* 526 * 527 * FUNCTION: AcpiExOpcode_2A_0T_1R 528 * 529 * PARAMETERS: WalkState - Current walk state 530 * 531 * RETURN: Status 532 * 533 * DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value 534 * 535 ******************************************************************************/ 536 537 ACPI_STATUS 538 AcpiExOpcode_2A_0T_1R ( 539 ACPI_WALK_STATE *WalkState) 540 { 541 ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; 542 ACPI_OPERAND_OBJECT *ReturnDesc = NULL; 543 ACPI_STATUS Status = AE_OK; 544 BOOLEAN LogicalResult = FALSE; 545 546 547 ACPI_FUNCTION_TRACE_STR (ExOpcode_2A_0T_1R, 548 AcpiPsGetOpcodeName (WalkState->Opcode)); 549 550 551 /* Create the internal return object */ 552 553 ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); 554 if (!ReturnDesc) 555 { 556 Status = AE_NO_MEMORY; 557 goto Cleanup; 558 } 559 560 /* Execute the Opcode */ 561 562 if (WalkState->OpInfo->Flags & AML_LOGICAL_NUMERIC) 563 { 564 /* LogicalOp (Operand0, Operand1) */ 565 566 Status = AcpiExDoLogicalNumericOp (WalkState->Opcode, 567 Operand[0]->Integer.Value, Operand[1]->Integer.Value, 568 &LogicalResult); 569 goto StoreLogicalResult; 570 } 571 else if (WalkState->OpInfo->Flags & AML_LOGICAL) 572 { 573 /* LogicalOp (Operand0, Operand1) */ 574 575 Status = AcpiExDoLogicalOp (WalkState->Opcode, Operand[0], 576 Operand[1], &LogicalResult); 577 goto StoreLogicalResult; 578 } 579 580 switch (WalkState->Opcode) 581 { 582 case AML_ACQUIRE_OP: /* Acquire (MutexObject, Timeout) */ 583 584 Status = AcpiExAcquireMutex (Operand[1], Operand[0], WalkState); 585 if (Status == AE_TIME) 586 { 587 LogicalResult = TRUE; /* TRUE = Acquire timed out */ 588 Status = AE_OK; 589 } 590 break; 591 592 593 case AML_WAIT_OP: /* Wait (EventObject, Timeout) */ 594 595 Status = AcpiExSystemWaitEvent (Operand[1], Operand[0]); 596 if (Status == AE_TIME) 597 { 598 LogicalResult = TRUE; /* TRUE, Wait timed out */ 599 Status = AE_OK; 600 } 601 break; 602 603 604 default: 605 606 ACPI_ERROR ((AE_INFO, "Unknown AML opcode 0x%X", 607 WalkState->Opcode)); 608 Status = AE_AML_BAD_OPCODE; 609 goto Cleanup; 610 } 611 612 613 StoreLogicalResult: 614 /* 615 * Set return value to according to LogicalResult. logical TRUE (all ones) 616 * Default is FALSE (zero) 617 */ 618 if (LogicalResult) 619 { 620 ReturnDesc->Integer.Value = ACPI_UINT64_MAX; 621 } 622 623 Cleanup: 624 625 /* Delete return object on error */ 626 627 if (ACPI_FAILURE (Status)) 628 { 629 AcpiUtRemoveReference (ReturnDesc); 630 } 631 632 /* Save return object on success */ 633 634 else 635 { 636 WalkState->ResultObj = ReturnDesc; 637 } 638 639 return_ACPI_STATUS (Status); 640 } 641 642