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