167754Smsmith/*******************************************************************************
267754Smsmith *
367754Smsmith * Module Name: dbexec - debugger control method execution
467754Smsmith *
567754Smsmith ******************************************************************************/
667754Smsmith
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
970243Smsmith * All rights reserved.
1067754Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2567754Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2967754Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4367754Smsmith
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
46193341Sjkim#include <contrib/dev/acpica/include/acdebug.h>
47193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
4867754Smsmith
4967754Smsmith
50102550Siwasaki#define _COMPONENT          ACPI_CA_DEBUGGER
5191116Smsmith        ACPI_MODULE_NAME    ("dbexec")
5267754Smsmith
5367754Smsmith
54222544Sjkimstatic ACPI_DB_METHOD_INFO          AcpiGbl_DbMethodInfo;
5567754Smsmith
56151937Sjkim/* Local prototypes */
5767754Smsmith
58151937Sjkimstatic ACPI_STATUS
59151937SjkimAcpiDbExecuteMethod (
60151937Sjkim    ACPI_DB_METHOD_INFO     *Info,
61151937Sjkim    ACPI_BUFFER             *ReturnObj);
62151937Sjkim
63281075Sdimstatic ACPI_STATUS
64151937SjkimAcpiDbExecuteSetup (
65151937Sjkim    ACPI_DB_METHOD_INFO     *Info);
66151937Sjkim
67151937Sjkimstatic UINT32
68151937SjkimAcpiDbGetOutstandingAllocations (
69151937Sjkim    void);
70151937Sjkim
71151937Sjkimstatic void ACPI_SYSTEM_XFACE
72151937SjkimAcpiDbMethodThread (
73151937Sjkim    void                    *Context);
74151937Sjkim
75151937Sjkimstatic ACPI_STATUS
76151937SjkimAcpiDbExecutionWalk (
77151937Sjkim    ACPI_HANDLE             ObjHandle,
78151937Sjkim    UINT32                  NestingLevel,
79151937Sjkim    void                    *Context,
80151937Sjkim    void                    **ReturnValue);
81151937Sjkim
82151937Sjkim
8367754Smsmith/*******************************************************************************
8467754Smsmith *
85222544Sjkim * FUNCTION:    AcpiDbDeleteObjects
86222544Sjkim *
87222544Sjkim * PARAMETERS:  Count               - Count of objects in the list
88222544Sjkim *              Objects             - Array of ACPI_OBJECTs to be deleted
89222544Sjkim *
90222544Sjkim * RETURN:      None
91222544Sjkim *
92222544Sjkim * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
93222544Sjkim *              packages via recursion.
94222544Sjkim *
95222544Sjkim ******************************************************************************/
96222544Sjkim
97245582Sjkimvoid
98222544SjkimAcpiDbDeleteObjects (
99222544Sjkim    UINT32                  Count,
100222544Sjkim    ACPI_OBJECT             *Objects)
101222544Sjkim{
102222544Sjkim    UINT32                  i;
103222544Sjkim
104222544Sjkim
105222544Sjkim    for (i = 0; i < Count; i++)
106222544Sjkim    {
107222544Sjkim        switch (Objects[i].Type)
108222544Sjkim        {
109222544Sjkim        case ACPI_TYPE_BUFFER:
110250838Sjkim
111222544Sjkim            ACPI_FREE (Objects[i].Buffer.Pointer);
112222544Sjkim            break;
113222544Sjkim
114222544Sjkim        case ACPI_TYPE_PACKAGE:
115222544Sjkim
116222544Sjkim            /* Recursive call to delete package elements */
117222544Sjkim
118222544Sjkim            AcpiDbDeleteObjects (Objects[i].Package.Count,
119222544Sjkim                Objects[i].Package.Elements);
120222544Sjkim
121222544Sjkim            /* Free the elements array */
122222544Sjkim
123222544Sjkim            ACPI_FREE (Objects[i].Package.Elements);
124222544Sjkim            break;
125222544Sjkim
126222544Sjkim        default:
127250838Sjkim
128222544Sjkim            break;
129222544Sjkim        }
130222544Sjkim    }
131222544Sjkim}
132222544Sjkim
133222544Sjkim
134222544Sjkim/*******************************************************************************
135222544Sjkim *
13667754Smsmith * FUNCTION:    AcpiDbExecuteMethod
13767754Smsmith *
13867754Smsmith * PARAMETERS:  Info            - Valid info segment
13967754Smsmith *              ReturnObj       - Where to put return object
14067754Smsmith *
14167754Smsmith * RETURN:      Status
14267754Smsmith *
14367754Smsmith * DESCRIPTION: Execute a control method.
14467754Smsmith *
14567754Smsmith ******************************************************************************/
14667754Smsmith
147151937Sjkimstatic ACPI_STATUS
14867754SmsmithAcpiDbExecuteMethod (
14991116Smsmith    ACPI_DB_METHOD_INFO     *Info,
15067754Smsmith    ACPI_BUFFER             *ReturnObj)
15167754Smsmith{
15267754Smsmith    ACPI_STATUS             Status;
15367754Smsmith    ACPI_OBJECT_LIST        ParamObjects;
154249663Sjkim    ACPI_OBJECT             Params[ACPI_DEBUGGER_MAX_ARGS + 1];
15567754Smsmith    UINT32                  i;
15667754Smsmith
15767754Smsmith
158216471Sjkim    ACPI_FUNCTION_TRACE (DbExecuteMethod);
159216471Sjkim
160216471Sjkim
16183174Smsmith    if (AcpiGbl_DbOutputToFile && !AcpiDbgLevel)
16267754Smsmith    {
16367754Smsmith        AcpiOsPrintf ("Warning: debug output is not enabled!\n");
16467754Smsmith    }
16567754Smsmith
166249663Sjkim    ParamObjects.Count = 0;
167249663Sjkim    ParamObjects.Pointer = NULL;
168193267Sjkim
169249663Sjkim    /* Pass through any command-line arguments */
170193267Sjkim
171249663Sjkim    if (Info->Args && Info->Args[0])
17267754Smsmith    {
173249663Sjkim        /* Get arguments passed on the command line */
17467754Smsmith
175249663Sjkim        for (i = 0; (Info->Args[i] && *(Info->Args[i])); i++)
176193267Sjkim        {
177249663Sjkim            /* Convert input string (token) to an actual ACPI_OBJECT */
178222544Sjkim
179249663Sjkim            Status = AcpiDbConvertToObject (Info->Types[i],
180249663Sjkim                Info->Args[i], &Params[i]);
181249663Sjkim            if (ACPI_FAILURE (Status))
182193267Sjkim            {
183249663Sjkim                ACPI_EXCEPTION ((AE_INFO, Status,
184249663Sjkim                    "While parsing method arguments"));
185249663Sjkim                goto Cleanup;
186193267Sjkim            }
187222544Sjkim        }
18867754Smsmith
189249663Sjkim        ParamObjects.Count = i;
190222544Sjkim        ParamObjects.Pointer = Params;
19167754Smsmith    }
19267754Smsmith
19367754Smsmith    /* Prepare for a return object of arbitrary size */
19467754Smsmith
195151937Sjkim    ReturnObj->Pointer = AcpiGbl_DbBuffer;
196151937Sjkim    ReturnObj->Length  = ACPI_DEBUG_BUFFER_SIZE;
19767754Smsmith
19867754Smsmith    /* Do the actual method execution */
19967754Smsmith
200114237Snjl    AcpiGbl_MethodExecuting = TRUE;
201249663Sjkim    Status = AcpiEvaluateObject (NULL, Info->Pathname,
202249663Sjkim        &ParamObjects, ReturnObj);
20367754Smsmith
20467754Smsmith    AcpiGbl_CmSingleStep = FALSE;
20567754Smsmith    AcpiGbl_MethodExecuting = FALSE;
20667754Smsmith
207216471Sjkim    if (ACPI_FAILURE (Status))
208216471Sjkim    {
209216471Sjkim        ACPI_EXCEPTION ((AE_INFO, Status,
210222544Sjkim            "while executing %s from debugger", Info->Pathname));
211216471Sjkim
212216471Sjkim        if (Status == AE_BUFFER_OVERFLOW)
213216471Sjkim        {
214216471Sjkim            ACPI_ERROR ((AE_INFO,
215306536Sjkim                "Possible overflow of internal debugger "
216306536Sjkim                "buffer (size 0x%X needed 0x%X)",
217216471Sjkim                ACPI_DEBUG_BUFFER_SIZE, (UINT32) ReturnObj->Length));
218216471Sjkim        }
219216471Sjkim    }
220216471Sjkim
221222544SjkimCleanup:
222249663Sjkim    AcpiDbDeleteObjects (ParamObjects.Count, Params);
223216471Sjkim    return_ACPI_STATUS (Status);
22467754Smsmith}
22567754Smsmith
22667754Smsmith
22767754Smsmith/*******************************************************************************
22867754Smsmith *
22967754Smsmith * FUNCTION:    AcpiDbExecuteSetup
23067754Smsmith *
23167754Smsmith * PARAMETERS:  Info            - Valid method info
23267754Smsmith *
233151937Sjkim * RETURN:      None
23467754Smsmith *
23567754Smsmith * DESCRIPTION: Setup info segment prior to method execution
23667754Smsmith *
23767754Smsmith ******************************************************************************/
23867754Smsmith
239281075Sdimstatic ACPI_STATUS
24067754SmsmithAcpiDbExecuteSetup (
24199679Siwasaki    ACPI_DB_METHOD_INFO     *Info)
24267754Smsmith{
243281075Sdim    ACPI_STATUS             Status;
24467754Smsmith
245281075Sdim
246281075Sdim    ACPI_FUNCTION_NAME (DbExecuteSetup);
247281075Sdim
248281075Sdim
24967754Smsmith    /* Catenate the current scope to the supplied name */
25067754Smsmith
25167754Smsmith    Info->Pathname[0] = 0;
25267754Smsmith    if ((Info->Name[0] != '\\') &&
25367754Smsmith        (Info->Name[0] != '/'))
25467754Smsmith    {
255281075Sdim        if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname),
256281075Sdim            AcpiGbl_DbScopeBuf))
257281075Sdim        {
258281075Sdim            Status = AE_BUFFER_OVERFLOW;
259281075Sdim            goto ErrorExit;
260281075Sdim        }
26167754Smsmith    }
26267754Smsmith
263281075Sdim    if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname),
264281075Sdim        Info->Name))
265281075Sdim    {
266281075Sdim        Status = AE_BUFFER_OVERFLOW;
267281075Sdim        goto ErrorExit;
268281075Sdim    }
269281075Sdim
27067754Smsmith    AcpiDbPrepNamestring (Info->Pathname);
27167754Smsmith
27291116Smsmith    AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
273240716Sjkim    AcpiOsPrintf ("Evaluating %s\n", Info->Pathname);
27467754Smsmith
27567754Smsmith    if (Info->Flags & EX_SINGLE_STEP)
27667754Smsmith    {
27767754Smsmith        AcpiGbl_CmSingleStep = TRUE;
27891116Smsmith        AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
27967754Smsmith    }
28067754Smsmith
28167754Smsmith    else
28267754Smsmith    {
28367754Smsmith        /* No single step, allow redirection to a file */
28467754Smsmith
28591116Smsmith        AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT);
28667754Smsmith    }
287281075Sdim
288281075Sdim    return (AE_OK);
289281075Sdim
290281075SdimErrorExit:
291281075Sdim
292281075Sdim    ACPI_EXCEPTION ((AE_INFO, Status, "During setup for method execution"));
293281075Sdim    return (Status);
29467754Smsmith}
29567754Smsmith
29667754Smsmith
297151937Sjkim#ifdef ACPI_DBG_TRACK_ALLOCATIONS
298167802SjkimUINT32
299151937SjkimAcpiDbGetCacheInfo (
300151937Sjkim    ACPI_MEMORY_LIST        *Cache)
301151937Sjkim{
302151937Sjkim
303151937Sjkim    return (Cache->TotalAllocated - Cache->TotalFreed - Cache->CurrentDepth);
304151937Sjkim}
305151937Sjkim#endif
306151937Sjkim
30767754Smsmith/*******************************************************************************
30867754Smsmith *
30982367Smsmith * FUNCTION:    AcpiDbGetOutstandingAllocations
31082367Smsmith *
31182367Smsmith * PARAMETERS:  None
31282367Smsmith *
31382367Smsmith * RETURN:      Current global allocation count minus cache entries
31482367Smsmith *
31582367Smsmith * DESCRIPTION: Determine the current number of "outstanding" allocations --
31682367Smsmith *              those allocations that have not been freed and also are not
31782367Smsmith *              in one of the various object caches.
31882367Smsmith *
31982367Smsmith ******************************************************************************/
32082367Smsmith
321151937Sjkimstatic UINT32
32299679SiwasakiAcpiDbGetOutstandingAllocations (
32399679Siwasaki    void)
32482367Smsmith{
32582367Smsmith    UINT32                  Outstanding = 0;
32682367Smsmith
32782367Smsmith#ifdef ACPI_DBG_TRACK_ALLOCATIONS
32882367Smsmith
329151937Sjkim    Outstanding += AcpiDbGetCacheInfo (AcpiGbl_StateCache);
330151937Sjkim    Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeCache);
331151937Sjkim    Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeExtCache);
332151937Sjkim    Outstanding += AcpiDbGetCacheInfo (AcpiGbl_OperandCache);
33382367Smsmith#endif
33482367Smsmith
33582367Smsmith    return (Outstanding);
33682367Smsmith}
33782367Smsmith
33882367Smsmith
33982367Smsmith/*******************************************************************************
34082367Smsmith *
341114237Snjl * FUNCTION:    AcpiDbExecutionWalk
342114237Snjl *
343114237Snjl * PARAMETERS:  WALK_CALLBACK
344114237Snjl *
345114237Snjl * RETURN:      Status
346114237Snjl *
347241973Sjkim * DESCRIPTION: Execute a control method. Name is relative to the current
348114237Snjl *              scope.
349114237Snjl *
350114237Snjl ******************************************************************************/
351114237Snjl
352151937Sjkimstatic ACPI_STATUS
353114237SnjlAcpiDbExecutionWalk (
354114237Snjl    ACPI_HANDLE             ObjHandle,
355114237Snjl    UINT32                  NestingLevel,
356114237Snjl    void                    *Context,
357114237Snjl    void                    **ReturnValue)
358114237Snjl{
359114237Snjl    ACPI_OPERAND_OBJECT     *ObjDesc;
360114237Snjl    ACPI_NAMESPACE_NODE     *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
361114237Snjl    ACPI_BUFFER             ReturnObj;
362114237Snjl    ACPI_STATUS             Status;
363114237Snjl
364114237Snjl
365114237Snjl    ObjDesc = AcpiNsGetAttachedObject (Node);
366114237Snjl    if (ObjDesc->Method.ParamCount)
367114237Snjl    {
368114237Snjl        return (AE_OK);
369114237Snjl    }
370114237Snjl
371114237Snjl    ReturnObj.Pointer = NULL;
372114237Snjl    ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
373114237Snjl
374240716Sjkim    AcpiNsPrintNodePathname (Node, "Evaluating");
375114237Snjl
376114237Snjl    /* Do the actual method execution */
377114237Snjl
378114237Snjl    AcpiOsPrintf ("\n");
379114237Snjl    AcpiGbl_MethodExecuting = TRUE;
380114237Snjl
381114237Snjl    Status = AcpiEvaluateObject (Node, NULL, NULL, &ReturnObj);
382114237Snjl
383306536Sjkim    AcpiOsPrintf ("Evaluation of [%4.4s] returned %s\n",
384306536Sjkim        AcpiUtGetNodeName (Node),
385306536Sjkim        AcpiFormatException (Status));
386306536Sjkim
387114237Snjl    AcpiGbl_MethodExecuting = FALSE;
388114237Snjl    return (AE_OK);
389114237Snjl}
390114237Snjl
391114237Snjl
392114237Snjl/*******************************************************************************
393114237Snjl *
39467754Smsmith * FUNCTION:    AcpiDbExecute
39567754Smsmith *
39667754Smsmith * PARAMETERS:  Name                - Name of method to execute
39767754Smsmith *              Args                - Parameters to the method
398306536Sjkim *              Types               -
39967754Smsmith *              Flags               - single step/no single step
40067754Smsmith *
401151937Sjkim * RETURN:      None
40267754Smsmith *
403241973Sjkim * DESCRIPTION: Execute a control method. Name is relative to the current
40467754Smsmith *              scope.
40567754Smsmith *
40667754Smsmith ******************************************************************************/
40767754Smsmith
40867754Smsmithvoid
40967754SmsmithAcpiDbExecute (
410114237Snjl    char                    *Name,
411114237Snjl    char                    **Args,
412222544Sjkim    ACPI_OBJECT_TYPE        *Types,
41367754Smsmith    UINT32                  Flags)
41467754Smsmith{
41567754Smsmith    ACPI_STATUS             Status;
41669450Smsmith    ACPI_BUFFER             ReturnObj;
417167802Sjkim    char                    *NameString;
41869450Smsmith
419102550Siwasaki#ifdef ACPI_DEBUG_OUTPUT
42067754Smsmith    UINT32                  PreviousAllocations;
42167754Smsmith    UINT32                  Allocations;
422306536Sjkim#endif
42367754Smsmith
42467754Smsmith
425306536Sjkim    /*
426306536Sjkim     * Allow one execution to be performed by debugger or single step
427306536Sjkim     * execution will be dead locked by the interpreter mutexes.
428306536Sjkim     */
429306536Sjkim    if (AcpiGbl_MethodExecuting)
430306536Sjkim    {
431306536Sjkim        AcpiOsPrintf ("Only one debugger execution is allowed.\n");
432306536Sjkim        return;
433306536Sjkim    }
434306536Sjkim
435306536Sjkim#ifdef ACPI_DEBUG_OUTPUT
43667754Smsmith    /* Memory allocation tracking */
43767754Smsmith
43882367Smsmith    PreviousAllocations = AcpiDbGetOutstandingAllocations ();
43969450Smsmith#endif
44067754Smsmith
441114237Snjl    if (*Name == '*')
442114237Snjl    {
443151937Sjkim        (void) AcpiWalkNamespace (ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
444306536Sjkim            ACPI_UINT32_MAX, AcpiDbExecutionWalk, NULL, NULL, NULL);
445114237Snjl        return;
446114237Snjl    }
447114237Snjl    else
448114237Snjl    {
449306536Sjkim        NameString = ACPI_ALLOCATE (strlen (Name) + 1);
450167802Sjkim        if (!NameString)
451167802Sjkim        {
452167802Sjkim            return;
453167802Sjkim        }
454167802Sjkim
455306536Sjkim        memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
456167802Sjkim
457306536Sjkim        strcpy (NameString, Name);
458167802Sjkim        AcpiUtStrupr (NameString);
459167802Sjkim        AcpiGbl_DbMethodInfo.Name = NameString;
460114237Snjl        AcpiGbl_DbMethodInfo.Args = Args;
461222544Sjkim        AcpiGbl_DbMethodInfo.Types = Types;
462114237Snjl        AcpiGbl_DbMethodInfo.Flags = Flags;
46367754Smsmith
464114237Snjl        ReturnObj.Pointer = NULL;
465114237Snjl        ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
466100966Siwasaki
467281075Sdim        Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
468281075Sdim        if (ACPI_FAILURE (Status))
469281075Sdim        {
470281075Sdim            ACPI_FREE (NameString);
471281075Sdim            return;
472281075Sdim        }
473239340Sjkim
474239340Sjkim        /* Get the NS node, determines existence also */
475239340Sjkim
476239340Sjkim        Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
477239340Sjkim            &AcpiGbl_DbMethodInfo.Method);
478245582Sjkim        if (ACPI_SUCCESS (Status))
479239340Sjkim        {
480306536Sjkim            Status = AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo,
481306536Sjkim                &ReturnObj);
482239340Sjkim        }
483167802Sjkim        ACPI_FREE (NameString);
484114237Snjl    }
48567754Smsmith
48682367Smsmith    /*
48782367Smsmith     * Allow any handlers in separate threads to complete.
48882367Smsmith     * (Such as Notify handlers invoked from AML executed above).
48982367Smsmith     */
490202771Sjkim    AcpiOsSleep ((UINT64) 10);
49167754Smsmith
492102550Siwasaki#ifdef ACPI_DEBUG_OUTPUT
49369450Smsmith
49467754Smsmith    /* Memory allocation tracking */
49567754Smsmith
49682367Smsmith    Allocations = AcpiDbGetOutstandingAllocations () - PreviousAllocations;
49767754Smsmith
49891116Smsmith    AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
49967754Smsmith
50067754Smsmith    if (Allocations > 0)
50167754Smsmith    {
502306536Sjkim        AcpiOsPrintf (
503306536Sjkim            "0x%X Outstanding allocations after evaluation of %s\n",
504306536Sjkim            Allocations, AcpiGbl_DbMethodInfo.Pathname);
50567754Smsmith    }
50669450Smsmith#endif
50767754Smsmith
50867754Smsmith    if (ACPI_FAILURE (Status))
50967754Smsmith    {
510240716Sjkim        AcpiOsPrintf ("Evaluation of %s failed with status %s\n",
511306536Sjkim            AcpiGbl_DbMethodInfo.Pathname,
512306536Sjkim            AcpiFormatException (Status));
51367754Smsmith    }
51467754Smsmith    else
51567754Smsmith    {
51667754Smsmith        /* Display a return object, if any */
51767754Smsmith
51867754Smsmith        if (ReturnObj.Length)
51967754Smsmith        {
520240716Sjkim            AcpiOsPrintf (
521306536Sjkim                "Evaluation of %s returned object %p, "
522306536Sjkim                "external buffer length %X\n",
523114237Snjl                AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer,
524104470Siwasaki                (UINT32) ReturnObj.Length);
525306536Sjkim
526151937Sjkim            AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
527239340Sjkim
528239340Sjkim            /* Dump a _PLD buffer if present */
529239340Sjkim
530239340Sjkim            if (ACPI_COMPARE_NAME ((ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
531306536Sjkim                AcpiGbl_DbMethodInfo.Method)->Name.Ascii),
532306536Sjkim                METHOD_NAME__PLD))
533239340Sjkim            {
534239340Sjkim                AcpiDbDumpPldBuffer (ReturnObj.Pointer);
535239340Sjkim            }
53667754Smsmith        }
537100966Siwasaki        else
538100966Siwasaki        {
539240716Sjkim            AcpiOsPrintf ("No object was returned from evaluation of %s\n",
540100966Siwasaki                AcpiGbl_DbMethodInfo.Pathname);
541100966Siwasaki        }
54267754Smsmith    }
54367754Smsmith
54491116Smsmith    AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
54567754Smsmith}
54667754Smsmith
54767754Smsmith
54867754Smsmith/*******************************************************************************
54967754Smsmith *
55067754Smsmith * FUNCTION:    AcpiDbMethodThread
55167754Smsmith *
55267754Smsmith * PARAMETERS:  Context             - Execution info segment
55367754Smsmith *
55467754Smsmith * RETURN:      None
55567754Smsmith *
556241973Sjkim * DESCRIPTION: Debugger execute thread. Waits for a command line, then
55767754Smsmith *              simply dispatches it.
55867754Smsmith *
55967754Smsmith ******************************************************************************/
56067754Smsmith
561151937Sjkimstatic void ACPI_SYSTEM_XFACE
56267754SmsmithAcpiDbMethodThread (
56367754Smsmith    void                    *Context)
56467754Smsmith{
56567754Smsmith    ACPI_STATUS             Status;
56691116Smsmith    ACPI_DB_METHOD_INFO     *Info = Context;
567193267Sjkim    ACPI_DB_METHOD_INFO     LocalInfo;
56867754Smsmith    UINT32                  i;
569167802Sjkim    UINT8                   Allow;
57067754Smsmith    ACPI_BUFFER             ReturnObj;
57167754Smsmith
57267754Smsmith
573193267Sjkim    /*
574193267Sjkim     * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments.
575193267Sjkim     * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads
576193267Sjkim     * concurrently.
577193267Sjkim     *
578193267Sjkim     * Note: The arguments we are passing are used by the ASL test suite
579193267Sjkim     * (aslts). Do not change them without updating the tests.
580193267Sjkim     */
581193267Sjkim    (void) AcpiOsWaitSemaphore (Info->InfoGate, 1, ACPI_WAIT_FOREVER);
582193267Sjkim
583167802Sjkim    if (Info->InitArgs)
584167802Sjkim    {
585306536Sjkim        AcpiDbUint32ToHexString (Info->NumCreated,
586306536Sjkim            Info->IndexOfThreadStr);
587306536Sjkim        AcpiDbUint32ToHexString ((UINT32) AcpiOsGetThreadId (),
588306536Sjkim            Info->IdOfThreadStr);
589167802Sjkim    }
590167802Sjkim
591167802Sjkim    if (Info->Threads && (Info->NumCreated < Info->NumThreads))
592167802Sjkim    {
593212761Sjkim        Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId();
594167802Sjkim    }
595167802Sjkim
596193267Sjkim    LocalInfo = *Info;
597193267Sjkim    LocalInfo.Args = LocalInfo.Arguments;
598193267Sjkim    LocalInfo.Arguments[0] = LocalInfo.NumThreadsStr;
599193267Sjkim    LocalInfo.Arguments[1] = LocalInfo.IdOfThreadStr;
600193267Sjkim    LocalInfo.Arguments[2] = LocalInfo.IndexOfThreadStr;
601193267Sjkim    LocalInfo.Arguments[3] = NULL;
602193267Sjkim
603222544Sjkim    LocalInfo.Types = LocalInfo.ArgTypes;
604222544Sjkim
605193267Sjkim    (void) AcpiOsSignalSemaphore (Info->InfoGate, 1);
606193267Sjkim
60767754Smsmith    for (i = 0; i < Info->NumLoops; i++)
60867754Smsmith    {
609193267Sjkim        Status = AcpiDbExecuteMethod (&LocalInfo, &ReturnObj);
610117521Snjl        if (ACPI_FAILURE (Status))
61167754Smsmith        {
612240716Sjkim            AcpiOsPrintf ("%s During evaluation of %s at iteration %X\n",
613117521Snjl                AcpiFormatException (Status), Info->Pathname, i);
614127175Snjl            if (Status == AE_ABORT_METHOD)
615127175Snjl            {
616127175Snjl                break;
617127175Snjl            }
61867754Smsmith        }
619117521Snjl
620167802Sjkim#if 0
621128212Snjl        if ((i % 100) == 0)
622117521Snjl        {
623306536Sjkim            AcpiOsPrintf ("%u loops, Thread 0x%x\n",
624306536Sjkim                i, AcpiOsGetThreadId ());
625117521Snjl        }
626117521Snjl
627117521Snjl        if (ReturnObj.Length)
628117521Snjl        {
629240716Sjkim            AcpiOsPrintf ("Evaluation of %s returned object %p Buflen %X\n",
630306536Sjkim                Info->Pathname, ReturnObj.Pointer,
631306536Sjkim                (UINT32) ReturnObj.Length);
632151937Sjkim            AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
633117521Snjl        }
634117521Snjl#endif
63567754Smsmith    }
63667754Smsmith
63767754Smsmith    /* Signal our completion */
63867754Smsmith
639167802Sjkim    Allow = 0;
640306536Sjkim    (void) AcpiOsWaitSemaphore (Info->ThreadCompleteGate,
641306536Sjkim        1, ACPI_WAIT_FOREVER);
642167802Sjkim    Info->NumCompleted++;
643167802Sjkim
644167802Sjkim    if (Info->NumCompleted == Info->NumThreads)
64599679Siwasaki    {
646167802Sjkim        /* Do signal for main thread once only */
647167802Sjkim        Allow = 1;
64899679Siwasaki    }
649167802Sjkim
650193267Sjkim    (void) AcpiOsSignalSemaphore (Info->ThreadCompleteGate, 1);
651167802Sjkim
652167802Sjkim    if (Allow)
653167802Sjkim    {
654167802Sjkim        Status = AcpiOsSignalSemaphore (Info->MainThreadGate, 1);
655167802Sjkim        if (ACPI_FAILURE (Status))
656167802Sjkim        {
657306536Sjkim            AcpiOsPrintf (
658306536Sjkim                "Could not signal debugger thread sync semaphore, %s\n",
659167802Sjkim                AcpiFormatException (Status));
660167802Sjkim        }
661167802Sjkim    }
66267754Smsmith}
66367754Smsmith
66467754Smsmith
66567754Smsmith/*******************************************************************************
66667754Smsmith *
66767754Smsmith * FUNCTION:    AcpiDbCreateExecutionThreads
66867754Smsmith *
66967754Smsmith * PARAMETERS:  NumThreadsArg           - Number of threads to create
67067754Smsmith *              NumLoopsArg             - Loop count for the thread(s)
67167754Smsmith *              MethodNameArg           - Control method to execute
67267754Smsmith *
67367754Smsmith * RETURN:      None
67467754Smsmith *
67567754Smsmith * DESCRIPTION: Create threads to execute method(s)
67667754Smsmith *
67767754Smsmith ******************************************************************************/
67867754Smsmith
67967754Smsmithvoid
68067754SmsmithAcpiDbCreateExecutionThreads (
681114237Snjl    char                    *NumThreadsArg,
682114237Snjl    char                    *NumLoopsArg,
683114237Snjl    char                    *MethodNameArg)
68467754Smsmith{
68567754Smsmith    ACPI_STATUS             Status;
68667754Smsmith    UINT32                  NumThreads;
68767754Smsmith    UINT32                  NumLoops;
68867754Smsmith    UINT32                  i;
689167802Sjkim    UINT32                  Size;
690167802Sjkim    ACPI_MUTEX              MainThreadGate;
691167802Sjkim    ACPI_MUTEX              ThreadCompleteGate;
692193267Sjkim    ACPI_MUTEX              InfoGate;
69367754Smsmith
694193267Sjkim
69567754Smsmith    /* Get the arguments */
69667754Smsmith
697306536Sjkim    NumThreads = strtoul (NumThreadsArg, NULL, 0);
698306536Sjkim    NumLoops = strtoul (NumLoopsArg, NULL, 0);
69967754Smsmith
70067754Smsmith    if (!NumThreads || !NumLoops)
70167754Smsmith    {
702151937Sjkim        AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n",
703151937Sjkim            NumThreads, NumLoops);
70467754Smsmith        return;
70567754Smsmith    }
70667754Smsmith
707167802Sjkim    /*
708167802Sjkim     * Create the semaphore for synchronization of
709167802Sjkim     * the created threads with the main thread.
710167802Sjkim     */
711167802Sjkim    Status = AcpiOsCreateSemaphore (1, 0, &MainThreadGate);
712167802Sjkim    if (ACPI_FAILURE (Status))
713167802Sjkim    {
714306536Sjkim        AcpiOsPrintf ("Could not create semaphore for "
715306536Sjkim            "synchronization with the main thread, %s\n",
716167802Sjkim            AcpiFormatException (Status));
717167802Sjkim        return;
718167802Sjkim    }
71967754Smsmith
720167802Sjkim    /*
721167802Sjkim     * Create the semaphore for synchronization
722167802Sjkim     * between the created threads.
723167802Sjkim     */
724167802Sjkim    Status = AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate);
72567754Smsmith    if (ACPI_FAILURE (Status))
72667754Smsmith    {
727306536Sjkim        AcpiOsPrintf ("Could not create semaphore for "
728306536Sjkim            "synchronization between the created threads, %s\n",
729151937Sjkim            AcpiFormatException (Status));
730306536Sjkim
731167802Sjkim        (void) AcpiOsDeleteSemaphore (MainThreadGate);
73267754Smsmith        return;
73367754Smsmith    }
73467754Smsmith
735193267Sjkim    Status = AcpiOsCreateSemaphore (1, 1, &InfoGate);
736193267Sjkim    if (ACPI_FAILURE (Status))
737193267Sjkim    {
738306536Sjkim        AcpiOsPrintf ("Could not create semaphore for "
739306536Sjkim            "synchronization of AcpiGbl_DbMethodInfo, %s\n",
740193267Sjkim            AcpiFormatException (Status));
741306536Sjkim
742193267Sjkim        (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
743193267Sjkim        (void) AcpiOsDeleteSemaphore (MainThreadGate);
744193267Sjkim        return;
745193267Sjkim    }
746193267Sjkim
747306536Sjkim    memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
748167802Sjkim
749167802Sjkim    /* Array to store IDs of threads */
750167802Sjkim
751167802Sjkim    AcpiGbl_DbMethodInfo.NumThreads = NumThreads;
752212761Sjkim    Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads;
753306536Sjkim
754212761Sjkim    AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size);
755167802Sjkim    if (AcpiGbl_DbMethodInfo.Threads == NULL)
756167802Sjkim    {
757167802Sjkim        AcpiOsPrintf ("No memory for thread IDs array\n");
758167802Sjkim        (void) AcpiOsDeleteSemaphore (MainThreadGate);
759167802Sjkim        (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
760193267Sjkim        (void) AcpiOsDeleteSemaphore (InfoGate);
761167802Sjkim        return;
762167802Sjkim    }
763306536Sjkim    memset (AcpiGbl_DbMethodInfo.Threads, 0, Size);
764167802Sjkim
76567754Smsmith    /* Setup the context to be passed to each thread */
76667754Smsmith
76783174Smsmith    AcpiGbl_DbMethodInfo.Name = MethodNameArg;
76883174Smsmith    AcpiGbl_DbMethodInfo.Flags = 0;
76983174Smsmith    AcpiGbl_DbMethodInfo.NumLoops = NumLoops;
770167802Sjkim    AcpiGbl_DbMethodInfo.MainThreadGate = MainThreadGate;
771167802Sjkim    AcpiGbl_DbMethodInfo.ThreadCompleteGate = ThreadCompleteGate;
772193267Sjkim    AcpiGbl_DbMethodInfo.InfoGate = InfoGate;
77367754Smsmith
774167802Sjkim    /* Init arguments to be passed to method */
775167802Sjkim
776167802Sjkim    AcpiGbl_DbMethodInfo.InitArgs = 1;
777167802Sjkim    AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments;
778167802Sjkim    AcpiGbl_DbMethodInfo.Arguments[0] = AcpiGbl_DbMethodInfo.NumThreadsStr;
779167802Sjkim    AcpiGbl_DbMethodInfo.Arguments[1] = AcpiGbl_DbMethodInfo.IdOfThreadStr;
780167802Sjkim    AcpiGbl_DbMethodInfo.Arguments[2] = AcpiGbl_DbMethodInfo.IndexOfThreadStr;
781167802Sjkim    AcpiGbl_DbMethodInfo.Arguments[3] = NULL;
782222544Sjkim
783222544Sjkim    AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes;
784222544Sjkim    AcpiGbl_DbMethodInfo.ArgTypes[0] = ACPI_TYPE_INTEGER;
785222544Sjkim    AcpiGbl_DbMethodInfo.ArgTypes[1] = ACPI_TYPE_INTEGER;
786222544Sjkim    AcpiGbl_DbMethodInfo.ArgTypes[2] = ACPI_TYPE_INTEGER;
787222544Sjkim
788237412Sjkim    AcpiDbUint32ToHexString (NumThreads, AcpiGbl_DbMethodInfo.NumThreadsStr);
789167802Sjkim
790281075Sdim    Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
791281075Sdim    if (ACPI_FAILURE (Status))
792281075Sdim    {
793281075Sdim        goto CleanupAndExit;
794281075Sdim    }
79567754Smsmith
796239340Sjkim    /* Get the NS node, determines existence also */
797239340Sjkim
798239340Sjkim    Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
799239340Sjkim        &AcpiGbl_DbMethodInfo.Method);
800239340Sjkim    if (ACPI_FAILURE (Status))
801239340Sjkim    {
802239340Sjkim        AcpiOsPrintf ("%s Could not get handle for %s\n",
803239340Sjkim            AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname);
804239340Sjkim        goto CleanupAndExit;
805239340Sjkim    }
806239340Sjkim
80767754Smsmith    /* Create the threads */
80867754Smsmith
809151937Sjkim    AcpiOsPrintf ("Creating %X threads to execute %X times each\n",
810151937Sjkim        NumThreads, NumLoops);
81167754Smsmith
81267754Smsmith    for (i = 0; i < (NumThreads); i++)
81367754Smsmith    {
814306536Sjkim        Status = AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD, AcpiDbMethodThread,
815151937Sjkim            &AcpiGbl_DbMethodInfo);
81699679Siwasaki        if (ACPI_FAILURE (Status))
81799679Siwasaki        {
81899679Siwasaki            break;
81999679Siwasaki        }
82067754Smsmith    }
82167754Smsmith
82267754Smsmith    /* Wait for all threads to complete */
82367754Smsmith
824193267Sjkim    (void) AcpiOsWaitSemaphore (MainThreadGate, 1, ACPI_WAIT_FOREVER);
82567754Smsmith
826167802Sjkim    AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
827167802Sjkim    AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads);
828167802Sjkim    AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
829167802Sjkim
830239340SjkimCleanupAndExit:
831239340Sjkim
83267754Smsmith    /* Cleanup and exit */
83367754Smsmith
834167802Sjkim    (void) AcpiOsDeleteSemaphore (MainThreadGate);
835167802Sjkim    (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
836193267Sjkim    (void) AcpiOsDeleteSemaphore (InfoGate);
83767754Smsmith
838167802Sjkim    AcpiOsFree (AcpiGbl_DbMethodInfo.Threads);
839167802Sjkim    AcpiGbl_DbMethodInfo.Threads = NULL;
84067754Smsmith}
841