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