]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/dev/acpica/debugger/dbexec.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / dev / acpica / debugger / dbexec.c
1 /*******************************************************************************
2  *
3  * Module Name: dbexec - debugger control method execution
4  *
5  ******************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2011, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43
44
45 #include <contrib/dev/acpica/include/acpi.h>
46 #include <contrib/dev/acpica/include/accommon.h>
47 #include <contrib/dev/acpica/include/acdebug.h>
48 #include <contrib/dev/acpica/include/acnamesp.h>
49
50 #ifdef ACPI_DEBUGGER
51
52 #define _COMPONENT          ACPI_CA_DEBUGGER
53         ACPI_MODULE_NAME    ("dbexec")
54
55
56 static ACPI_DB_METHOD_INFO          AcpiGbl_DbMethodInfo;
57 #define DB_DEFAULT_PKG_ELEMENTS     33
58
59 /* Local prototypes */
60
61 static ACPI_STATUS
62 AcpiDbExecuteMethod (
63     ACPI_DB_METHOD_INFO     *Info,
64     ACPI_BUFFER             *ReturnObj);
65
66 static void
67 AcpiDbExecuteSetup (
68     ACPI_DB_METHOD_INFO     *Info);
69
70 static UINT32
71 AcpiDbGetOutstandingAllocations (
72     void);
73
74 static void ACPI_SYSTEM_XFACE
75 AcpiDbMethodThread (
76     void                    *Context);
77
78 static ACPI_STATUS
79 AcpiDbExecutionWalk (
80     ACPI_HANDLE             ObjHandle,
81     UINT32                  NestingLevel,
82     void                    *Context,
83     void                    **ReturnValue);
84
85 static ACPI_STATUS
86 AcpiDbHexCharToValue (
87     int                     HexChar,
88     UINT8                   *ReturnValue);
89
90 static ACPI_STATUS
91 AcpiDbConvertToPackage (
92     char                    *String,
93     ACPI_OBJECT             *Object);
94
95 static ACPI_STATUS
96 AcpiDbConvertToObject (
97     ACPI_OBJECT_TYPE        Type,
98     char                    *String,
99     ACPI_OBJECT             *Object);
100
101 static void
102 AcpiDbDeleteObjects (
103     UINT32                  Count,
104     ACPI_OBJECT             *Objects);
105
106
107 /*******************************************************************************
108  *
109  * FUNCTION:    AcpiDbHexCharToValue
110  *
111  * PARAMETERS:  HexChar             - Ascii Hex digit, 0-9|a-f|A-F
112  *              ReturnValue         - Where the converted value is returned
113  *
114  * RETURN:      Status
115  *
116  * DESCRIPTION: Convert a single hex character to a 4-bit number (0-16).
117  *
118  ******************************************************************************/
119
120 static ACPI_STATUS
121 AcpiDbHexCharToValue (
122     int                     HexChar,
123     UINT8                   *ReturnValue)
124 {
125     UINT8                   Value;
126
127
128     /* Digit must be ascii [0-9a-fA-F] */
129
130     if (!ACPI_IS_XDIGIT (HexChar))
131     {
132         return (AE_BAD_HEX_CONSTANT);
133     }
134
135     if (HexChar <= 0x39)
136     {
137         Value = (UINT8) (HexChar - 0x30);
138     }
139     else
140     {
141         Value = (UINT8) (ACPI_TOUPPER (HexChar) - 0x37);
142     }
143
144     *ReturnValue = Value;
145     return (AE_OK);
146 }
147
148
149 /*******************************************************************************
150  *
151  * FUNCTION:    AcpiDbHexByteToBinary
152  *
153  * PARAMETERS:  HexByte             - Double hex digit (0x00 - 0xFF) in format:
154  *                                    HiByte then LoByte.
155  *              ReturnValue         - Where the converted value is returned
156  *
157  * RETURN:      Status
158  *
159  * DESCRIPTION: Convert two hex characters to an 8 bit number (0 - 255).
160  *
161  ******************************************************************************/
162
163 static ACPI_STATUS
164 AcpiDbHexByteToBinary (
165     char                    *HexByte,
166     UINT8                   *ReturnValue)
167 {
168     UINT8                   Local0;
169     UINT8                   Local1;
170     ACPI_STATUS             Status;
171
172
173     /* High byte */
174
175     Status = AcpiDbHexCharToValue (HexByte[0], &Local0);
176     if (ACPI_FAILURE (Status))
177     {
178         return (Status);
179     }
180
181     /* Low byte */
182
183     Status = AcpiDbHexCharToValue (HexByte[1], &Local1);
184     if (ACPI_FAILURE (Status))
185     {
186         return (Status);
187     }
188
189     *ReturnValue = (UINT8) ((Local0 << 4) | Local1);
190     return (AE_OK);
191 }
192
193
194 /*******************************************************************************
195  *
196  * FUNCTION:    AcpiDbConvertToBuffer
197  *
198  * PARAMETERS:  String              - Input string to be converted
199  *              Object              - Where the buffer object is returned
200  *
201  * RETURN:      Status
202  *
203  * DESCRIPTION: Convert a string to a buffer object. String is treated a list
204  *              of buffer elements, each separated by a space or comma.
205  *
206  ******************************************************************************/
207
208 static ACPI_STATUS
209 AcpiDbConvertToBuffer (
210     char                    *String,
211     ACPI_OBJECT             *Object)
212 {
213     UINT32                  i;
214     UINT32                  j;
215     UINT32                  Length;
216     UINT8                   *Buffer;
217     ACPI_STATUS             Status;
218
219
220     /* Generate the final buffer length */
221
222     for (i = 0, Length = 0; String[i];)
223     {
224         i+=2;
225         Length++;
226
227         while (String[i] &&
228               ((String[i] == ',') || (String[i] == ' ')))
229         {
230             i++;
231         }
232     }
233
234     Buffer = ACPI_ALLOCATE (Length);
235     if (!Buffer)
236     {
237         return (AE_NO_MEMORY);
238     }
239
240     /* Convert the command line bytes to the buffer */
241
242     for (i = 0, j = 0; String[i];)
243     {
244         Status = AcpiDbHexByteToBinary (&String[i], &Buffer[j]);
245         if (ACPI_FAILURE (Status))
246         {
247             ACPI_FREE (Buffer);
248             return (Status);
249         }
250
251         j++;
252         i+=2;
253         while (String[i] &&
254               ((String[i] == ',') || (String[i] == ' ')))
255         {
256             i++;
257         }
258     }
259
260     Object->Type = ACPI_TYPE_BUFFER;
261     Object->Buffer.Pointer = Buffer;
262     Object->Buffer.Length = Length;
263     return (AE_OK);
264 }
265
266
267 /*******************************************************************************
268  *
269  * FUNCTION:    AcpiDbConvertToPackage
270  *
271  * PARAMETERS:  String              - Input string to be converted
272  *              Object              - Where the package object is returned
273  *
274  * RETURN:      Status
275  *
276  * DESCRIPTION: Convert a string to a package object. Handles nested packages
277  *              via recursion with AcpiDbConvertToObject.
278  *
279  ******************************************************************************/
280
281 static ACPI_STATUS
282 AcpiDbConvertToPackage (
283     char                    *String,
284     ACPI_OBJECT             *Object)
285 {
286     char                    *This;
287     char                    *Next;
288     UINT32                  i;
289     ACPI_OBJECT_TYPE        Type;
290     ACPI_OBJECT             *Elements;
291     ACPI_STATUS             Status;
292
293
294     Elements = ACPI_ALLOCATE_ZEROED (
295         DB_DEFAULT_PKG_ELEMENTS * sizeof (ACPI_OBJECT));
296
297     This = String;
298     for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++)
299     {
300         This = AcpiDbGetNextToken (This, &Next, &Type);
301         if (!This)
302         {
303             break;
304         }
305
306         /* Recursive call to convert each package element */
307
308         Status = AcpiDbConvertToObject (Type, This, &Elements[i]);
309         if (ACPI_FAILURE (Status))
310         {
311             AcpiDbDeleteObjects (i + 1, Elements);
312             ACPI_FREE (Elements);
313             return (Status);
314         }
315
316         This = Next;
317     }
318
319     Object->Type = ACPI_TYPE_PACKAGE;
320     Object->Package.Count = i;
321     Object->Package.Elements = Elements;
322     return (AE_OK);
323 }
324
325
326 /*******************************************************************************
327  *
328  * FUNCTION:    AcpiDbConvertToObject
329  *
330  * PARAMETERS:  Type                - Object type as determined by parser
331  *              String              - Input string to be converted
332  *              Object              - Where the new object is returned
333  *
334  * RETURN:      Status
335  *
336  * DESCRIPTION: Convert a typed and tokenized string to an ACPI_OBJECT. Typing:
337  *              1) String objects were surrounded by quotes.
338  *              2) Buffer objects were surrounded by parentheses.
339  *              3) Package objects were surrounded by brackets "[]".
340  *              4) All standalone tokens are treated as integers.
341  *
342  ******************************************************************************/
343
344 static ACPI_STATUS
345 AcpiDbConvertToObject (
346     ACPI_OBJECT_TYPE        Type,
347     char                    *String,
348     ACPI_OBJECT             *Object)
349 {
350     ACPI_STATUS             Status = AE_OK;
351
352
353     switch (Type)
354     {
355     case ACPI_TYPE_STRING:
356         Object->Type = ACPI_TYPE_STRING;
357         Object->String.Pointer = String;
358         Object->String.Length = (UINT32) ACPI_STRLEN (String);
359         break;
360
361     case ACPI_TYPE_BUFFER:
362         Status = AcpiDbConvertToBuffer (String, Object);
363         break;
364
365     case ACPI_TYPE_PACKAGE:
366         Status = AcpiDbConvertToPackage (String, Object);
367         break;
368
369     default:
370         Object->Type = ACPI_TYPE_INTEGER;
371         Status = AcpiUtStrtoul64 (String, 16, &Object->Integer.Value);
372         break;
373     }
374
375     return (Status);
376 }
377
378
379 /*******************************************************************************
380  *
381  * FUNCTION:    AcpiDbDeleteObjects
382  *
383  * PARAMETERS:  Count               - Count of objects in the list
384  *              Objects             - Array of ACPI_OBJECTs to be deleted
385  *
386  * RETURN:      None
387  *
388  * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
389  *              packages via recursion.
390  *
391  ******************************************************************************/
392
393 static void
394 AcpiDbDeleteObjects (
395     UINT32                  Count,
396     ACPI_OBJECT             *Objects)
397 {
398     UINT32                  i;
399
400
401     for (i = 0; i < Count; i++)
402     {
403         switch (Objects[i].Type)
404         {
405         case ACPI_TYPE_BUFFER:
406             ACPI_FREE (Objects[i].Buffer.Pointer);
407             break;
408
409         case ACPI_TYPE_PACKAGE:
410
411             /* Recursive call to delete package elements */
412
413             AcpiDbDeleteObjects (Objects[i].Package.Count,
414                 Objects[i].Package.Elements);
415
416             /* Free the elements array */
417
418             ACPI_FREE (Objects[i].Package.Elements);
419             break;
420
421         default:
422             break;
423         }
424     }
425 }
426
427
428 /*******************************************************************************
429  *
430  * FUNCTION:    AcpiDbExecuteMethod
431  *
432  * PARAMETERS:  Info            - Valid info segment
433  *              ReturnObj       - Where to put return object
434  *
435  * RETURN:      Status
436  *
437  * DESCRIPTION: Execute a control method.
438  *
439  ******************************************************************************/
440
441 static ACPI_STATUS
442 AcpiDbExecuteMethod (
443     ACPI_DB_METHOD_INFO     *Info,
444     ACPI_BUFFER             *ReturnObj)
445 {
446     ACPI_STATUS             Status;
447     ACPI_OBJECT_LIST        ParamObjects;
448     ACPI_OBJECT             Params[ACPI_METHOD_NUM_ARGS];
449     ACPI_HANDLE             Handle;
450     ACPI_DEVICE_INFO        *ObjInfo;
451     UINT32                  i;
452
453
454     ACPI_FUNCTION_TRACE (DbExecuteMethod);
455
456
457     if (AcpiGbl_DbOutputToFile && !AcpiDbgLevel)
458     {
459         AcpiOsPrintf ("Warning: debug output is not enabled!\n");
460     }
461
462     /* Get the NS node, determines existence also */
463
464     Status = AcpiGetHandle (NULL, Info->Pathname, &Handle);
465     if (ACPI_FAILURE (Status))
466     {
467         return_ACPI_STATUS (Status);
468     }
469
470     /* Get the object info for number of method parameters */
471
472     Status = AcpiGetObjectInfo (Handle, &ObjInfo);
473     if (ACPI_FAILURE (Status))
474     {
475         return_ACPI_STATUS (Status);
476     }
477
478     ParamObjects.Pointer = NULL;
479     ParamObjects.Count   = 0;
480
481     if (ObjInfo->Type == ACPI_TYPE_METHOD)
482     {
483         /* Are there arguments to the method? */
484
485         i = 0;
486         if (Info->Args && Info->Args[0])
487         {
488             /* Get arguments passed on the command line */
489
490             for (; Info->Args[i] &&
491                 (i < ACPI_METHOD_NUM_ARGS) &&
492                 (i < ObjInfo->ParamCount);
493                 i++)
494             {
495                 /* Convert input string (token) to an actual ACPI_OBJECT */
496
497                 Status = AcpiDbConvertToObject (Info->Types[i],
498                     Info->Args[i], &Params[i]);
499                 if (ACPI_FAILURE (Status))
500                 {
501                     ACPI_EXCEPTION ((AE_INFO, Status,
502                         "While parsing method arguments"));
503                     goto Cleanup;
504                 }
505             }
506         }
507
508         /* Create additional "default" parameters as needed */
509
510         if (i < ObjInfo->ParamCount)
511         {
512             AcpiOsPrintf ("Adding %u arguments containing default values\n",
513                 ObjInfo->ParamCount - i);
514
515             for (; i < ObjInfo->ParamCount; i++)
516             {
517                 switch (i)
518                 {
519                 case 0:
520
521                     Params[0].Type           = ACPI_TYPE_INTEGER;
522                     Params[0].Integer.Value  = 0x01020304;
523                     break;
524
525                 case 1:
526
527                     Params[1].Type           = ACPI_TYPE_STRING;
528                     Params[1].String.Length  = 12;
529                     Params[1].String.Pointer = "AML Debugger";
530                     break;
531
532                 default:
533
534                     Params[i].Type           = ACPI_TYPE_INTEGER;
535                     Params[i].Integer.Value  = i * (UINT64) 0x1000;
536                     break;
537                 }
538             }
539         }
540
541         ParamObjects.Count = ObjInfo->ParamCount;
542         ParamObjects.Pointer = Params;
543     }
544
545     /* Prepare for a return object of arbitrary size */
546
547     ReturnObj->Pointer = AcpiGbl_DbBuffer;
548     ReturnObj->Length  = ACPI_DEBUG_BUFFER_SIZE;
549
550     /* Do the actual method execution */
551
552     AcpiGbl_MethodExecuting = TRUE;
553     Status = AcpiEvaluateObject (NULL,
554         Info->Pathname, &ParamObjects, ReturnObj);
555
556     AcpiGbl_CmSingleStep = FALSE;
557     AcpiGbl_MethodExecuting = FALSE;
558
559     if (ACPI_FAILURE (Status))
560     {
561         ACPI_EXCEPTION ((AE_INFO, Status,
562             "while executing %s from debugger", Info->Pathname));
563
564         if (Status == AE_BUFFER_OVERFLOW)
565         {
566             ACPI_ERROR ((AE_INFO,
567                 "Possible overflow of internal debugger buffer (size 0x%X needed 0x%X)",
568                 ACPI_DEBUG_BUFFER_SIZE, (UINT32) ReturnObj->Length));
569         }
570     }
571
572 Cleanup:
573     AcpiDbDeleteObjects (ObjInfo->ParamCount, Params);
574     ACPI_FREE (ObjInfo);
575
576     return_ACPI_STATUS (Status);
577 }
578
579
580 /*******************************************************************************
581  *
582  * FUNCTION:    AcpiDbExecuteSetup
583  *
584  * PARAMETERS:  Info            - Valid method info
585  *
586  * RETURN:      None
587  *
588  * DESCRIPTION: Setup info segment prior to method execution
589  *
590  ******************************************************************************/
591
592 static void
593 AcpiDbExecuteSetup (
594     ACPI_DB_METHOD_INFO     *Info)
595 {
596
597     /* Catenate the current scope to the supplied name */
598
599     Info->Pathname[0] = 0;
600     if ((Info->Name[0] != '\\') &&
601         (Info->Name[0] != '/'))
602     {
603         ACPI_STRCAT (Info->Pathname, AcpiGbl_DbScopeBuf);
604     }
605
606     ACPI_STRCAT (Info->Pathname, Info->Name);
607     AcpiDbPrepNamestring (Info->Pathname);
608
609     AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
610     AcpiOsPrintf ("Executing %s\n", Info->Pathname);
611
612     if (Info->Flags & EX_SINGLE_STEP)
613     {
614         AcpiGbl_CmSingleStep = TRUE;
615         AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
616     }
617
618     else
619     {
620         /* No single step, allow redirection to a file */
621
622         AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT);
623     }
624 }
625
626
627 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
628 UINT32
629 AcpiDbGetCacheInfo (
630     ACPI_MEMORY_LIST        *Cache)
631 {
632
633     return (Cache->TotalAllocated - Cache->TotalFreed - Cache->CurrentDepth);
634 }
635 #endif
636
637 /*******************************************************************************
638  *
639  * FUNCTION:    AcpiDbGetOutstandingAllocations
640  *
641  * PARAMETERS:  None
642  *
643  * RETURN:      Current global allocation count minus cache entries
644  *
645  * DESCRIPTION: Determine the current number of "outstanding" allocations --
646  *              those allocations that have not been freed and also are not
647  *              in one of the various object caches.
648  *
649  ******************************************************************************/
650
651 static UINT32
652 AcpiDbGetOutstandingAllocations (
653     void)
654 {
655     UINT32                  Outstanding = 0;
656
657 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
658
659     Outstanding += AcpiDbGetCacheInfo (AcpiGbl_StateCache);
660     Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeCache);
661     Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeExtCache);
662     Outstanding += AcpiDbGetCacheInfo (AcpiGbl_OperandCache);
663 #endif
664
665     return (Outstanding);
666 }
667
668
669 /*******************************************************************************
670  *
671  * FUNCTION:    AcpiDbExecutionWalk
672  *
673  * PARAMETERS:  WALK_CALLBACK
674  *
675  * RETURN:      Status
676  *
677  * DESCRIPTION: Execute a control method.  Name is relative to the current
678  *              scope.
679  *
680  ******************************************************************************/
681
682 static ACPI_STATUS
683 AcpiDbExecutionWalk (
684     ACPI_HANDLE             ObjHandle,
685     UINT32                  NestingLevel,
686     void                    *Context,
687     void                    **ReturnValue)
688 {
689     ACPI_OPERAND_OBJECT     *ObjDesc;
690     ACPI_NAMESPACE_NODE     *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
691     ACPI_BUFFER             ReturnObj;
692     ACPI_STATUS             Status;
693
694
695     ObjDesc = AcpiNsGetAttachedObject (Node);
696     if (ObjDesc->Method.ParamCount)
697     {
698         return (AE_OK);
699     }
700
701     ReturnObj.Pointer = NULL;
702     ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
703
704     AcpiNsPrintNodePathname (Node, "Execute");
705
706     /* Do the actual method execution */
707
708     AcpiOsPrintf ("\n");
709     AcpiGbl_MethodExecuting = TRUE;
710
711     Status = AcpiEvaluateObject (Node, NULL, NULL, &ReturnObj);
712
713     AcpiOsPrintf ("[%4.4s] returned %s\n", AcpiUtGetNodeName (Node),
714             AcpiFormatException (Status));
715     AcpiGbl_MethodExecuting = FALSE;
716
717     return (AE_OK);
718 }
719
720
721 /*******************************************************************************
722  *
723  * FUNCTION:    AcpiDbExecute
724  *
725  * PARAMETERS:  Name                - Name of method to execute
726  *              Args                - Parameters to the method
727  *              Flags               - single step/no single step
728  *
729  * RETURN:      None
730  *
731  * DESCRIPTION: Execute a control method.  Name is relative to the current
732  *              scope.
733  *
734  ******************************************************************************/
735
736 void
737 AcpiDbExecute (
738     char                    *Name,
739     char                    **Args,
740     ACPI_OBJECT_TYPE        *Types,
741     UINT32                  Flags)
742 {
743     ACPI_STATUS             Status;
744     ACPI_BUFFER             ReturnObj;
745     char                    *NameString;
746
747
748 #ifdef ACPI_DEBUG_OUTPUT
749     UINT32                  PreviousAllocations;
750     UINT32                  Allocations;
751
752
753     /* Memory allocation tracking */
754
755     PreviousAllocations = AcpiDbGetOutstandingAllocations ();
756 #endif
757
758     if (*Name == '*')
759     {
760         (void) AcpiWalkNamespace (ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
761                     ACPI_UINT32_MAX, AcpiDbExecutionWalk, NULL, NULL, NULL);
762         return;
763     }
764     else
765     {
766         NameString = ACPI_ALLOCATE (ACPI_STRLEN (Name) + 1);
767         if (!NameString)
768         {
769             return;
770         }
771
772         ACPI_MEMSET (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
773
774         ACPI_STRCPY (NameString, Name);
775         AcpiUtStrupr (NameString);
776         AcpiGbl_DbMethodInfo.Name = NameString;
777         AcpiGbl_DbMethodInfo.Args = Args;
778         AcpiGbl_DbMethodInfo.Types = Types;
779         AcpiGbl_DbMethodInfo.Flags = Flags;
780
781         ReturnObj.Pointer = NULL;
782         ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
783
784         AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
785         Status = AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo, &ReturnObj);
786         ACPI_FREE (NameString);
787     }
788
789     /*
790      * Allow any handlers in separate threads to complete.
791      * (Such as Notify handlers invoked from AML executed above).
792      */
793     AcpiOsSleep ((UINT64) 10);
794
795
796 #ifdef ACPI_DEBUG_OUTPUT
797
798     /* Memory allocation tracking */
799
800     Allocations = AcpiDbGetOutstandingAllocations () - PreviousAllocations;
801
802     AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
803
804     if (Allocations > 0)
805     {
806         AcpiOsPrintf ("Outstanding: 0x%X allocations after execution\n",
807                         Allocations);
808     }
809 #endif
810
811     if (ACPI_FAILURE (Status))
812     {
813         AcpiOsPrintf ("Execution of %s failed with status %s\n",
814             AcpiGbl_DbMethodInfo.Pathname, AcpiFormatException (Status));
815     }
816     else
817     {
818         /* Display a return object, if any */
819
820         if (ReturnObj.Length)
821         {
822             AcpiOsPrintf ("Execution of %s returned object %p Buflen %X\n",
823                 AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer,
824                 (UINT32) ReturnObj.Length);
825             AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
826         }
827         else
828         {
829             AcpiOsPrintf ("No return object from execution of %s\n",
830                 AcpiGbl_DbMethodInfo.Pathname);
831         }
832     }
833
834     AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
835 }
836
837
838 /*******************************************************************************
839  *
840  * FUNCTION:    AcpiDbMethodThread
841  *
842  * PARAMETERS:  Context             - Execution info segment
843  *
844  * RETURN:      None
845  *
846  * DESCRIPTION: Debugger execute thread.  Waits for a command line, then
847  *              simply dispatches it.
848  *
849  ******************************************************************************/
850
851 static void ACPI_SYSTEM_XFACE
852 AcpiDbMethodThread (
853     void                    *Context)
854 {
855     ACPI_STATUS             Status;
856     ACPI_DB_METHOD_INFO     *Info = Context;
857     ACPI_DB_METHOD_INFO     LocalInfo;
858     UINT32                  i;
859     UINT8                   Allow;
860     ACPI_BUFFER             ReturnObj;
861
862
863     /*
864      * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments.
865      * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads
866      * concurrently.
867      *
868      * Note: The arguments we are passing are used by the ASL test suite
869      * (aslts). Do not change them without updating the tests.
870      */
871     (void) AcpiOsWaitSemaphore (Info->InfoGate, 1, ACPI_WAIT_FOREVER);
872
873     if (Info->InitArgs)
874     {
875         AcpiDbUInt32ToHexString (Info->NumCreated, Info->IndexOfThreadStr);
876         AcpiDbUInt32ToHexString ((UINT32) AcpiOsGetThreadId (), Info->IdOfThreadStr);
877     }
878
879     if (Info->Threads && (Info->NumCreated < Info->NumThreads))
880     {
881         Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId();
882     }
883
884     LocalInfo = *Info;
885     LocalInfo.Args = LocalInfo.Arguments;
886     LocalInfo.Arguments[0] = LocalInfo.NumThreadsStr;
887     LocalInfo.Arguments[1] = LocalInfo.IdOfThreadStr;
888     LocalInfo.Arguments[2] = LocalInfo.IndexOfThreadStr;
889     LocalInfo.Arguments[3] = NULL;
890
891     LocalInfo.Types = LocalInfo.ArgTypes;
892
893     (void) AcpiOsSignalSemaphore (Info->InfoGate, 1);
894
895     for (i = 0; i < Info->NumLoops; i++)
896     {
897         Status = AcpiDbExecuteMethod (&LocalInfo, &ReturnObj);
898         if (ACPI_FAILURE (Status))
899         {
900             AcpiOsPrintf ("%s During execution of %s at iteration %X\n",
901                 AcpiFormatException (Status), Info->Pathname, i);
902             if (Status == AE_ABORT_METHOD)
903             {
904                 break;
905             }
906         }
907
908 #if 0
909         if ((i % 100) == 0)
910         {
911             AcpiOsPrintf ("%u executions, Thread 0x%x\n", i, AcpiOsGetThreadId ());
912         }
913
914         if (ReturnObj.Length)
915         {
916             AcpiOsPrintf ("Execution of %s returned object %p Buflen %X\n",
917                 Info->Pathname, ReturnObj.Pointer, (UINT32) ReturnObj.Length);
918             AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
919         }
920 #endif
921     }
922
923     /* Signal our completion */
924
925     Allow = 0;
926     (void) AcpiOsWaitSemaphore (Info->ThreadCompleteGate, 1, ACPI_WAIT_FOREVER);
927     Info->NumCompleted++;
928
929     if (Info->NumCompleted == Info->NumThreads)
930     {
931         /* Do signal for main thread once only */
932         Allow = 1;
933     }
934
935     (void) AcpiOsSignalSemaphore (Info->ThreadCompleteGate, 1);
936
937     if (Allow)
938     {
939         Status = AcpiOsSignalSemaphore (Info->MainThreadGate, 1);
940         if (ACPI_FAILURE (Status))
941         {
942             AcpiOsPrintf ("Could not signal debugger thread sync semaphore, %s\n",
943                 AcpiFormatException (Status));
944         }
945     }
946 }
947
948
949 /*******************************************************************************
950  *
951  * FUNCTION:    AcpiDbCreateExecutionThreads
952  *
953  * PARAMETERS:  NumThreadsArg           - Number of threads to create
954  *              NumLoopsArg             - Loop count for the thread(s)
955  *              MethodNameArg           - Control method to execute
956  *
957  * RETURN:      None
958  *
959  * DESCRIPTION: Create threads to execute method(s)
960  *
961  ******************************************************************************/
962
963 void
964 AcpiDbCreateExecutionThreads (
965     char                    *NumThreadsArg,
966     char                    *NumLoopsArg,
967     char                    *MethodNameArg)
968 {
969     ACPI_STATUS             Status;
970     UINT32                  NumThreads;
971     UINT32                  NumLoops;
972     UINT32                  i;
973     UINT32                  Size;
974     ACPI_MUTEX              MainThreadGate;
975     ACPI_MUTEX              ThreadCompleteGate;
976     ACPI_MUTEX              InfoGate;
977
978
979     /* Get the arguments */
980
981     NumThreads = ACPI_STRTOUL (NumThreadsArg, NULL, 0);
982     NumLoops   = ACPI_STRTOUL (NumLoopsArg, NULL, 0);
983
984     if (!NumThreads || !NumLoops)
985     {
986         AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n",
987             NumThreads, NumLoops);
988         return;
989     }
990
991     /*
992      * Create the semaphore for synchronization of
993      * the created threads with the main thread.
994      */
995     Status = AcpiOsCreateSemaphore (1, 0, &MainThreadGate);
996     if (ACPI_FAILURE (Status))
997     {
998         AcpiOsPrintf ("Could not create semaphore for synchronization with the main thread, %s\n",
999             AcpiFormatException (Status));
1000         return;
1001     }
1002
1003     /*
1004      * Create the semaphore for synchronization
1005      * between the created threads.
1006      */
1007     Status = AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate);
1008     if (ACPI_FAILURE (Status))
1009     {
1010         AcpiOsPrintf ("Could not create semaphore for synchronization between the created threads, %s\n",
1011             AcpiFormatException (Status));
1012         (void) AcpiOsDeleteSemaphore (MainThreadGate);
1013         return;
1014     }
1015
1016     Status = AcpiOsCreateSemaphore (1, 1, &InfoGate);
1017     if (ACPI_FAILURE (Status))
1018     {
1019         AcpiOsPrintf ("Could not create semaphore for synchronization of AcpiGbl_DbMethodInfo, %s\n",
1020             AcpiFormatException (Status));
1021         (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
1022         (void) AcpiOsDeleteSemaphore (MainThreadGate);
1023         return;
1024     }
1025
1026     ACPI_MEMSET (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
1027
1028     /* Array to store IDs of threads */
1029
1030     AcpiGbl_DbMethodInfo.NumThreads = NumThreads;
1031     Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads;
1032     AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size);
1033     if (AcpiGbl_DbMethodInfo.Threads == NULL)
1034     {
1035         AcpiOsPrintf ("No memory for thread IDs array\n");
1036         (void) AcpiOsDeleteSemaphore (MainThreadGate);
1037         (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
1038         (void) AcpiOsDeleteSemaphore (InfoGate);
1039         return;
1040     }
1041     ACPI_MEMSET (AcpiGbl_DbMethodInfo.Threads, 0, Size);
1042
1043     /* Setup the context to be passed to each thread */
1044
1045     AcpiGbl_DbMethodInfo.Name = MethodNameArg;
1046     AcpiGbl_DbMethodInfo.Flags = 0;
1047     AcpiGbl_DbMethodInfo.NumLoops = NumLoops;
1048     AcpiGbl_DbMethodInfo.MainThreadGate = MainThreadGate;
1049     AcpiGbl_DbMethodInfo.ThreadCompleteGate = ThreadCompleteGate;
1050     AcpiGbl_DbMethodInfo.InfoGate = InfoGate;
1051
1052     /* Init arguments to be passed to method */
1053
1054     AcpiGbl_DbMethodInfo.InitArgs = 1;
1055     AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments;
1056     AcpiGbl_DbMethodInfo.Arguments[0] = AcpiGbl_DbMethodInfo.NumThreadsStr;
1057     AcpiGbl_DbMethodInfo.Arguments[1] = AcpiGbl_DbMethodInfo.IdOfThreadStr;
1058     AcpiGbl_DbMethodInfo.Arguments[2] = AcpiGbl_DbMethodInfo.IndexOfThreadStr;
1059     AcpiGbl_DbMethodInfo.Arguments[3] = NULL;
1060
1061     AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes;
1062     AcpiGbl_DbMethodInfo.ArgTypes[0] = ACPI_TYPE_INTEGER;
1063     AcpiGbl_DbMethodInfo.ArgTypes[1] = ACPI_TYPE_INTEGER;
1064     AcpiGbl_DbMethodInfo.ArgTypes[2] = ACPI_TYPE_INTEGER;
1065
1066     AcpiDbUInt32ToHexString (NumThreads, AcpiGbl_DbMethodInfo.NumThreadsStr);
1067
1068     AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
1069
1070     /* Create the threads */
1071
1072     AcpiOsPrintf ("Creating %X threads to execute %X times each\n",
1073         NumThreads, NumLoops);
1074
1075     for (i = 0; i < (NumThreads); i++)
1076     {
1077         Status = AcpiOsExecute (OSL_DEBUGGER_THREAD, AcpiDbMethodThread,
1078             &AcpiGbl_DbMethodInfo);
1079         if (ACPI_FAILURE (Status))
1080         {
1081             break;
1082         }
1083     }
1084
1085     /* Wait for all threads to complete */
1086
1087     (void) AcpiOsWaitSemaphore (MainThreadGate, 1, ACPI_WAIT_FOREVER);
1088
1089     AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
1090     AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads);
1091     AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
1092
1093     /* Cleanup and exit */
1094
1095     (void) AcpiOsDeleteSemaphore (MainThreadGate);
1096     (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
1097     (void) AcpiOsDeleteSemaphore (InfoGate);
1098
1099     AcpiOsFree (AcpiGbl_DbMethodInfo.Threads);
1100     AcpiGbl_DbMethodInfo.Threads = NULL;
1101 }
1102
1103 #endif /* ACPI_DEBUGGER */
1104
1105