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