1 /*******************************************************************************
   2  *
   3  * Module Name: dbmethod - Debug commands for control methods
   4  *
   5  ******************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2013, 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 "acdispat.h"
  48 #include "acnamesp.h"
  49 #include "acdebug.h"
  50 #include "acdisasm.h"
  51 #include "acparser.h"
  52 #include "acpredef.h"
  53 
  54 
  55 #ifdef ACPI_DEBUGGER
  56 
  57 #define _COMPONENT          ACPI_CA_DEBUGGER
  58         ACPI_MODULE_NAME    ("dbmethod")
  59 
  60 
  61 /* Local prototypes */
  62 
  63 static ACPI_STATUS
  64 AcpiDbWalkForExecute (
  65     ACPI_HANDLE             ObjHandle,
  66     UINT32                  NestingLevel,
  67     void                    *Context,
  68     void                    **ReturnValue);
  69 
  70 
  71 /*******************************************************************************
  72  *
  73  * FUNCTION:    AcpiDbSetMethodBreakpoint
  74  *
  75  * PARAMETERS:  Location            - AML offset of breakpoint
  76  *              WalkState           - Current walk info
  77  *              Op                  - Current Op (from parse walk)
  78  *
  79  * RETURN:      None
  80  *
  81  * DESCRIPTION: Set a breakpoint in a control method at the specified
  82  *              AML offset
  83  *
  84  ******************************************************************************/
  85 
  86 void
  87 AcpiDbSetMethodBreakpoint (
  88     char                    *Location,
  89     ACPI_WALK_STATE         *WalkState,
  90     ACPI_PARSE_OBJECT       *Op)
  91 {
  92     UINT32                  Address;
  93 
  94 
  95     if (!Op)
  96     {
  97         AcpiOsPrintf ("There is no method currently executing\n");
  98         return;
  99     }
 100 
 101     /* Get and verify the breakpoint address */
 102 
 103     Address = ACPI_STRTOUL (Location, NULL, 16);
 104     if (Address <= Op->Common.AmlOffset)
 105     {
 106         AcpiOsPrintf ("Breakpoint %X is beyond current address %X\n",
 107             Address, Op->Common.AmlOffset);
 108     }
 109 
 110     /* Save breakpoint in current walk */
 111 
 112     WalkState->UserBreakpoint = Address;
 113     AcpiOsPrintf ("Breakpoint set at AML offset %X\n", Address);
 114 }
 115 
 116 
 117 /*******************************************************************************
 118  *
 119  * FUNCTION:    AcpiDbSetMethodCallBreakpoint
 120  *
 121  * PARAMETERS:  Op                  - Current Op (from parse walk)
 122  *
 123  * RETURN:      None
 124  *
 125  * DESCRIPTION: Set a breakpoint in a control method at the specified
 126  *              AML offset
 127  *
 128  ******************************************************************************/
 129 
 130 void
 131 AcpiDbSetMethodCallBreakpoint (
 132     ACPI_PARSE_OBJECT       *Op)
 133 {
 134 
 135 
 136     if (!Op)
 137     {
 138         AcpiOsPrintf ("There is no method currently executing\n");
 139         return;
 140     }
 141 
 142     AcpiGbl_StepToNextCall = TRUE;
 143 }
 144 
 145 
 146 /*******************************************************************************
 147  *
 148  * FUNCTION:    AcpiDbSetMethodData
 149  *
 150  * PARAMETERS:  TypeArg         - L for local, A for argument
 151  *              IndexArg        - which one
 152  *              ValueArg        - Value to set.
 153  *
 154  * RETURN:      None
 155  *
 156  * DESCRIPTION: Set a local or argument for the running control method.
 157  *              NOTE: only object supported is Number.
 158  *
 159  ******************************************************************************/
 160 
 161 void
 162 AcpiDbSetMethodData (
 163     char                    *TypeArg,
 164     char                    *IndexArg,
 165     char                    *ValueArg)
 166 {
 167     char                    Type;
 168     UINT32                  Index;
 169     UINT32                  Value;
 170     ACPI_WALK_STATE         *WalkState;
 171     ACPI_OPERAND_OBJECT     *ObjDesc;
 172     ACPI_STATUS             Status;
 173     ACPI_NAMESPACE_NODE     *Node;
 174 
 175 
 176     /* Validate TypeArg */
 177 
 178     AcpiUtStrupr (TypeArg);
 179     Type = TypeArg[0];
 180     if ((Type != 'L') &&
 181         (Type != 'A') &&
 182         (Type != 'N'))
 183     {
 184         AcpiOsPrintf ("Invalid SET operand: %s\n", TypeArg);
 185         return;
 186     }
 187 
 188     Value = ACPI_STRTOUL (ValueArg, NULL, 16);
 189 
 190     if (Type == 'N')
 191     {
 192         Node = AcpiDbConvertToNode (IndexArg);
 193         if (Node->Type != ACPI_TYPE_INTEGER)
 194         {
 195             AcpiOsPrintf ("Can only set Integer nodes\n");
 196             return;
 197         }
 198         ObjDesc = Node->Object;
 199         ObjDesc->Integer.Value = Value;
 200         return;
 201     }
 202 
 203     /* Get the index and value */
 204 
 205     Index = ACPI_STRTOUL (IndexArg, NULL, 16);
 206 
 207     WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList);
 208     if (!WalkState)
 209     {
 210         AcpiOsPrintf ("There is no method currently executing\n");
 211         return;
 212     }
 213 
 214     /* Create and initialize the new object */
 215 
 216     ObjDesc = AcpiUtCreateIntegerObject ((UINT64) Value);
 217     if (!ObjDesc)
 218     {
 219         AcpiOsPrintf ("Could not create an internal object\n");
 220         return;
 221     }
 222 
 223     /* Store the new object into the target */
 224 
 225     switch (Type)
 226     {
 227     case 'A':
 228 
 229         /* Set a method argument */
 230 
 231         if (Index > ACPI_METHOD_MAX_ARG)
 232         {
 233             AcpiOsPrintf ("Arg%u - Invalid argument name\n", Index);
 234             goto Cleanup;
 235         }
 236 
 237         Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_ARG, Index, ObjDesc,
 238                     WalkState);
 239         if (ACPI_FAILURE (Status))
 240         {
 241             goto Cleanup;
 242         }
 243 
 244         ObjDesc = WalkState->Arguments[Index].Object;
 245 
 246         AcpiOsPrintf ("Arg%u: ", Index);
 247         AcpiDmDisplayInternalObject (ObjDesc, WalkState);
 248         break;
 249 
 250     case 'L':
 251 
 252         /* Set a method local */
 253 
 254         if (Index > ACPI_METHOD_MAX_LOCAL)
 255         {
 256             AcpiOsPrintf ("Local%u - Invalid local variable name\n", Index);
 257             goto Cleanup;
 258         }
 259 
 260         Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_LOCAL, Index, ObjDesc,
 261                     WalkState);
 262         if (ACPI_FAILURE (Status))
 263         {
 264             goto Cleanup;
 265         }
 266 
 267         ObjDesc = WalkState->LocalVariables[Index].Object;
 268 
 269         AcpiOsPrintf ("Local%u: ", Index);
 270         AcpiDmDisplayInternalObject (ObjDesc, WalkState);
 271         break;
 272 
 273     default:
 274 
 275         break;
 276     }
 277 
 278 Cleanup:
 279     AcpiUtRemoveReference (ObjDesc);
 280 }
 281 
 282 
 283 /*******************************************************************************
 284  *
 285  * FUNCTION:    AcpiDbDisassembleAml
 286  *
 287  * PARAMETERS:  Statements          - Number of statements to disassemble
 288  *              Op                  - Current Op (from parse walk)
 289  *
 290  * RETURN:      None
 291  *
 292  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
 293  *              of statements specified.
 294  *
 295  ******************************************************************************/
 296 
 297 void
 298 AcpiDbDisassembleAml (
 299     char                    *Statements,
 300     ACPI_PARSE_OBJECT       *Op)
 301 {
 302     UINT32                  NumStatements = 8;
 303 
 304 
 305     if (!Op)
 306     {
 307         AcpiOsPrintf ("There is no method currently executing\n");
 308         return;
 309     }
 310 
 311     if (Statements)
 312     {
 313         NumStatements = ACPI_STRTOUL (Statements, NULL, 0);
 314     }
 315 
 316     AcpiDmDisassemble (NULL, Op, NumStatements);
 317 }
 318 
 319 
 320 /*******************************************************************************
 321  *
 322  * FUNCTION:    AcpiDbDisassembleMethod
 323  *
 324  * PARAMETERS:  Name            - Name of control method
 325  *
 326  * RETURN:      None
 327  *
 328  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
 329  *              of statements specified.
 330  *
 331  ******************************************************************************/
 332 
 333 ACPI_STATUS
 334 AcpiDbDisassembleMethod (
 335     char                    *Name)
 336 {
 337     ACPI_STATUS             Status;
 338     ACPI_PARSE_OBJECT       *Op;
 339     ACPI_WALK_STATE         *WalkState;
 340     ACPI_OPERAND_OBJECT     *ObjDesc;
 341     ACPI_NAMESPACE_NODE     *Method;
 342 
 343 
 344     Method = AcpiDbConvertToNode (Name);
 345     if (!Method)
 346     {
 347         return (AE_BAD_PARAMETER);
 348     }
 349 
 350     if (Method->Type != ACPI_TYPE_METHOD)
 351     {
 352         ACPI_ERROR ((AE_INFO, "%s (%s): Object must be a control method",
 353             Name, AcpiUtGetTypeName (Method->Type)));
 354         return (AE_BAD_PARAMETER);
 355     }
 356 
 357     ObjDesc = Method->Object;
 358 
 359     Op = AcpiPsCreateScopeOp ();
 360     if (!Op)
 361     {
 362         return (AE_NO_MEMORY);
 363     }
 364 
 365     /* Create and initialize a new walk state */
 366 
 367     WalkState = AcpiDsCreateWalkState (0, Op, NULL, NULL);
 368     if (!WalkState)
 369     {
 370         return (AE_NO_MEMORY);
 371     }
 372 
 373     Status = AcpiDsInitAmlWalk (WalkState, Op, NULL,
 374         ObjDesc->Method.AmlStart,
 375         ObjDesc->Method.AmlLength, NULL, ACPI_IMODE_LOAD_PASS1);
 376     if (ACPI_FAILURE (Status))
 377     {
 378         return (Status);
 379     }
 380 
 381     Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
 382     WalkState->OwnerId = ObjDesc->Method.OwnerId;
 383 
 384     /* Push start scope on scope stack and make it current */
 385 
 386     Status = AcpiDsScopeStackPush (Method,
 387         Method->Type, WalkState);
 388     if (ACPI_FAILURE (Status))
 389     {
 390         return (Status);
 391     }
 392 
 393     /* Parse the entire method AML including deferred operators */
 394 
 395     WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE;
 396     WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE;
 397 
 398     Status = AcpiPsParseAml (WalkState);
 399     (void) AcpiDmParseDeferredOps (Op);
 400 
 401     /* Now we can disassemble the method */
 402 
 403     AcpiGbl_DbOpt_verbose = FALSE;
 404     AcpiDmDisassemble (NULL, Op, 0);
 405     AcpiGbl_DbOpt_verbose = TRUE;
 406 
 407     AcpiPsDeleteParseTree (Op);
 408 
 409     /* Method cleanup */
 410 
 411     AcpiNsDeleteNamespaceSubtree (Method);
 412     AcpiNsDeleteNamespaceByOwner (ObjDesc->Method.OwnerId);
 413     AcpiUtReleaseOwnerId (&ObjDesc->Method.OwnerId);
 414     return (AE_OK);
 415 }
 416 
 417 
 418 /*******************************************************************************
 419  *
 420  * FUNCTION:    AcpiDbWalkForExecute
 421  *
 422  * PARAMETERS:  Callback from WalkNamespace
 423  *
 424  * RETURN:      Status
 425  *
 426  * DESCRIPTION: Batch execution module. Currently only executes predefined
 427  *              ACPI names.
 428  *
 429  ******************************************************************************/
 430 
 431 static ACPI_STATUS
 432 AcpiDbWalkForExecute (
 433     ACPI_HANDLE             ObjHandle,
 434     UINT32                  NestingLevel,
 435     void                    *Context,
 436     void                    **ReturnValue)
 437 {
 438     ACPI_NAMESPACE_NODE         *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
 439     ACPI_DB_EXECUTE_WALK        *Info = (ACPI_DB_EXECUTE_WALK *) Context;
 440     char                        *Pathname;
 441     const ACPI_PREDEFINED_INFO  *Predefined;
 442     ACPI_DEVICE_INFO            *ObjInfo;
 443     ACPI_OBJECT_LIST            ParamObjects;
 444     ACPI_OBJECT                 Params[ACPI_METHOD_NUM_ARGS];
 445     ACPI_OBJECT                 *ThisParam;
 446     ACPI_BUFFER                 ReturnObj;
 447     ACPI_STATUS                 Status;
 448     UINT16                      ArgTypeList;
 449     UINT8                       ArgCount;
 450     UINT8                       ArgType;
 451     UINT32                      i;
 452 
 453 
 454     /* The name must be a predefined ACPI name */
 455 
 456     Predefined = AcpiUtMatchPredefinedMethod (Node->Name.Ascii);
 457     if (!Predefined)
 458     {
 459         return (AE_OK);
 460     }
 461 
 462     if (Node->Type == ACPI_TYPE_LOCAL_SCOPE)
 463     {
 464         return (AE_OK);
 465     }
 466 
 467     Pathname = AcpiNsGetExternalPathname (Node);
 468     if (!Pathname)
 469     {
 470         return (AE_OK);
 471     }
 472 
 473     /* Get the object info for number of method parameters */
 474 
 475     Status = AcpiGetObjectInfo (ObjHandle, &ObjInfo);
 476     if (ACPI_FAILURE (Status))
 477     {
 478         return (Status);
 479     }
 480 
 481     ParamObjects.Count = 0;
 482     ParamObjects.Pointer = NULL;
 483 
 484     if (ObjInfo->Type == ACPI_TYPE_METHOD)
 485     {
 486         /* Setup default parameters (with proper types) */
 487 
 488         ArgTypeList = Predefined->Info.ArgumentList;
 489         ArgCount = METHOD_GET_ARG_COUNT (ArgTypeList);
 490 
 491         /*
 492          * Setup the ACPI-required number of arguments, regardless of what
 493          * the actual method defines. If there is a difference, then the
 494          * method is wrong and a warning will be issued during execution.
 495          */
 496         ThisParam = Params;
 497         for (i = 0; i < ArgCount; i++)
 498         {
 499             ArgType = METHOD_GET_NEXT_TYPE (ArgTypeList);
 500             ThisParam->Type = ArgType;
 501 
 502             switch (ArgType)
 503             {
 504             case ACPI_TYPE_INTEGER:
 505 
 506                 ThisParam->Integer.Value = 1;
 507                 break;
 508 
 509             case ACPI_TYPE_STRING:
 510 
 511                 ThisParam->String.Pointer = "This is the default argument string";
 512                 ThisParam->String.Length = ACPI_STRLEN (ThisParam->String.Pointer);
 513                 break;
 514 
 515             case ACPI_TYPE_BUFFER:
 516 
 517                 ThisParam->Buffer.Pointer = (UINT8 *) Params; /* just a garbage buffer */
 518                 ThisParam->Buffer.Length = 48;
 519                 break;
 520 
 521              case ACPI_TYPE_PACKAGE:
 522 
 523                 ThisParam->Package.Elements = NULL;
 524                 ThisParam->Package.Count = 0;
 525                 break;
 526 
 527            default:
 528 
 529                 AcpiOsPrintf ("%s: Unsupported argument type: %u\n",
 530                     Pathname, ArgType);
 531                 break;
 532             }
 533 
 534             ThisParam++;
 535         }
 536 
 537         ParamObjects.Count = ArgCount;
 538         ParamObjects.Pointer = Params;
 539     }
 540 
 541     ACPI_FREE (ObjInfo);
 542     ReturnObj.Pointer = NULL;
 543     ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
 544 
 545     /* Do the actual method execution */
 546 
 547     AcpiGbl_MethodExecuting = TRUE;
 548 
 549     Status = AcpiEvaluateObject (Node, NULL, &ParamObjects, &ReturnObj);
 550 
 551     AcpiOsPrintf ("%-32s returned %s\n", Pathname, AcpiFormatException (Status));
 552     AcpiGbl_MethodExecuting = FALSE;
 553     ACPI_FREE (Pathname);
 554 
 555     /* Ignore status from method execution */
 556 
 557     Status = AE_OK;
 558 
 559     /* Update count, check if we have executed enough methods */
 560 
 561     Info->Count++;
 562     if (Info->Count >= Info->MaxCount)
 563     {
 564         Status = AE_CTRL_TERMINATE;
 565     }
 566 
 567     return (Status);
 568 }
 569 
 570 
 571 /*******************************************************************************
 572  *
 573  * FUNCTION:    AcpiDbBatchExecute
 574  *
 575  * PARAMETERS:  CountArg            - Max number of methods to execute
 576  *
 577  * RETURN:      None
 578  *
 579  * DESCRIPTION: Namespace batch execution. Execute predefined names in the
 580  *              namespace, up to the max count, if specified.
 581  *
 582  ******************************************************************************/
 583 
 584 void
 585 AcpiDbBatchExecute (
 586     char                    *CountArg)
 587 {
 588     ACPI_DB_EXECUTE_WALK    Info;
 589 
 590 
 591     Info.Count = 0;
 592     Info.MaxCount = ACPI_UINT32_MAX;
 593 
 594     if (CountArg)
 595     {
 596         Info.MaxCount = ACPI_STRTOUL (CountArg, NULL, 0);
 597     }
 598 
 599 
 600     /* Search all nodes in namespace */
 601 
 602     (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
 603                 AcpiDbWalkForExecute, NULL, (void *) &Info, NULL);
 604 
 605     AcpiOsPrintf ("Evaluated %u predefined names in the namespace\n", Info.Count);
 606 }
 607 
 608 #endif /* ACPI_DEBUGGER */