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