1 /******************************************************************************* 2 * 3 * Module Name: dbexec - debugger control method execution 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2022, 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 MERCHANTABILITY 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 "acpi.h" 45 #include "accommon.h" 46 #include "acdebug.h" 47 #include "acnamesp.h" 48 49 50 #define _COMPONENT ACPI_CA_DEBUGGER 51 ACPI_MODULE_NAME ("dbexec") 52 53 54 static ACPI_DB_METHOD_INFO AcpiGbl_DbMethodInfo; 55 56 /* Local prototypes */ 57 58 static ACPI_STATUS 59 AcpiDbExecuteMethod ( 60 ACPI_DB_METHOD_INFO *Info, 61 ACPI_BUFFER *ReturnObj); 62 63 static ACPI_STATUS 64 AcpiDbExecuteSetup ( 65 ACPI_DB_METHOD_INFO *Info); 66 67 static UINT32 68 AcpiDbGetOutstandingAllocations ( 69 void); 70 71 static void ACPI_SYSTEM_XFACE 72 AcpiDbMethodThread ( 73 void *Context); 74 75 static ACPI_STATUS 76 AcpiDbExecutionWalk ( 77 ACPI_HANDLE ObjHandle, 78 UINT32 NestingLevel, 79 void *Context, 80 void **ReturnValue); 81 82 static void ACPI_SYSTEM_XFACE 83 AcpiDbSingleExecutionThread ( 84 void *Context); 85 86 87 /******************************************************************************* 88 * 89 * FUNCTION: AcpiDbDeleteObjects 90 * 91 * PARAMETERS: Count - Count of objects in the list 92 * Objects - Array of ACPI_OBJECTs to be deleted 93 * 94 * RETURN: None 95 * 96 * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested 97 * packages via recursion. 98 * 99 ******************************************************************************/ 100 101 void 102 AcpiDbDeleteObjects ( 103 UINT32 Count, 104 ACPI_OBJECT *Objects) 105 { 106 UINT32 i; 107 108 109 for (i = 0; i < Count; i++) 110 { 111 switch (Objects[i].Type) 112 { 113 case ACPI_TYPE_BUFFER: 114 115 ACPI_FREE (Objects[i].Buffer.Pointer); 116 break; 117 118 case ACPI_TYPE_PACKAGE: 119 120 /* Recursive call to delete package elements */ 121 122 AcpiDbDeleteObjects (Objects[i].Package.Count, 123 Objects[i].Package.Elements); 124 125 /* Free the elements array */ 126 127 ACPI_FREE (Objects[i].Package.Elements); 128 break; 129 130 default: 131 132 break; 133 } 134 } 135 } 136 137 138 /******************************************************************************* 139 * 140 * FUNCTION: AcpiDbExecuteMethod 141 * 142 * PARAMETERS: Info - Valid info segment 143 * ReturnObj - Where to put return object 144 * 145 * RETURN: Status 146 * 147 * DESCRIPTION: Execute a control method. Used to evaluate objects via the 148 * "EXECUTE" or "EVALUATE" commands. 149 * 150 ******************************************************************************/ 151 152 static ACPI_STATUS 153 AcpiDbExecuteMethod ( 154 ACPI_DB_METHOD_INFO *Info, 155 ACPI_BUFFER *ReturnObj) 156 { 157 ACPI_STATUS Status; 158 ACPI_OBJECT_LIST ParamObjects; 159 ACPI_OBJECT Params[ACPI_DEBUGGER_MAX_ARGS + 1]; 160 UINT32 i; 161 162 163 ACPI_FUNCTION_TRACE (DbExecuteMethod); 164 165 166 if (AcpiGbl_DbOutputToFile && !AcpiDbgLevel) 167 { 168 AcpiOsPrintf ("Warning: debug output is not enabled!\n"); 169 } 170 171 ParamObjects.Count = 0; 172 ParamObjects.Pointer = NULL; 173 174 /* Pass through any command-line arguments */ 175 176 if (Info->Args && Info->Args[0]) 177 { 178 /* Get arguments passed on the command line */ 179 180 for (i = 0; (Info->Args[i] && *(Info->Args[i])); i++) 181 { 182 /* Convert input string (token) to an actual ACPI_OBJECT */ 183 184 Status = AcpiDbConvertToObject (Info->Types[i], 185 Info->Args[i], &Params[i]); 186 if (ACPI_FAILURE (Status)) 187 { 188 ACPI_EXCEPTION ((AE_INFO, Status, 189 "While parsing method arguments")); 190 goto Cleanup; 191 } 192 } 193 194 ParamObjects.Count = i; 195 ParamObjects.Pointer = Params; 196 } 197 198 /* Prepare for a return object of arbitrary size */ 199 200 ReturnObj->Pointer = AcpiGbl_DbBuffer; 201 ReturnObj->Length = ACPI_DEBUG_BUFFER_SIZE; 202 203 /* Do the actual method execution */ 204 205 AcpiGbl_MethodExecuting = TRUE; 206 Status = AcpiEvaluateObject (NULL, Info->Pathname, 207 &ParamObjects, ReturnObj); 208 209 AcpiGbl_CmSingleStep = FALSE; 210 AcpiGbl_MethodExecuting = FALSE; 211 212 if (ACPI_FAILURE (Status)) 213 { 214 if ((Status == AE_ABORT_METHOD) || AcpiGbl_AbortMethod) 215 { 216 /* Clear the abort and fall back to the debugger prompt */ 217 218 ACPI_EXCEPTION ((AE_INFO, Status, 219 "Aborting top-level method")); 220 221 AcpiGbl_AbortMethod = FALSE; 222 Status = AE_OK; 223 goto Cleanup; 224 } 225 226 ACPI_EXCEPTION ((AE_INFO, Status, 227 "while executing %s from AML Debugger", Info->Pathname)); 228 229 if (Status == AE_BUFFER_OVERFLOW) 230 { 231 ACPI_ERROR ((AE_INFO, 232 "Possible buffer overflow within AML Debugger " 233 "buffer (size 0x%X needed 0x%X)", 234 ACPI_DEBUG_BUFFER_SIZE, (UINT32) ReturnObj->Length)); 235 } 236 } 237 238 Cleanup: 239 AcpiDbDeleteObjects (ParamObjects.Count, Params); 240 return_ACPI_STATUS (Status); 241 } 242 243 244 /******************************************************************************* 245 * 246 * FUNCTION: AcpiDbExecuteSetup 247 * 248 * PARAMETERS: Info - Valid method info 249 * 250 * RETURN: None 251 * 252 * DESCRIPTION: Setup info segment prior to method execution 253 * 254 ******************************************************************************/ 255 256 static ACPI_STATUS 257 AcpiDbExecuteSetup ( 258 ACPI_DB_METHOD_INFO *Info) 259 { 260 ACPI_STATUS Status; 261 262 263 ACPI_FUNCTION_NAME (DbExecuteSetup); 264 265 266 /* Concatenate the current scope to the supplied name */ 267 268 Info->Pathname[0] = 0; 269 if ((Info->Name[0] != '\\') && 270 (Info->Name[0] != '/')) 271 { 272 if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname), 273 AcpiGbl_DbScopeBuf)) 274 { 275 Status = AE_BUFFER_OVERFLOW; 276 goto ErrorExit; 277 } 278 } 279 280 if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname), 281 Info->Name)) 282 { 283 Status = AE_BUFFER_OVERFLOW; 284 goto ErrorExit; 285 } 286 287 AcpiDbPrepNamestring (Info->Pathname); 288 289 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); 290 AcpiOsPrintf ("Evaluating %s\n", Info->Pathname); 291 292 if (Info->Flags & EX_SINGLE_STEP) 293 { 294 AcpiGbl_CmSingleStep = TRUE; 295 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); 296 } 297 298 else 299 { 300 /* No single step, allow redirection to a file */ 301 302 AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT); 303 } 304 305 return (AE_OK); 306 307 ErrorExit: 308 309 ACPI_EXCEPTION ((AE_INFO, Status, "During setup for method execution")); 310 return (Status); 311 } 312 313 314 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 315 UINT32 316 AcpiDbGetCacheInfo ( 317 ACPI_MEMORY_LIST *Cache) 318 { 319 320 return (Cache->TotalAllocated - Cache->TotalFreed - Cache->CurrentDepth); 321 } 322 #endif 323 324 /******************************************************************************* 325 * 326 * FUNCTION: AcpiDbGetOutstandingAllocations 327 * 328 * PARAMETERS: None 329 * 330 * RETURN: Current global allocation count minus cache entries 331 * 332 * DESCRIPTION: Determine the current number of "outstanding" allocations -- 333 * those allocations that have not been freed and also are not 334 * in one of the various object caches. 335 * 336 ******************************************************************************/ 337 338 #ifdef ACPI_DEBUG_OUTPUT 339 static UINT32 340 AcpiDbGetOutstandingAllocations ( 341 void) 342 { 343 UINT32 Outstanding = 0; 344 345 #ifdef ACPI_DBG_TRACK_ALLOCATIONS 346 347 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_StateCache); 348 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeCache); 349 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeExtCache); 350 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_OperandCache); 351 #endif 352 353 return (Outstanding); 354 } 355 #endif 356 357 358 /******************************************************************************* 359 * 360 * FUNCTION: AcpiDbExecutionWalk 361 * 362 * PARAMETERS: WALK_CALLBACK 363 * 364 * RETURN: Status 365 * 366 * DESCRIPTION: Execute a control method. Name is relative to the current 367 * scope. 368 * 369 ******************************************************************************/ 370 371 static ACPI_STATUS 372 AcpiDbExecutionWalk ( 373 ACPI_HANDLE ObjHandle, 374 UINT32 NestingLevel, 375 void *Context, 376 void **ReturnValue) 377 { 378 ACPI_OPERAND_OBJECT *ObjDesc; 379 ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; 380 ACPI_BUFFER ReturnObj; 381 ACPI_STATUS Status; 382 383 384 ObjDesc = AcpiNsGetAttachedObject (Node); 385 if (ObjDesc->Method.ParamCount) 386 { 387 return (AE_OK); 388 } 389 390 ReturnObj.Pointer = NULL; 391 ReturnObj.Length = ACPI_ALLOCATE_BUFFER; 392 393 AcpiNsPrintNodePathname (Node, "Evaluating"); 394 395 /* Do the actual method execution */ 396 397 AcpiOsPrintf ("\n"); 398 AcpiGbl_MethodExecuting = TRUE; 399 400 Status = AcpiEvaluateObject (Node, NULL, NULL, &ReturnObj); 401 402 AcpiGbl_MethodExecuting = FALSE; 403 404 AcpiOsPrintf ("Evaluation of [%4.4s] returned %s\n", 405 AcpiUtGetNodeName (Node), 406 AcpiFormatException (Status)); 407 408 return (AE_OK); 409 } 410 411 412 /******************************************************************************* 413 * 414 * FUNCTION: AcpiDbExecute 415 * 416 * PARAMETERS: Name - Name of method to execute 417 * Args - Parameters to the method 418 * Types - 419 * Flags - single step/no single step 420 * 421 * RETURN: None 422 * 423 * DESCRIPTION: Execute a control method. Name is relative to the current 424 * scope. Function used for the "EXECUTE", "EVALUATE", and 425 * "ALL" commands 426 * 427 ******************************************************************************/ 428 429 void 430 AcpiDbExecute ( 431 char *Name, 432 char **Args, 433 ACPI_OBJECT_TYPE *Types, 434 UINT32 Flags) 435 { 436 ACPI_STATUS Status; 437 ACPI_BUFFER ReturnObj; 438 char *NameString; 439 440 #ifdef ACPI_DEBUG_OUTPUT 441 UINT32 PreviousAllocations; 442 UINT32 Allocations; 443 #endif 444 445 446 /* 447 * Allow one execution to be performed by debugger or single step 448 * execution will be dead locked by the interpreter mutexes. 449 */ 450 if (AcpiGbl_MethodExecuting) 451 { 452 AcpiOsPrintf ("Only one debugger execution is allowed.\n"); 453 return; 454 } 455 456 #ifdef ACPI_DEBUG_OUTPUT 457 /* Memory allocation tracking */ 458 459 PreviousAllocations = AcpiDbGetOutstandingAllocations (); 460 #endif 461 462 if (*Name == '*') 463 { 464 (void) AcpiWalkNamespace (ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT, 465 ACPI_UINT32_MAX, AcpiDbExecutionWalk, NULL, NULL, NULL); 466 return; 467 } 468 469 if ((Flags & EX_ALL) && (strlen (Name) > 4)) 470 { 471 AcpiOsPrintf ("Input name (%s) must be a 4-char NameSeg\n", Name); 472 return; 473 } 474 475 NameString = ACPI_ALLOCATE (strlen (Name) + 1); 476 if (!NameString) 477 { 478 return; 479 } 480 481 memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO)); 482 strcpy (NameString, Name); 483 AcpiUtStrupr (NameString); 484 485 /* Subcommand to Execute all predefined names in the namespace */ 486 487 if (!strncmp (NameString, "PREDEF", 6)) 488 { 489 AcpiDbEvaluatePredefinedNames (); 490 ACPI_FREE (NameString); 491 return; 492 } 493 494 /* Command (ALL <nameseg>) to execute all methods of a particular name */ 495 496 else if (Flags & EX_ALL) 497 { 498 AcpiGbl_DbMethodInfo.Name = NameString; 499 ReturnObj.Pointer = NULL; 500 ReturnObj.Length = ACPI_ALLOCATE_BUFFER; 501 AcpiDbEvaluateAll (NameString); 502 ACPI_FREE (NameString); 503 return; 504 } 505 else 506 { 507 AcpiGbl_DbMethodInfo.Name = NameString; 508 AcpiGbl_DbMethodInfo.Args = Args; 509 AcpiGbl_DbMethodInfo.Types = Types; 510 AcpiGbl_DbMethodInfo.Flags = Flags; 511 512 ReturnObj.Pointer = NULL; 513 ReturnObj.Length = ACPI_ALLOCATE_BUFFER; 514 } 515 516 Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo); 517 if (ACPI_FAILURE (Status)) 518 { 519 ACPI_FREE (NameString); 520 return; 521 } 522 523 /* Get the NS node, determines existence also */ 524 525 Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname, 526 &AcpiGbl_DbMethodInfo.Method); 527 if (ACPI_SUCCESS (Status)) 528 { 529 Status = AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo, 530 &ReturnObj); 531 } 532 ACPI_FREE (NameString); 533 534 /* 535 * Allow any handlers in separate threads to complete. 536 * (Such as Notify handlers invoked from AML executed above). 537 */ 538 AcpiOsSleep ((UINT64) 10); 539 540 #ifdef ACPI_DEBUG_OUTPUT 541 542 /* Memory allocation tracking */ 543 544 Allocations = AcpiDbGetOutstandingAllocations () - PreviousAllocations; 545 546 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); 547 548 if (Allocations > 0) 549 { 550 AcpiOsPrintf ( 551 "0x%X Outstanding allocations after evaluation of %s\n", 552 Allocations, AcpiGbl_DbMethodInfo.Pathname); 553 } 554 #endif 555 556 if (ACPI_FAILURE (Status)) 557 { 558 AcpiOsPrintf ("Evaluation of %s failed with status %s\n", 559 AcpiGbl_DbMethodInfo.Pathname, 560 AcpiFormatException (Status)); 561 } 562 else 563 { 564 /* Display a return object, if any */ 565 566 if (ReturnObj.Length) 567 { 568 AcpiOsPrintf ( 569 "Evaluation of %s returned object %p, " 570 "external buffer length %X\n", 571 AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer, 572 (UINT32) ReturnObj.Length); 573 574 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1); 575 AcpiOsPrintf ("\n"); 576 577 /* Dump a _PLD buffer if present */ 578 579 if (ACPI_COMPARE_NAMESEG ((ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, 580 AcpiGbl_DbMethodInfo.Method)->Name.Ascii), 581 METHOD_NAME__PLD)) 582 { 583 AcpiDbDumpPldBuffer (ReturnObj.Pointer); 584 } 585 } 586 else 587 { 588 AcpiOsPrintf ("No object was returned from evaluation of %s\n", 589 AcpiGbl_DbMethodInfo.Pathname); 590 } 591 } 592 593 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); 594 } 595 596 597 /******************************************************************************* 598 * 599 * FUNCTION: AcpiDbMethodThread 600 * 601 * PARAMETERS: Context - Execution info segment 602 * 603 * RETURN: None 604 * 605 * DESCRIPTION: Debugger execute thread. Waits for a command line, then 606 * simply dispatches it. 607 * 608 ******************************************************************************/ 609 610 static void ACPI_SYSTEM_XFACE 611 AcpiDbMethodThread ( 612 void *Context) 613 { 614 ACPI_STATUS Status; 615 ACPI_DB_METHOD_INFO *Info = Context; 616 ACPI_DB_METHOD_INFO LocalInfo; 617 UINT32 i; 618 UINT8 Allow; 619 ACPI_BUFFER ReturnObj; 620 621 622 /* 623 * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments. 624 * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads 625 * concurrently. 626 * 627 * Note: The arguments we are passing are used by the ASL test suite 628 * (aslts). Do not change them without updating the tests. 629 */ 630 (void) AcpiOsWaitSemaphore (Info->InfoGate, 1, ACPI_WAIT_FOREVER); 631 632 if (Info->InitArgs) 633 { 634 AcpiDbUint32ToHexString (Info->NumCreated, 635 Info->IndexOfThreadStr); 636 AcpiDbUint32ToHexString ((UINT32) AcpiOsGetThreadId (), 637 Info->IdOfThreadStr); 638 } 639 640 if (Info->Threads && (Info->NumCreated < Info->NumThreads)) 641 { 642 Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId(); 643 } 644 645 LocalInfo = *Info; 646 LocalInfo.Args = LocalInfo.Arguments; 647 LocalInfo.Arguments[0] = LocalInfo.NumThreadsStr; 648 LocalInfo.Arguments[1] = LocalInfo.IdOfThreadStr; 649 LocalInfo.Arguments[2] = LocalInfo.IndexOfThreadStr; 650 LocalInfo.Arguments[3] = NULL; 651 652 LocalInfo.Types = LocalInfo.ArgTypes; 653 654 (void) AcpiOsSignalSemaphore (Info->InfoGate, 1); 655 656 for (i = 0; i < Info->NumLoops; i++) 657 { 658 Status = AcpiDbExecuteMethod (&LocalInfo, &ReturnObj); 659 if (ACPI_FAILURE (Status)) 660 { 661 AcpiOsPrintf ("%s During evaluation of %s at iteration %X\n", 662 AcpiFormatException (Status), Info->Pathname, i); 663 if (Status == AE_ABORT_METHOD) 664 { 665 break; 666 } 667 } 668 669 #if 0 670 if ((i % 100) == 0) 671 { 672 AcpiOsPrintf ("%u loops, Thread 0x%x\n", 673 i, AcpiOsGetThreadId ()); 674 } 675 676 if (ReturnObj.Length) 677 { 678 AcpiOsPrintf ("Evaluation of %s returned object %p Buflen %X\n", 679 Info->Pathname, ReturnObj.Pointer, 680 (UINT32) ReturnObj.Length); 681 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1); 682 } 683 #endif 684 } 685 686 /* Signal our completion */ 687 688 Allow = 0; 689 (void) AcpiOsWaitSemaphore (Info->ThreadCompleteGate, 690 1, ACPI_WAIT_FOREVER); 691 Info->NumCompleted++; 692 693 if (Info->NumCompleted == Info->NumThreads) 694 { 695 /* Do signal for main thread once only */ 696 Allow = 1; 697 } 698 699 (void) AcpiOsSignalSemaphore (Info->ThreadCompleteGate, 1); 700 701 if (Allow) 702 { 703 Status = AcpiOsSignalSemaphore (Info->MainThreadGate, 1); 704 if (ACPI_FAILURE (Status)) 705 { 706 AcpiOsPrintf ( 707 "Could not signal debugger thread sync semaphore, %s\n", 708 AcpiFormatException (Status)); 709 } 710 } 711 } 712 713 714 /******************************************************************************* 715 * 716 * FUNCTION: AcpiDbSingleExecutionThread 717 * 718 * PARAMETERS: Context - Method info struct 719 * 720 * RETURN: None 721 * 722 * DESCRIPTION: Create one thread and execute a method 723 * 724 ******************************************************************************/ 725 726 static void ACPI_SYSTEM_XFACE 727 AcpiDbSingleExecutionThread ( 728 void *Context) 729 { 730 ACPI_DB_METHOD_INFO *Info = Context; 731 ACPI_STATUS Status; 732 ACPI_BUFFER ReturnObj; 733 734 735 AcpiOsPrintf ("\n"); 736 737 Status = AcpiDbExecuteMethod (Info, &ReturnObj); 738 if (ACPI_FAILURE (Status)) 739 { 740 AcpiOsPrintf ("%s During evaluation of %s\n", 741 AcpiFormatException (Status), Info->Pathname); 742 return; 743 } 744 745 /* Display a return object, if any */ 746 747 if (ReturnObj.Length) 748 { 749 AcpiOsPrintf ("Evaluation of %s returned object %p, " 750 "external buffer length %X\n", 751 AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer, 752 (UINT32) ReturnObj.Length); 753 754 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1); 755 } 756 757 AcpiOsPrintf ("\nBackground thread completed\n%c ", 758 ACPI_DEBUGGER_COMMAND_PROMPT); 759 } 760 761 762 /******************************************************************************* 763 * 764 * FUNCTION: AcpiDbCreateExecutionThread 765 * 766 * PARAMETERS: MethodNameArg - Control method to execute 767 * Arguments - Array of arguments to the method 768 * Types - Corresponding array of object types 769 * 770 * RETURN: None 771 * 772 * DESCRIPTION: Create a single thread to evaluate a namespace object. Handles 773 * arguments passed on command line for control methods. 774 * 775 ******************************************************************************/ 776 777 void 778 AcpiDbCreateExecutionThread ( 779 char *MethodNameArg, 780 char **Arguments, 781 ACPI_OBJECT_TYPE *Types) 782 { 783 ACPI_STATUS Status; 784 UINT32 i; 785 786 787 memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO)); 788 AcpiGbl_DbMethodInfo.Name = MethodNameArg; 789 AcpiGbl_DbMethodInfo.InitArgs = 1; 790 AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments; 791 AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes; 792 793 /* Setup method arguments, up to 7 (0-6) */ 794 795 for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && *Arguments; i++) 796 { 797 AcpiGbl_DbMethodInfo.Arguments[i] = *Arguments; 798 Arguments++; 799 800 AcpiGbl_DbMethodInfo.ArgTypes[i] = *Types; 801 Types++; 802 } 803 804 Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo); 805 if (ACPI_FAILURE (Status)) 806 { 807 return; 808 } 809 810 /* Get the NS node, determines existence also */ 811 812 Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname, 813 &AcpiGbl_DbMethodInfo.Method); 814 if (ACPI_FAILURE (Status)) 815 { 816 AcpiOsPrintf ("%s Could not get handle for %s\n", 817 AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname); 818 return; 819 } 820 821 Status = AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD, 822 AcpiDbSingleExecutionThread, &AcpiGbl_DbMethodInfo); 823 if (ACPI_FAILURE (Status)) 824 { 825 return; 826 } 827 828 AcpiOsPrintf ("\nBackground thread started\n"); 829 } 830 831 832 /******************************************************************************* 833 * 834 * FUNCTION: AcpiDbCreateExecutionThreads 835 * 836 * PARAMETERS: NumThreadsArg - Number of threads to create 837 * NumLoopsArg - Loop count for the thread(s) 838 * MethodNameArg - Control method to execute 839 * 840 * RETURN: None 841 * 842 * DESCRIPTION: Create threads to execute method(s) 843 * 844 ******************************************************************************/ 845 846 void 847 AcpiDbCreateExecutionThreads ( 848 char *NumThreadsArg, 849 char *NumLoopsArg, 850 char *MethodNameArg) 851 { 852 ACPI_STATUS Status; 853 UINT32 NumThreads; 854 UINT32 NumLoops; 855 UINT32 i; 856 UINT32 Size; 857 ACPI_MUTEX MainThreadGate; 858 ACPI_MUTEX ThreadCompleteGate; 859 ACPI_MUTEX InfoGate; 860 861 862 /* Get the arguments */ 863 864 NumThreads = strtoul (NumThreadsArg, NULL, 0); 865 NumLoops = strtoul (NumLoopsArg, NULL, 0); 866 867 if (!NumThreads || !NumLoops) 868 { 869 AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n", 870 NumThreads, NumLoops); 871 return; 872 } 873 874 /* 875 * Create the semaphore for synchronization of 876 * the created threads with the main thread. 877 */ 878 Status = AcpiOsCreateSemaphore (1, 0, &MainThreadGate); 879 if (ACPI_FAILURE (Status)) 880 { 881 AcpiOsPrintf ("Could not create semaphore for " 882 "synchronization with the main thread, %s\n", 883 AcpiFormatException (Status)); 884 return; 885 } 886 887 /* 888 * Create the semaphore for synchronization 889 * between the created threads. 890 */ 891 Status = AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate); 892 if (ACPI_FAILURE (Status)) 893 { 894 AcpiOsPrintf ("Could not create semaphore for " 895 "synchronization between the created threads, %s\n", 896 AcpiFormatException (Status)); 897 898 (void) AcpiOsDeleteSemaphore (MainThreadGate); 899 return; 900 } 901 902 Status = AcpiOsCreateSemaphore (1, 1, &InfoGate); 903 if (ACPI_FAILURE (Status)) 904 { 905 AcpiOsPrintf ("Could not create semaphore for " 906 "synchronization of AcpiGbl_DbMethodInfo, %s\n", 907 AcpiFormatException (Status)); 908 909 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate); 910 (void) AcpiOsDeleteSemaphore (MainThreadGate); 911 return; 912 } 913 914 memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO)); 915 916 /* Array to store IDs of threads */ 917 918 AcpiGbl_DbMethodInfo.NumThreads = NumThreads; 919 Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads; 920 921 AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size); 922 if (AcpiGbl_DbMethodInfo.Threads == NULL) 923 { 924 AcpiOsPrintf ("No memory for thread IDs array\n"); 925 (void) AcpiOsDeleteSemaphore (MainThreadGate); 926 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate); 927 (void) AcpiOsDeleteSemaphore (InfoGate); 928 return; 929 } 930 memset (AcpiGbl_DbMethodInfo.Threads, 0, Size); 931 932 /* Setup the context to be passed to each thread */ 933 934 AcpiGbl_DbMethodInfo.Name = MethodNameArg; 935 AcpiGbl_DbMethodInfo.Flags = 0; 936 AcpiGbl_DbMethodInfo.NumLoops = NumLoops; 937 AcpiGbl_DbMethodInfo.MainThreadGate = MainThreadGate; 938 AcpiGbl_DbMethodInfo.ThreadCompleteGate = ThreadCompleteGate; 939 AcpiGbl_DbMethodInfo.InfoGate = InfoGate; 940 941 /* Init arguments to be passed to method */ 942 943 AcpiGbl_DbMethodInfo.InitArgs = 1; 944 AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments; 945 AcpiGbl_DbMethodInfo.Arguments[0] = AcpiGbl_DbMethodInfo.NumThreadsStr; 946 AcpiGbl_DbMethodInfo.Arguments[1] = AcpiGbl_DbMethodInfo.IdOfThreadStr; 947 AcpiGbl_DbMethodInfo.Arguments[2] = AcpiGbl_DbMethodInfo.IndexOfThreadStr; 948 AcpiGbl_DbMethodInfo.Arguments[3] = NULL; 949 950 AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes; 951 AcpiGbl_DbMethodInfo.ArgTypes[0] = ACPI_TYPE_INTEGER; 952 AcpiGbl_DbMethodInfo.ArgTypes[1] = ACPI_TYPE_INTEGER; 953 AcpiGbl_DbMethodInfo.ArgTypes[2] = ACPI_TYPE_INTEGER; 954 955 AcpiDbUint32ToHexString (NumThreads, AcpiGbl_DbMethodInfo.NumThreadsStr); 956 957 Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo); 958 if (ACPI_FAILURE (Status)) 959 { 960 goto CleanupAndExit; 961 } 962 963 /* Get the NS node, determines existence also */ 964 965 Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname, 966 &AcpiGbl_DbMethodInfo.Method); 967 if (ACPI_FAILURE (Status)) 968 { 969 AcpiOsPrintf ("%s Could not get handle for %s\n", 970 AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname); 971 goto CleanupAndExit; 972 } 973 974 /* Create the threads */ 975 976 AcpiOsPrintf ("Creating %X threads to execute %X times each\n", 977 NumThreads, NumLoops); 978 979 for (i = 0; i < (NumThreads); i++) 980 { 981 Status = AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD, AcpiDbMethodThread, 982 &AcpiGbl_DbMethodInfo); 983 if (ACPI_FAILURE (Status)) 984 { 985 break; 986 } 987 } 988 989 /* Wait for all threads to complete */ 990 991 (void) AcpiOsWaitSemaphore (MainThreadGate, 1, ACPI_WAIT_FOREVER); 992 993 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT); 994 AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads); 995 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT); 996 997 CleanupAndExit: 998 999 /* Cleanup and exit */ 1000 1001 (void) AcpiOsDeleteSemaphore (MainThreadGate); 1002 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate); 1003 (void) AcpiOsDeleteSemaphore (InfoGate); 1004 1005 AcpiOsFree (AcpiGbl_DbMethodInfo.Threads); 1006 AcpiGbl_DbMethodInfo.Threads = NULL; 1007 } 1008