1 /*******************************************************************************
2  *
3  * Module Name: dbmethod - Debug commands for control methods
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acdispat.h"
47 #include "acnamesp.h"
48 #include "acdebug.h"
49 #include "acparser.h"
50 #include "acpredef.h"
51 
52 
53 #ifdef ACPI_DEBUGGER
54 
55 #define _COMPONENT          ACPI_CA_DEBUGGER
56         ACPI_MODULE_NAME    ("dbmethod")
57 
58 /* Local prototypes */
59 
60 static ACPI_STATUS
61 AcpiDbWalkForExecute (
62     ACPI_HANDLE             ObjHandle,
63     UINT32                  NestingLevel,
64     void                    *Context,
65     void                    **ReturnValue);
66 
67 
68 /*******************************************************************************
69  *
70  * FUNCTION:    AcpiDbSetMethodBreakpoint
71  *
72  * PARAMETERS:  Location            - AML offset of breakpoint
73  *              WalkState           - Current walk info
74  *              Op                  - Current Op (from parse walk)
75  *
76  * RETURN:      None
77  *
78  * DESCRIPTION: Set a breakpoint in a control method at the specified
79  *              AML offset
80  *
81  ******************************************************************************/
82 
83 void
84 AcpiDbSetMethodBreakpoint (
85     char                    *Location,
86     ACPI_WALK_STATE         *WalkState,
87     ACPI_PARSE_OBJECT       *Op)
88 {
89     UINT32                  Address;
90     UINT32                  AmlOffset;
91 
92 
93     if (!Op)
94     {
95         AcpiOsPrintf ("There is no method currently executing\n");
96         return;
97     }
98 
99     /* Get and verify the breakpoint address */
100 
101     Address = strtoul (Location, NULL, 16);
102     AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
103         WalkState->ParserState.AmlStart);
104     if (Address <= AmlOffset)
105     {
106         AcpiOsPrintf ("Breakpoint %X is beyond current address %X\n",
107             Address, 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 = strtoul (ValueArg, NULL, 16);
189 
190     if (Type == 'N')
191     {
192         Node = AcpiDbConvertToNode (IndexArg);
193         if (!Node)
194         {
195             return;
196         }
197 
198         if (Node->Type != ACPI_TYPE_INTEGER)
199         {
200             AcpiOsPrintf ("Can only set Integer nodes\n");
201             return;
202         }
203         ObjDesc = Node->Object;
204         ObjDesc->Integer.Value = Value;
205         return;
206     }
207 
208     /* Get the index and value */
209 
210     Index = strtoul (IndexArg, NULL, 16);
211 
212     WalkState = AcpiDsGetCurrentWalkState (AcpiGbl_CurrentWalkList);
213     if (!WalkState)
214     {
215         AcpiOsPrintf ("There is no method currently executing\n");
216         return;
217     }
218 
219     /* Create and initialize the new object */
220 
221     ObjDesc = AcpiUtCreateIntegerObject ((UINT64) Value);
222     if (!ObjDesc)
223     {
224         AcpiOsPrintf ("Could not create an internal object\n");
225         return;
226     }
227 
228     /* Store the new object into the target */
229 
230     switch (Type)
231     {
232     case 'A':
233 
234         /* Set a method argument */
235 
236         if (Index > ACPI_METHOD_MAX_ARG)
237         {
238             AcpiOsPrintf ("Arg%u - Invalid argument name\n",
239                 Index);
240             goto Cleanup;
241         }
242 
243         Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_ARG,
244             Index, ObjDesc, WalkState);
245         if (ACPI_FAILURE (Status))
246         {
247             goto Cleanup;
248         }
249 
250         ObjDesc = WalkState->Arguments[Index].Object;
251 
252         AcpiOsPrintf ("Arg%u: ", Index);
253         AcpiDbDisplayInternalObject (ObjDesc, WalkState);
254         break;
255 
256     case 'L':
257 
258         /* Set a method local */
259 
260         if (Index > ACPI_METHOD_MAX_LOCAL)
261         {
262             AcpiOsPrintf ("Local%u - Invalid local variable name\n",
263                 Index);
264             goto Cleanup;
265         }
266 
267         Status = AcpiDsStoreObjectToLocal (ACPI_REFCLASS_LOCAL,
268             Index, ObjDesc, WalkState);
269         if (ACPI_FAILURE (Status))
270         {
271             goto Cleanup;
272         }
273 
274         ObjDesc = WalkState->LocalVariables[Index].Object;
275 
276         AcpiOsPrintf ("Local%u: ", Index);
277         AcpiDbDisplayInternalObject (ObjDesc, WalkState);
278         break;
279 
280     default:
281 
282         break;
283     }
284 
285 Cleanup:
286     AcpiUtRemoveReference (ObjDesc);
287 }
288 
289 
290 /*******************************************************************************
291  *
292  * FUNCTION:    AcpiDbDisassembleAml
293  *
294  * PARAMETERS:  Statements          - Number of statements to disassemble
295  *              Op                  - Current Op (from parse walk)
296  *
297  * RETURN:      None
298  *
299  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
300  *              of statements specified.
301  *
302  ******************************************************************************/
303 
304 void
305 AcpiDbDisassembleAml (
306     char                    *Statements,
307     ACPI_PARSE_OBJECT       *Op)
308 {
309     UINT32                  NumStatements = 8;
310 
311 
312     if (!Op)
313     {
314         AcpiOsPrintf ("There is no method currently executing\n");
315         return;
316     }
317 
318     if (Statements)
319     {
320         NumStatements = strtoul (Statements, NULL, 0);
321     }
322 
323 #ifdef ACPI_DISASSEMBLER
324     AcpiDmDisassemble (NULL, Op, NumStatements);
325 #endif
326 }
327 
328 
329 /*******************************************************************************
330  *
331  * FUNCTION:    AcpiDbDisassembleMethod
332  *
333  * PARAMETERS:  Name            - Name of control method
334  *
335  * RETURN:      None
336  *
337  * DESCRIPTION: Display disassembled AML (ASL) starting from Op for the number
338  *              of statements specified.
339  *
340  ******************************************************************************/
341 
342 ACPI_STATUS
343 AcpiDbDisassembleMethod (
344     char                    *Name)
345 {
346     ACPI_STATUS             Status;
347     ACPI_PARSE_OBJECT       *Op;
348     ACPI_WALK_STATE         *WalkState;
349     ACPI_OPERAND_OBJECT     *ObjDesc;
350     ACPI_NAMESPACE_NODE     *Method;
351 
352 
353     Method = AcpiDbConvertToNode (Name);
354     if (!Method)
355     {
356         return (AE_BAD_PARAMETER);
357     }
358 
359     if (Method->Type != ACPI_TYPE_METHOD)
360     {
361         ACPI_ERROR ((AE_INFO, "%s (%s): Object must be a control method",
362             Name, AcpiUtGetTypeName (Method->Type)));
363         return (AE_BAD_PARAMETER);
364     }
365 
366     ObjDesc = Method->Object;
367 
368     Op = AcpiPsCreateScopeOp (ObjDesc->Method.AmlStart);
369     if (!Op)
370     {
371         return (AE_NO_MEMORY);
372     }
373 
374     /* Create and initialize a new walk state */
375 
376     WalkState = AcpiDsCreateWalkState (0, Op, NULL, NULL);
377     if (!WalkState)
378     {
379         return (AE_NO_MEMORY);
380     }
381 
382     Status = AcpiDsInitAmlWalk (WalkState, Op, NULL,
383         ObjDesc->Method.AmlStart,
384         ObjDesc->Method.AmlLength, NULL, ACPI_IMODE_LOAD_PASS1);
385     if (ACPI_FAILURE (Status))
386     {
387         return (Status);
388     }
389 
390     Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId);
391     WalkState->OwnerId = ObjDesc->Method.OwnerId;
392 
393     /* Push start scope on scope stack and make it current */
394 
395     Status = AcpiDsScopeStackPush (Method,
396         Method->Type, WalkState);
397     if (ACPI_FAILURE (Status))
398     {
399         return (Status);
400     }
401 
402     /* Parse the entire method AML including deferred operators */
403 
404     WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE;
405     WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE;
406 
407     Status = AcpiPsParseAml (WalkState);
408 
409 #ifdef ACPI_DISASSEMBLER
410     (void) AcpiDmParseDeferredOps (Op);
411 
412     /* Now we can disassemble the method */
413 
414     AcpiGbl_DmOpt_Verbose = FALSE;
415     AcpiDmDisassemble (NULL, Op, 0);
416     AcpiGbl_DmOpt_Verbose = TRUE;
417 #endif
418 
419     AcpiPsDeleteParseTree (Op);
420 
421     /* Method cleanup */
422 
423     AcpiNsDeleteNamespaceSubtree (Method);
424     AcpiNsDeleteNamespaceByOwner (ObjDesc->Method.OwnerId);
425     AcpiUtReleaseOwnerId (&ObjDesc->Method.OwnerId);
426     return (AE_OK);
427 }
428 
429 
430 /*******************************************************************************
431  *
432  * FUNCTION:    AcpiDbWalkForExecute
433  *
434  * PARAMETERS:  Callback from WalkNamespace
435  *
436  * RETURN:      Status
437  *
438  * DESCRIPTION: Batch execution module. Currently only executes predefined
439  *              ACPI names.
440  *
441  ******************************************************************************/
442 
443 static ACPI_STATUS
444 AcpiDbWalkForExecute (
445     ACPI_HANDLE             ObjHandle,
446     UINT32                  NestingLevel,
447     void                    *Context,
448     void                    **ReturnValue)
449 {
450     ACPI_NAMESPACE_NODE     *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
451     ACPI_DB_EXECUTE_WALK    *Info = (ACPI_DB_EXECUTE_WALK *) Context;
452     ACPI_BUFFER             ReturnObj;
453     ACPI_STATUS             Status;
454     char                    *Pathname;
455     UINT32                  i;
456     ACPI_DEVICE_INFO        *ObjInfo;
457     ACPI_OBJECT_LIST        ParamObjects;
458     ACPI_OBJECT             Params[ACPI_METHOD_NUM_ARGS];
459     const ACPI_PREDEFINED_INFO *Predefined;
460 
461 
462     Predefined = AcpiUtMatchPredefinedMethod (Node->Name.Ascii);
463     if (!Predefined)
464     {
465         return (AE_OK);
466     }
467 
468     if (Node->Type == ACPI_TYPE_LOCAL_SCOPE)
469     {
470         return (AE_OK);
471     }
472 
473     Pathname = AcpiNsGetExternalPathname (Node);
474     if (!Pathname)
475     {
476         return (AE_OK);
477     }
478 
479     /* Get the object info for number of method parameters */
480 
481     Status = AcpiGetObjectInfo (ObjHandle, &ObjInfo);
482     if (ACPI_FAILURE (Status))
483     {
484         return (Status);
485     }
486 
487     ParamObjects.Pointer = NULL;
488     ParamObjects.Count   = 0;
489 
490     if (ObjInfo->Type == ACPI_TYPE_METHOD)
491     {
492         /* Setup default parameters */
493 
494         for (i = 0; i < ObjInfo->ParamCount; i++)
495         {
496             Params[i].Type           = ACPI_TYPE_INTEGER;
497             Params[i].Integer.Value  = 1;
498         }
499 
500         ParamObjects.Pointer     = Params;
501         ParamObjects.Count       = ObjInfo->ParamCount;
502     }
503 
504     ACPI_FREE (ObjInfo);
505     ReturnObj.Pointer = NULL;
506     ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
507 
508     /* Do the actual method execution */
509 
510     AcpiGbl_MethodExecuting = TRUE;
511 
512     Status = AcpiEvaluateObject (Node, NULL, &ParamObjects, &ReturnObj);
513 
514     AcpiOsPrintf ("%-32s returned %s\n", Pathname, AcpiFormatException (Status));
515     AcpiGbl_MethodExecuting = FALSE;
516     ACPI_FREE (Pathname);
517 
518     /* Ignore status from method execution */
519 
520     Status = AE_OK;
521 
522     /* Update count, check if we have executed enough methods */
523 
524     Info->Count++;
525     if (Info->Count >= Info->MaxCount)
526     {
527         Status = AE_CTRL_TERMINATE;
528     }
529 
530     return (Status);
531 }
532 
533 
534 /*******************************************************************************
535  *
536  * FUNCTION:    AcpiDbEvaluatePredefinedNames
537  *
538  * PARAMETERS:  None
539  *
540  * RETURN:      None
541  *
542  * DESCRIPTION: Namespace batch execution. Execute predefined names in the
543  *              namespace, up to the max count, if specified.
544  *
545  ******************************************************************************/
546 
547 void
548 AcpiDbEvaluatePredefinedNames (
549     void)
550 {
551     ACPI_DB_EXECUTE_WALK    Info;
552 
553 
554     Info.Count = 0;
555     Info.MaxCount = ACPI_UINT32_MAX;
556 
557     /* Search all nodes in namespace */
558 
559     (void) AcpiWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
560                 AcpiDbWalkForExecute, NULL, (void *) &Info, NULL);
561 
562     AcpiOsPrintf ("Evaluated %u predefined names in the namespace\n", Info.Count);
563 }
564 
565 #endif /* ACPI_DEBUGGER */
566