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