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