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