167754Smsmith/*******************************************************************************
267754Smsmith *
367754Smsmith * Module Name: dbexec - debugger control method execution
467754Smsmith *
567754Smsmith ******************************************************************************/
667754Smsmith
7217365Sjkim/*
8245582Sjkim * Copyright (C) 2000 - 2013, 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
4467754Smsmith
45193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
46193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
47193341Sjkim#include <contrib/dev/acpica/include/acdebug.h>
48193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
4967754Smsmith
50102550Siwasaki#ifdef ACPI_DEBUGGER
5167754Smsmith
52102550Siwasaki#define _COMPONENT          ACPI_CA_DEBUGGER
5391116Smsmith        ACPI_MODULE_NAME    ("dbexec")
5467754Smsmith
5567754Smsmith
56222544Sjkimstatic ACPI_DB_METHOD_INFO          AcpiGbl_DbMethodInfo;
5767754Smsmith
58151937Sjkim/* Local prototypes */
5967754Smsmith
60151937Sjkimstatic ACPI_STATUS
61151937SjkimAcpiDbExecuteMethod (
62151937Sjkim    ACPI_DB_METHOD_INFO     *Info,
63151937Sjkim    ACPI_BUFFER             *ReturnObj);
64151937Sjkim
65151937Sjkimstatic void
66151937SjkimAcpiDbExecuteSetup (
67151937Sjkim    ACPI_DB_METHOD_INFO     *Info);
68151937Sjkim
69151937Sjkimstatic UINT32
70151937SjkimAcpiDbGetOutstandingAllocations (
71151937Sjkim    void);
72151937Sjkim
73151937Sjkimstatic void ACPI_SYSTEM_XFACE
74151937SjkimAcpiDbMethodThread (
75151937Sjkim    void                    *Context);
76151937Sjkim
77151937Sjkimstatic ACPI_STATUS
78151937SjkimAcpiDbExecutionWalk (
79151937Sjkim    ACPI_HANDLE             ObjHandle,
80151937Sjkim    UINT32                  NestingLevel,
81151937Sjkim    void                    *Context,
82151937Sjkim    void                    **ReturnValue);
83151937Sjkim
84151937Sjkim
8567754Smsmith/*******************************************************************************
8667754Smsmith *
87222544Sjkim * FUNCTION:    AcpiDbDeleteObjects
88222544Sjkim *
89222544Sjkim * PARAMETERS:  Count               - Count of objects in the list
90222544Sjkim *              Objects             - Array of ACPI_OBJECTs to be deleted
91222544Sjkim *
92222544Sjkim * RETURN:      None
93222544Sjkim *
94222544Sjkim * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
95222544Sjkim *              packages via recursion.
96222544Sjkim *
97222544Sjkim ******************************************************************************/
98222544Sjkim
99245582Sjkimvoid
100222544SjkimAcpiDbDeleteObjects (
101222544Sjkim    UINT32                  Count,
102222544Sjkim    ACPI_OBJECT             *Objects)
103222544Sjkim{
104222544Sjkim    UINT32                  i;
105222544Sjkim
106222544Sjkim
107222544Sjkim    for (i = 0; i < Count; i++)
108222544Sjkim    {
109222544Sjkim        switch (Objects[i].Type)
110222544Sjkim        {
111222544Sjkim        case ACPI_TYPE_BUFFER:
112250838Sjkim
113222544Sjkim            ACPI_FREE (Objects[i].Buffer.Pointer);
114222544Sjkim            break;
115222544Sjkim
116222544Sjkim        case ACPI_TYPE_PACKAGE:
117222544Sjkim
118222544Sjkim            /* Recursive call to delete package elements */
119222544Sjkim
120222544Sjkim            AcpiDbDeleteObjects (Objects[i].Package.Count,
121222544Sjkim                Objects[i].Package.Elements);
122222544Sjkim
123222544Sjkim            /* Free the elements array */
124222544Sjkim
125222544Sjkim            ACPI_FREE (Objects[i].Package.Elements);
126222544Sjkim            break;
127222544Sjkim
128222544Sjkim        default:
129250838Sjkim
130222544Sjkim            break;
131222544Sjkim        }
132222544Sjkim    }
133222544Sjkim}
134222544Sjkim
135222544Sjkim
136222544Sjkim/*******************************************************************************
137222544Sjkim *
13867754Smsmith * FUNCTION:    AcpiDbExecuteMethod
13967754Smsmith *
14067754Smsmith * PARAMETERS:  Info            - Valid info segment
14167754Smsmith *              ReturnObj       - Where to put return object
14267754Smsmith *
14367754Smsmith * RETURN:      Status
14467754Smsmith *
14567754Smsmith * DESCRIPTION: Execute a control method.
14667754Smsmith *
14767754Smsmith ******************************************************************************/
14867754Smsmith
149151937Sjkimstatic ACPI_STATUS
15067754SmsmithAcpiDbExecuteMethod (
15191116Smsmith    ACPI_DB_METHOD_INFO     *Info,
15267754Smsmith    ACPI_BUFFER             *ReturnObj)
15367754Smsmith{
15467754Smsmith    ACPI_STATUS             Status;
15567754Smsmith    ACPI_OBJECT_LIST        ParamObjects;
156249663Sjkim    ACPI_OBJECT             Params[ACPI_DEBUGGER_MAX_ARGS + 1];
15767754Smsmith    UINT32                  i;
15867754Smsmith
15967754Smsmith
160216471Sjkim    ACPI_FUNCTION_TRACE (DbExecuteMethod);
161216471Sjkim
162216471Sjkim
16383174Smsmith    if (AcpiGbl_DbOutputToFile && !AcpiDbgLevel)
16467754Smsmith    {
16567754Smsmith        AcpiOsPrintf ("Warning: debug output is not enabled!\n");
16667754Smsmith    }
16767754Smsmith
168249663Sjkim    ParamObjects.Count = 0;
169249663Sjkim    ParamObjects.Pointer = NULL;
170193267Sjkim
171249663Sjkim    /* Pass through any command-line arguments */
172193267Sjkim
173249663Sjkim    if (Info->Args && Info->Args[0])
17467754Smsmith    {
175249663Sjkim        /* Get arguments passed on the command line */
17667754Smsmith
177249663Sjkim        for (i = 0; (Info->Args[i] && *(Info->Args[i])); i++)
178193267Sjkim        {
179249663Sjkim            /* Convert input string (token) to an actual ACPI_OBJECT */
180222544Sjkim
181249663Sjkim            Status = AcpiDbConvertToObject (Info->Types[i],
182249663Sjkim                Info->Args[i], &Params[i]);
183249663Sjkim            if (ACPI_FAILURE (Status))
184193267Sjkim            {
185249663Sjkim                ACPI_EXCEPTION ((AE_INFO, Status,
186249663Sjkim                    "While parsing method arguments"));
187249663Sjkim                goto Cleanup;
188193267Sjkim            }
189222544Sjkim        }
19067754Smsmith
191249663Sjkim        ParamObjects.Count = i;
192222544Sjkim        ParamObjects.Pointer = Params;
19367754Smsmith    }
19467754Smsmith
19567754Smsmith    /* Prepare for a return object of arbitrary size */
19667754Smsmith
197151937Sjkim    ReturnObj->Pointer = AcpiGbl_DbBuffer;
198151937Sjkim    ReturnObj->Length  = ACPI_DEBUG_BUFFER_SIZE;
19967754Smsmith
20067754Smsmith    /* Do the actual method execution */
20167754Smsmith
202114237Snjl    AcpiGbl_MethodExecuting = TRUE;
203249663Sjkim    Status = AcpiEvaluateObject (NULL, Info->Pathname,
204249663Sjkim        &ParamObjects, ReturnObj);
20567754Smsmith
20667754Smsmith    AcpiGbl_CmSingleStep = FALSE;
20767754Smsmith    AcpiGbl_MethodExecuting = FALSE;
20867754Smsmith
209216471Sjkim    if (ACPI_FAILURE (Status))
210216471Sjkim    {
211216471Sjkim        ACPI_EXCEPTION ((AE_INFO, Status,
212222544Sjkim            "while executing %s from debugger", Info->Pathname));
213216471Sjkim
214216471Sjkim        if (Status == AE_BUFFER_OVERFLOW)
215216471Sjkim        {
216216471Sjkim            ACPI_ERROR ((AE_INFO,
217222544Sjkim                "Possible overflow of internal debugger buffer (size 0x%X needed 0x%X)",
218216471Sjkim                ACPI_DEBUG_BUFFER_SIZE, (UINT32) ReturnObj->Length));
219216471Sjkim        }
220216471Sjkim    }
221216471Sjkim
222222544SjkimCleanup:
223249663Sjkim    AcpiDbDeleteObjects (ParamObjects.Count, Params);
224216471Sjkim    return_ACPI_STATUS (Status);
22567754Smsmith}
22667754Smsmith
22767754Smsmith
22867754Smsmith/*******************************************************************************
22967754Smsmith *
23067754Smsmith * FUNCTION:    AcpiDbExecuteSetup
23167754Smsmith *
23267754Smsmith * PARAMETERS:  Info            - Valid method info
23367754Smsmith *
234151937Sjkim * RETURN:      None
23567754Smsmith *
23667754Smsmith * DESCRIPTION: Setup info segment prior to method execution
23767754Smsmith *
23867754Smsmith ******************************************************************************/
23967754Smsmith
240151937Sjkimstatic void
24167754SmsmithAcpiDbExecuteSetup (
24299679Siwasaki    ACPI_DB_METHOD_INFO     *Info)
24367754Smsmith{
24467754Smsmith
24567754Smsmith    /* Catenate the current scope to the supplied name */
24667754Smsmith
24767754Smsmith    Info->Pathname[0] = 0;
24867754Smsmith    if ((Info->Name[0] != '\\') &&
24967754Smsmith        (Info->Name[0] != '/'))
25067754Smsmith    {
25191116Smsmith        ACPI_STRCAT (Info->Pathname, AcpiGbl_DbScopeBuf);
25267754Smsmith    }
25367754Smsmith
25491116Smsmith    ACPI_STRCAT (Info->Pathname, Info->Name);
25567754Smsmith    AcpiDbPrepNamestring (Info->Pathname);
25667754Smsmith
25791116Smsmith    AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
258240716Sjkim    AcpiOsPrintf ("Evaluating %s\n", Info->Pathname);
25967754Smsmith
26067754Smsmith    if (Info->Flags & EX_SINGLE_STEP)
26167754Smsmith    {
26267754Smsmith        AcpiGbl_CmSingleStep = TRUE;
26391116Smsmith        AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
26467754Smsmith    }
26567754Smsmith
26667754Smsmith    else
26767754Smsmith    {
26867754Smsmith        /* No single step, allow redirection to a file */
26967754Smsmith
27091116Smsmith        AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT);
27167754Smsmith    }
27267754Smsmith}
27367754Smsmith
27467754Smsmith
275151937Sjkim#ifdef ACPI_DBG_TRACK_ALLOCATIONS
276167802SjkimUINT32
277151937SjkimAcpiDbGetCacheInfo (
278151937Sjkim    ACPI_MEMORY_LIST        *Cache)
279151937Sjkim{
280151937Sjkim
281151937Sjkim    return (Cache->TotalAllocated - Cache->TotalFreed - Cache->CurrentDepth);
282151937Sjkim}
283151937Sjkim#endif
284151937Sjkim
28567754Smsmith/*******************************************************************************
28667754Smsmith *
28782367Smsmith * FUNCTION:    AcpiDbGetOutstandingAllocations
28882367Smsmith *
28982367Smsmith * PARAMETERS:  None
29082367Smsmith *
29182367Smsmith * RETURN:      Current global allocation count minus cache entries
29282367Smsmith *
29382367Smsmith * DESCRIPTION: Determine the current number of "outstanding" allocations --
29482367Smsmith *              those allocations that have not been freed and also are not
29582367Smsmith *              in one of the various object caches.
29682367Smsmith *
29782367Smsmith ******************************************************************************/
29882367Smsmith
299151937Sjkimstatic UINT32
30099679SiwasakiAcpiDbGetOutstandingAllocations (
30199679Siwasaki    void)
30282367Smsmith{
30382367Smsmith    UINT32                  Outstanding = 0;
30482367Smsmith
30582367Smsmith#ifdef ACPI_DBG_TRACK_ALLOCATIONS
30682367Smsmith
307151937Sjkim    Outstanding += AcpiDbGetCacheInfo (AcpiGbl_StateCache);
308151937Sjkim    Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeCache);
309151937Sjkim    Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeExtCache);
310151937Sjkim    Outstanding += AcpiDbGetCacheInfo (AcpiGbl_OperandCache);
31182367Smsmith#endif
31282367Smsmith
31382367Smsmith    return (Outstanding);
31482367Smsmith}
31582367Smsmith
31682367Smsmith
31782367Smsmith/*******************************************************************************
31882367Smsmith *
319114237Snjl * FUNCTION:    AcpiDbExecutionWalk
320114237Snjl *
321114237Snjl * PARAMETERS:  WALK_CALLBACK
322114237Snjl *
323114237Snjl * RETURN:      Status
324114237Snjl *
325241973Sjkim * DESCRIPTION: Execute a control method. Name is relative to the current
326114237Snjl *              scope.
327114237Snjl *
328114237Snjl ******************************************************************************/
329114237Snjl
330151937Sjkimstatic ACPI_STATUS
331114237SnjlAcpiDbExecutionWalk (
332114237Snjl    ACPI_HANDLE             ObjHandle,
333114237Snjl    UINT32                  NestingLevel,
334114237Snjl    void                    *Context,
335114237Snjl    void                    **ReturnValue)
336114237Snjl{
337114237Snjl    ACPI_OPERAND_OBJECT     *ObjDesc;
338114237Snjl    ACPI_NAMESPACE_NODE     *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
339114237Snjl    ACPI_BUFFER             ReturnObj;
340114237Snjl    ACPI_STATUS             Status;
341114237Snjl
342114237Snjl
343114237Snjl    ObjDesc = AcpiNsGetAttachedObject (Node);
344114237Snjl    if (ObjDesc->Method.ParamCount)
345114237Snjl    {
346114237Snjl        return (AE_OK);
347114237Snjl    }
348114237Snjl
349114237Snjl    ReturnObj.Pointer = NULL;
350114237Snjl    ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
351114237Snjl
352240716Sjkim    AcpiNsPrintNodePathname (Node, "Evaluating");
353114237Snjl
354114237Snjl    /* Do the actual method execution */
355114237Snjl
356114237Snjl    AcpiOsPrintf ("\n");
357114237Snjl    AcpiGbl_MethodExecuting = TRUE;
358114237Snjl
359114237Snjl    Status = AcpiEvaluateObject (Node, NULL, NULL, &ReturnObj);
360114237Snjl
361240716Sjkim    AcpiOsPrintf ("Evaluation of [%4.4s] returned %s\n", AcpiUtGetNodeName (Node),
362123315Snjl            AcpiFormatException (Status));
363114237Snjl    AcpiGbl_MethodExecuting = FALSE;
364114237Snjl
365114237Snjl    return (AE_OK);
366114237Snjl}
367114237Snjl
368114237Snjl
369114237Snjl/*******************************************************************************
370114237Snjl *
37167754Smsmith * FUNCTION:    AcpiDbExecute
37267754Smsmith *
37367754Smsmith * PARAMETERS:  Name                - Name of method to execute
37467754Smsmith *              Args                - Parameters to the method
37567754Smsmith *              Flags               - single step/no single step
37667754Smsmith *
377151937Sjkim * RETURN:      None
37867754Smsmith *
379241973Sjkim * DESCRIPTION: Execute a control method. Name is relative to the current
38067754Smsmith *              scope.
38167754Smsmith *
38267754Smsmith ******************************************************************************/
38367754Smsmith
38467754Smsmithvoid
38567754SmsmithAcpiDbExecute (
386114237Snjl    char                    *Name,
387114237Snjl    char                    **Args,
388222544Sjkim    ACPI_OBJECT_TYPE        *Types,
38967754Smsmith    UINT32                  Flags)
39067754Smsmith{
39167754Smsmith    ACPI_STATUS             Status;
39269450Smsmith    ACPI_BUFFER             ReturnObj;
393167802Sjkim    char                    *NameString;
39469450Smsmith
39569450Smsmith
396102550Siwasaki#ifdef ACPI_DEBUG_OUTPUT
39767754Smsmith    UINT32                  PreviousAllocations;
39867754Smsmith    UINT32                  Allocations;
39967754Smsmith
40067754Smsmith
40167754Smsmith    /* Memory allocation tracking */
40267754Smsmith
40382367Smsmith    PreviousAllocations = AcpiDbGetOutstandingAllocations ();
40469450Smsmith#endif
40567754Smsmith
406114237Snjl    if (*Name == '*')
407114237Snjl    {
408151937Sjkim        (void) AcpiWalkNamespace (ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
409199337Sjkim                    ACPI_UINT32_MAX, AcpiDbExecutionWalk, NULL, NULL, NULL);
410114237Snjl        return;
411114237Snjl    }
412114237Snjl    else
413114237Snjl    {
414167802Sjkim        NameString = ACPI_ALLOCATE (ACPI_STRLEN (Name) + 1);
415167802Sjkim        if (!NameString)
416167802Sjkim        {
417167802Sjkim            return;
418167802Sjkim        }
419167802Sjkim
420167802Sjkim        ACPI_MEMSET (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
421167802Sjkim
422167802Sjkim        ACPI_STRCPY (NameString, Name);
423167802Sjkim        AcpiUtStrupr (NameString);
424167802Sjkim        AcpiGbl_DbMethodInfo.Name = NameString;
425114237Snjl        AcpiGbl_DbMethodInfo.Args = Args;
426222544Sjkim        AcpiGbl_DbMethodInfo.Types = Types;
427114237Snjl        AcpiGbl_DbMethodInfo.Flags = Flags;
42867754Smsmith
429114237Snjl        ReturnObj.Pointer = NULL;
430114237Snjl        ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
431100966Siwasaki
432114237Snjl        AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
433239340Sjkim
434239340Sjkim        /* Get the NS node, determines existence also */
435239340Sjkim
436239340Sjkim        Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
437239340Sjkim            &AcpiGbl_DbMethodInfo.Method);
438245582Sjkim        if (ACPI_SUCCESS (Status))
439239340Sjkim        {
440245582Sjkim            Status = AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo, &ReturnObj);
441239340Sjkim        }
442167802Sjkim        ACPI_FREE (NameString);
443114237Snjl    }
44467754Smsmith
44582367Smsmith    /*
44682367Smsmith     * Allow any handlers in separate threads to complete.
44782367Smsmith     * (Such as Notify handlers invoked from AML executed above).
44882367Smsmith     */
449202771Sjkim    AcpiOsSleep ((UINT64) 10);
45067754Smsmith
451102550Siwasaki#ifdef ACPI_DEBUG_OUTPUT
45269450Smsmith
45367754Smsmith    /* Memory allocation tracking */
45467754Smsmith
45582367Smsmith    Allocations = AcpiDbGetOutstandingAllocations () - PreviousAllocations;
45667754Smsmith
45791116Smsmith    AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
45867754Smsmith
45967754Smsmith    if (Allocations > 0)
46067754Smsmith    {
461240716Sjkim        AcpiOsPrintf ("0x%X Outstanding allocations after evaluation of %s\n",
462240716Sjkim                        Allocations, AcpiGbl_DbMethodInfo.Pathname);
46367754Smsmith    }
46469450Smsmith#endif
46567754Smsmith
46667754Smsmith    if (ACPI_FAILURE (Status))
46767754Smsmith    {
468240716Sjkim        AcpiOsPrintf ("Evaluation of %s failed with status %s\n",
46983174Smsmith            AcpiGbl_DbMethodInfo.Pathname, AcpiFormatException (Status));
47067754Smsmith    }
47167754Smsmith    else
47267754Smsmith    {
47367754Smsmith        /* Display a return object, if any */
47467754Smsmith
47567754Smsmith        if (ReturnObj.Length)
47667754Smsmith        {
477240716Sjkim            AcpiOsPrintf (
478240716Sjkim                "Evaluation of %s returned object %p, external buffer length %X\n",
479114237Snjl                AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer,
480104470Siwasaki                (UINT32) ReturnObj.Length);
481151937Sjkim            AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
482239340Sjkim
483239340Sjkim            /* Dump a _PLD buffer if present */
484239340Sjkim
485239340Sjkim            if (ACPI_COMPARE_NAME ((ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
486239340Sjkim                    AcpiGbl_DbMethodInfo.Method)->Name.Ascii), METHOD_NAME__PLD))
487239340Sjkim            {
488239340Sjkim                AcpiDbDumpPldBuffer (ReturnObj.Pointer);
489239340Sjkim            }
49067754Smsmith        }
491100966Siwasaki        else
492100966Siwasaki        {
493240716Sjkim            AcpiOsPrintf ("No object was returned from evaluation of %s\n",
494100966Siwasaki                AcpiGbl_DbMethodInfo.Pathname);
495100966Siwasaki        }
49667754Smsmith    }
49767754Smsmith
49891116Smsmith    AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
49967754Smsmith}
50067754Smsmith
50167754Smsmith
50267754Smsmith/*******************************************************************************
50367754Smsmith *
50467754Smsmith * FUNCTION:    AcpiDbMethodThread
50567754Smsmith *
50667754Smsmith * PARAMETERS:  Context             - Execution info segment
50767754Smsmith *
50867754Smsmith * RETURN:      None
50967754Smsmith *
510241973Sjkim * DESCRIPTION: Debugger execute thread. Waits for a command line, then
51167754Smsmith *              simply dispatches it.
51267754Smsmith *
51367754Smsmith ******************************************************************************/
51467754Smsmith
515151937Sjkimstatic void ACPI_SYSTEM_XFACE
51667754SmsmithAcpiDbMethodThread (
51767754Smsmith    void                    *Context)
51867754Smsmith{
51967754Smsmith    ACPI_STATUS             Status;
52091116Smsmith    ACPI_DB_METHOD_INFO     *Info = Context;
521193267Sjkim    ACPI_DB_METHOD_INFO     LocalInfo;
52267754Smsmith    UINT32                  i;
523167802Sjkim    UINT8                   Allow;
52467754Smsmith    ACPI_BUFFER             ReturnObj;
52567754Smsmith
52667754Smsmith
527193267Sjkim    /*
528193267Sjkim     * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments.
529193267Sjkim     * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads
530193267Sjkim     * concurrently.
531193267Sjkim     *
532193267Sjkim     * Note: The arguments we are passing are used by the ASL test suite
533193267Sjkim     * (aslts). Do not change them without updating the tests.
534193267Sjkim     */
535193267Sjkim    (void) AcpiOsWaitSemaphore (Info->InfoGate, 1, ACPI_WAIT_FOREVER);
536193267Sjkim
537167802Sjkim    if (Info->InitArgs)
538167802Sjkim    {
539237412Sjkim        AcpiDbUint32ToHexString (Info->NumCreated, Info->IndexOfThreadStr);
540237412Sjkim        AcpiDbUint32ToHexString ((UINT32) AcpiOsGetThreadId (), Info->IdOfThreadStr);
541167802Sjkim    }
542167802Sjkim
543167802Sjkim    if (Info->Threads && (Info->NumCreated < Info->NumThreads))
544167802Sjkim    {
545212761Sjkim        Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId();
546167802Sjkim    }
547167802Sjkim
548193267Sjkim    LocalInfo = *Info;
549193267Sjkim    LocalInfo.Args = LocalInfo.Arguments;
550193267Sjkim    LocalInfo.Arguments[0] = LocalInfo.NumThreadsStr;
551193267Sjkim    LocalInfo.Arguments[1] = LocalInfo.IdOfThreadStr;
552193267Sjkim    LocalInfo.Arguments[2] = LocalInfo.IndexOfThreadStr;
553193267Sjkim    LocalInfo.Arguments[3] = NULL;
554193267Sjkim
555222544Sjkim    LocalInfo.Types = LocalInfo.ArgTypes;
556222544Sjkim
557193267Sjkim    (void) AcpiOsSignalSemaphore (Info->InfoGate, 1);
558193267Sjkim
55967754Smsmith    for (i = 0; i < Info->NumLoops; i++)
56067754Smsmith    {
561193267Sjkim        Status = AcpiDbExecuteMethod (&LocalInfo, &ReturnObj);
562117521Snjl        if (ACPI_FAILURE (Status))
56367754Smsmith        {
564240716Sjkim            AcpiOsPrintf ("%s During evaluation of %s at iteration %X\n",
565117521Snjl                AcpiFormatException (Status), Info->Pathname, i);
566127175Snjl            if (Status == AE_ABORT_METHOD)
567127175Snjl            {
568127175Snjl                break;
569127175Snjl            }
57067754Smsmith        }
571117521Snjl
572167802Sjkim#if 0
573128212Snjl        if ((i % 100) == 0)
574117521Snjl        {
575240716Sjkim            AcpiOsPrintf ("%u loops, Thread 0x%x\n", i, AcpiOsGetThreadId ());
576117521Snjl        }
577117521Snjl
578117521Snjl        if (ReturnObj.Length)
579117521Snjl        {
580240716Sjkim            AcpiOsPrintf ("Evaluation of %s returned object %p Buflen %X\n",
581117521Snjl                Info->Pathname, ReturnObj.Pointer, (UINT32) ReturnObj.Length);
582151937Sjkim            AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
583117521Snjl        }
584117521Snjl#endif
58567754Smsmith    }
58667754Smsmith
58767754Smsmith    /* Signal our completion */
58867754Smsmith
589167802Sjkim    Allow = 0;
590193267Sjkim    (void) AcpiOsWaitSemaphore (Info->ThreadCompleteGate, 1, ACPI_WAIT_FOREVER);
591167802Sjkim    Info->NumCompleted++;
592167802Sjkim
593167802Sjkim    if (Info->NumCompleted == Info->NumThreads)
59499679Siwasaki    {
595167802Sjkim        /* Do signal for main thread once only */
596167802Sjkim        Allow = 1;
59799679Siwasaki    }
598167802Sjkim
599193267Sjkim    (void) AcpiOsSignalSemaphore (Info->ThreadCompleteGate, 1);
600167802Sjkim
601167802Sjkim    if (Allow)
602167802Sjkim    {
603167802Sjkim        Status = AcpiOsSignalSemaphore (Info->MainThreadGate, 1);
604167802Sjkim        if (ACPI_FAILURE (Status))
605167802Sjkim        {
606167802Sjkim            AcpiOsPrintf ("Could not signal debugger thread sync semaphore, %s\n",
607167802Sjkim                AcpiFormatException (Status));
608167802Sjkim        }
609167802Sjkim    }
61067754Smsmith}
61167754Smsmith
61267754Smsmith
61367754Smsmith/*******************************************************************************
61467754Smsmith *
61567754Smsmith * FUNCTION:    AcpiDbCreateExecutionThreads
61667754Smsmith *
61767754Smsmith * PARAMETERS:  NumThreadsArg           - Number of threads to create
61867754Smsmith *              NumLoopsArg             - Loop count for the thread(s)
61967754Smsmith *              MethodNameArg           - Control method to execute
62067754Smsmith *
62167754Smsmith * RETURN:      None
62267754Smsmith *
62367754Smsmith * DESCRIPTION: Create threads to execute method(s)
62467754Smsmith *
62567754Smsmith ******************************************************************************/
62667754Smsmith
62767754Smsmithvoid
62867754SmsmithAcpiDbCreateExecutionThreads (
629114237Snjl    char                    *NumThreadsArg,
630114237Snjl    char                    *NumLoopsArg,
631114237Snjl    char                    *MethodNameArg)
63267754Smsmith{
63367754Smsmith    ACPI_STATUS             Status;
63467754Smsmith    UINT32                  NumThreads;
63567754Smsmith    UINT32                  NumLoops;
63667754Smsmith    UINT32                  i;
637167802Sjkim    UINT32                  Size;
638167802Sjkim    ACPI_MUTEX              MainThreadGate;
639167802Sjkim    ACPI_MUTEX              ThreadCompleteGate;
640193267Sjkim    ACPI_MUTEX              InfoGate;
64167754Smsmith
642193267Sjkim
64367754Smsmith    /* Get the arguments */
64467754Smsmith
64591116Smsmith    NumThreads = ACPI_STRTOUL (NumThreadsArg, NULL, 0);
64691116Smsmith    NumLoops   = ACPI_STRTOUL (NumLoopsArg, NULL, 0);
64767754Smsmith
64867754Smsmith    if (!NumThreads || !NumLoops)
64967754Smsmith    {
650151937Sjkim        AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n",
651151937Sjkim            NumThreads, NumLoops);
65267754Smsmith        return;
65367754Smsmith    }
65467754Smsmith
655167802Sjkim    /*
656167802Sjkim     * Create the semaphore for synchronization of
657167802Sjkim     * the created threads with the main thread.
658167802Sjkim     */
659167802Sjkim    Status = AcpiOsCreateSemaphore (1, 0, &MainThreadGate);
660167802Sjkim    if (ACPI_FAILURE (Status))
661167802Sjkim    {
662167802Sjkim        AcpiOsPrintf ("Could not create semaphore for synchronization with the main thread, %s\n",
663167802Sjkim            AcpiFormatException (Status));
664167802Sjkim        return;
665167802Sjkim    }
66667754Smsmith
667167802Sjkim    /*
668167802Sjkim     * Create the semaphore for synchronization
669167802Sjkim     * between the created threads.
670167802Sjkim     */
671167802Sjkim    Status = AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate);
67267754Smsmith    if (ACPI_FAILURE (Status))
67367754Smsmith    {
674167802Sjkim        AcpiOsPrintf ("Could not create semaphore for synchronization between the created threads, %s\n",
675151937Sjkim            AcpiFormatException (Status));
676167802Sjkim        (void) AcpiOsDeleteSemaphore (MainThreadGate);
67767754Smsmith        return;
67867754Smsmith    }
67967754Smsmith
680193267Sjkim    Status = AcpiOsCreateSemaphore (1, 1, &InfoGate);
681193267Sjkim    if (ACPI_FAILURE (Status))
682193267Sjkim    {
683193267Sjkim        AcpiOsPrintf ("Could not create semaphore for synchronization of AcpiGbl_DbMethodInfo, %s\n",
684193267Sjkim            AcpiFormatException (Status));
685193267Sjkim        (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
686193267Sjkim        (void) AcpiOsDeleteSemaphore (MainThreadGate);
687193267Sjkim        return;
688193267Sjkim    }
689193267Sjkim
690167802Sjkim    ACPI_MEMSET (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
691167802Sjkim
692167802Sjkim    /* Array to store IDs of threads */
693167802Sjkim
694167802Sjkim    AcpiGbl_DbMethodInfo.NumThreads = NumThreads;
695212761Sjkim    Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads;
696212761Sjkim    AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size);
697167802Sjkim    if (AcpiGbl_DbMethodInfo.Threads == NULL)
698167802Sjkim    {
699167802Sjkim        AcpiOsPrintf ("No memory for thread IDs array\n");
700167802Sjkim        (void) AcpiOsDeleteSemaphore (MainThreadGate);
701167802Sjkim        (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
702193267Sjkim        (void) AcpiOsDeleteSemaphore (InfoGate);
703167802Sjkim        return;
704167802Sjkim    }
705167802Sjkim    ACPI_MEMSET (AcpiGbl_DbMethodInfo.Threads, 0, Size);
706167802Sjkim
70767754Smsmith    /* Setup the context to be passed to each thread */
70867754Smsmith
70983174Smsmith    AcpiGbl_DbMethodInfo.Name = MethodNameArg;
71083174Smsmith    AcpiGbl_DbMethodInfo.Flags = 0;
71183174Smsmith    AcpiGbl_DbMethodInfo.NumLoops = NumLoops;
712167802Sjkim    AcpiGbl_DbMethodInfo.MainThreadGate = MainThreadGate;
713167802Sjkim    AcpiGbl_DbMethodInfo.ThreadCompleteGate = ThreadCompleteGate;
714193267Sjkim    AcpiGbl_DbMethodInfo.InfoGate = InfoGate;
71567754Smsmith
716167802Sjkim    /* Init arguments to be passed to method */
717167802Sjkim
718167802Sjkim    AcpiGbl_DbMethodInfo.InitArgs = 1;
719167802Sjkim    AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments;
720167802Sjkim    AcpiGbl_DbMethodInfo.Arguments[0] = AcpiGbl_DbMethodInfo.NumThreadsStr;
721167802Sjkim    AcpiGbl_DbMethodInfo.Arguments[1] = AcpiGbl_DbMethodInfo.IdOfThreadStr;
722167802Sjkim    AcpiGbl_DbMethodInfo.Arguments[2] = AcpiGbl_DbMethodInfo.IndexOfThreadStr;
723167802Sjkim    AcpiGbl_DbMethodInfo.Arguments[3] = NULL;
724222544Sjkim
725222544Sjkim    AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes;
726222544Sjkim    AcpiGbl_DbMethodInfo.ArgTypes[0] = ACPI_TYPE_INTEGER;
727222544Sjkim    AcpiGbl_DbMethodInfo.ArgTypes[1] = ACPI_TYPE_INTEGER;
728222544Sjkim    AcpiGbl_DbMethodInfo.ArgTypes[2] = ACPI_TYPE_INTEGER;
729222544Sjkim
730237412Sjkim    AcpiDbUint32ToHexString (NumThreads, AcpiGbl_DbMethodInfo.NumThreadsStr);
731167802Sjkim
73283174Smsmith    AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
73367754Smsmith
734239340Sjkim    /* Get the NS node, determines existence also */
735239340Sjkim
736239340Sjkim    Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
737239340Sjkim        &AcpiGbl_DbMethodInfo.Method);
738239340Sjkim    if (ACPI_FAILURE (Status))
739239340Sjkim    {
740239340Sjkim        AcpiOsPrintf ("%s Could not get handle for %s\n",
741239340Sjkim            AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname);
742239340Sjkim        goto CleanupAndExit;
743239340Sjkim    }
744239340Sjkim
74567754Smsmith    /* Create the threads */
74667754Smsmith
747151937Sjkim    AcpiOsPrintf ("Creating %X threads to execute %X times each\n",
748151937Sjkim        NumThreads, NumLoops);
74967754Smsmith
75067754Smsmith    for (i = 0; i < (NumThreads); i++)
75167754Smsmith    {
752167802Sjkim        Status = AcpiOsExecute (OSL_DEBUGGER_THREAD, AcpiDbMethodThread,
753151937Sjkim            &AcpiGbl_DbMethodInfo);
75499679Siwasaki        if (ACPI_FAILURE (Status))
75599679Siwasaki        {
75699679Siwasaki            break;
75799679Siwasaki        }
75867754Smsmith    }
75967754Smsmith
76067754Smsmith    /* Wait for all threads to complete */
76167754Smsmith
762193267Sjkim    (void) AcpiOsWaitSemaphore (MainThreadGate, 1, ACPI_WAIT_FOREVER);
76367754Smsmith
764167802Sjkim    AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
765167802Sjkim    AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads);
766167802Sjkim    AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
767167802Sjkim
768239340SjkimCleanupAndExit:
769239340Sjkim
77067754Smsmith    /* Cleanup and exit */
77167754Smsmith
772167802Sjkim    (void) AcpiOsDeleteSemaphore (MainThreadGate);
773167802Sjkim    (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
774193267Sjkim    (void) AcpiOsDeleteSemaphore (InfoGate);
77567754Smsmith
776167802Sjkim    AcpiOsFree (AcpiGbl_DbMethodInfo.Threads);
777167802Sjkim    AcpiGbl_DbMethodInfo.Threads = NULL;
77867754Smsmith}
77967754Smsmith
780102550Siwasaki#endif /* ACPI_DEBUGGER */
781