xref: /freebsd/sys/contrib/dev/acpica/components/debugger/dbexec.c (revision 25408c853d9ecb2e76b9e38407338f86ecb8a55c)
1 /*******************************************************************************
2  *
3  * Module Name: dbexec - debugger control method execution
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2012, 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 static UINT8 *
108 AcpiDbEncodePldBuffer (
109     ACPI_PLD_INFO           *PldInfo);
110 
111 static void
112 AcpiDbDumpPldBuffer (
113     ACPI_OBJECT             *ObjDesc);
114 
115 
116 /*******************************************************************************
117  *
118  * FUNCTION:    AcpiDbHexCharToValue
119  *
120  * PARAMETERS:  HexChar             - Ascii Hex digit, 0-9|a-f|A-F
121  *              ReturnValue         - Where the converted value is returned
122  *
123  * RETURN:      Status
124  *
125  * DESCRIPTION: Convert a single hex character to a 4-bit number (0-16).
126  *
127  ******************************************************************************/
128 
129 static ACPI_STATUS
130 AcpiDbHexCharToValue (
131     int                     HexChar,
132     UINT8                   *ReturnValue)
133 {
134     UINT8                   Value;
135 
136 
137     /* Digit must be ascii [0-9a-fA-F] */
138 
139     if (!ACPI_IS_XDIGIT (HexChar))
140     {
141         return (AE_BAD_HEX_CONSTANT);
142     }
143 
144     if (HexChar <= 0x39)
145     {
146         Value = (UINT8) (HexChar - 0x30);
147     }
148     else
149     {
150         Value = (UINT8) (ACPI_TOUPPER (HexChar) - 0x37);
151     }
152 
153     *ReturnValue = Value;
154     return (AE_OK);
155 }
156 
157 
158 /*******************************************************************************
159  *
160  * FUNCTION:    AcpiDbHexByteToBinary
161  *
162  * PARAMETERS:  HexByte             - Double hex digit (0x00 - 0xFF) in format:
163  *                                    HiByte then LoByte.
164  *              ReturnValue         - Where the converted value is returned
165  *
166  * RETURN:      Status
167  *
168  * DESCRIPTION: Convert two hex characters to an 8 bit number (0 - 255).
169  *
170  ******************************************************************************/
171 
172 static ACPI_STATUS
173 AcpiDbHexByteToBinary (
174     char                    *HexByte,
175     UINT8                   *ReturnValue)
176 {
177     UINT8                   Local0;
178     UINT8                   Local1;
179     ACPI_STATUS             Status;
180 
181 
182     /* High byte */
183 
184     Status = AcpiDbHexCharToValue (HexByte[0], &Local0);
185     if (ACPI_FAILURE (Status))
186     {
187         return (Status);
188     }
189 
190     /* Low byte */
191 
192     Status = AcpiDbHexCharToValue (HexByte[1], &Local1);
193     if (ACPI_FAILURE (Status))
194     {
195         return (Status);
196     }
197 
198     *ReturnValue = (UINT8) ((Local0 << 4) | Local1);
199     return (AE_OK);
200 }
201 
202 
203 /*******************************************************************************
204  *
205  * FUNCTION:    AcpiDbConvertToBuffer
206  *
207  * PARAMETERS:  String              - Input string to be converted
208  *              Object              - Where the buffer object is returned
209  *
210  * RETURN:      Status
211  *
212  * DESCRIPTION: Convert a string to a buffer object. String is treated a list
213  *              of buffer elements, each separated by a space or comma.
214  *
215  ******************************************************************************/
216 
217 static ACPI_STATUS
218 AcpiDbConvertToBuffer (
219     char                    *String,
220     ACPI_OBJECT             *Object)
221 {
222     UINT32                  i;
223     UINT32                  j;
224     UINT32                  Length;
225     UINT8                   *Buffer;
226     ACPI_STATUS             Status;
227 
228 
229     /* Generate the final buffer length */
230 
231     for (i = 0, Length = 0; String[i];)
232     {
233         i+=2;
234         Length++;
235 
236         while (String[i] &&
237               ((String[i] == ',') || (String[i] == ' ')))
238         {
239             i++;
240         }
241     }
242 
243     Buffer = ACPI_ALLOCATE (Length);
244     if (!Buffer)
245     {
246         return (AE_NO_MEMORY);
247     }
248 
249     /* Convert the command line bytes to the buffer */
250 
251     for (i = 0, j = 0; String[i];)
252     {
253         Status = AcpiDbHexByteToBinary (&String[i], &Buffer[j]);
254         if (ACPI_FAILURE (Status))
255         {
256             ACPI_FREE (Buffer);
257             return (Status);
258         }
259 
260         j++;
261         i+=2;
262         while (String[i] &&
263               ((String[i] == ',') || (String[i] == ' ')))
264         {
265             i++;
266         }
267     }
268 
269     Object->Type = ACPI_TYPE_BUFFER;
270     Object->Buffer.Pointer = Buffer;
271     Object->Buffer.Length = Length;
272     return (AE_OK);
273 }
274 
275 
276 /*******************************************************************************
277  *
278  * FUNCTION:    AcpiDbConvertToPackage
279  *
280  * PARAMETERS:  String              - Input string to be converted
281  *              Object              - Where the package object is returned
282  *
283  * RETURN:      Status
284  *
285  * DESCRIPTION: Convert a string to a package object. Handles nested packages
286  *              via recursion with AcpiDbConvertToObject.
287  *
288  ******************************************************************************/
289 
290 static ACPI_STATUS
291 AcpiDbConvertToPackage (
292     char                    *String,
293     ACPI_OBJECT             *Object)
294 {
295     char                    *This;
296     char                    *Next;
297     UINT32                  i;
298     ACPI_OBJECT_TYPE        Type;
299     ACPI_OBJECT             *Elements;
300     ACPI_STATUS             Status;
301 
302 
303     Elements = ACPI_ALLOCATE_ZEROED (
304         DB_DEFAULT_PKG_ELEMENTS * sizeof (ACPI_OBJECT));
305 
306     This = String;
307     for (i = 0; i < (DB_DEFAULT_PKG_ELEMENTS - 1); i++)
308     {
309         This = AcpiDbGetNextToken (This, &Next, &Type);
310         if (!This)
311         {
312             break;
313         }
314 
315         /* Recursive call to convert each package element */
316 
317         Status = AcpiDbConvertToObject (Type, This, &Elements[i]);
318         if (ACPI_FAILURE (Status))
319         {
320             AcpiDbDeleteObjects (i + 1, Elements);
321             ACPI_FREE (Elements);
322             return (Status);
323         }
324 
325         This = Next;
326     }
327 
328     Object->Type = ACPI_TYPE_PACKAGE;
329     Object->Package.Count = i;
330     Object->Package.Elements = Elements;
331     return (AE_OK);
332 }
333 
334 
335 /*******************************************************************************
336  *
337  * FUNCTION:    AcpiDbConvertToObject
338  *
339  * PARAMETERS:  Type                - Object type as determined by parser
340  *              String              - Input string to be converted
341  *              Object              - Where the new object is returned
342  *
343  * RETURN:      Status
344  *
345  * DESCRIPTION: Convert a typed and tokenized string to an ACPI_OBJECT. Typing:
346  *              1) String objects were surrounded by quotes.
347  *              2) Buffer objects were surrounded by parentheses.
348  *              3) Package objects were surrounded by brackets "[]".
349  *              4) All standalone tokens are treated as integers.
350  *
351  ******************************************************************************/
352 
353 static ACPI_STATUS
354 AcpiDbConvertToObject (
355     ACPI_OBJECT_TYPE        Type,
356     char                    *String,
357     ACPI_OBJECT             *Object)
358 {
359     ACPI_STATUS             Status = AE_OK;
360 
361 
362     switch (Type)
363     {
364     case ACPI_TYPE_STRING:
365         Object->Type = ACPI_TYPE_STRING;
366         Object->String.Pointer = String;
367         Object->String.Length = (UINT32) ACPI_STRLEN (String);
368         break;
369 
370     case ACPI_TYPE_BUFFER:
371         Status = AcpiDbConvertToBuffer (String, Object);
372         break;
373 
374     case ACPI_TYPE_PACKAGE:
375         Status = AcpiDbConvertToPackage (String, Object);
376         break;
377 
378     default:
379         Object->Type = ACPI_TYPE_INTEGER;
380         Status = AcpiUtStrtoul64 (String, 16, &Object->Integer.Value);
381         break;
382     }
383 
384     return (Status);
385 }
386 
387 
388 /*******************************************************************************
389  *
390  * FUNCTION:    AcpiDbDeleteObjects
391  *
392  * PARAMETERS:  Count               - Count of objects in the list
393  *              Objects             - Array of ACPI_OBJECTs to be deleted
394  *
395  * RETURN:      None
396  *
397  * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
398  *              packages via recursion.
399  *
400  ******************************************************************************/
401 
402 static void
403 AcpiDbDeleteObjects (
404     UINT32                  Count,
405     ACPI_OBJECT             *Objects)
406 {
407     UINT32                  i;
408 
409 
410     for (i = 0; i < Count; i++)
411     {
412         switch (Objects[i].Type)
413         {
414         case ACPI_TYPE_BUFFER:
415             ACPI_FREE (Objects[i].Buffer.Pointer);
416             break;
417 
418         case ACPI_TYPE_PACKAGE:
419 
420             /* Recursive call to delete package elements */
421 
422             AcpiDbDeleteObjects (Objects[i].Package.Count,
423                 Objects[i].Package.Elements);
424 
425             /* Free the elements array */
426 
427             ACPI_FREE (Objects[i].Package.Elements);
428             break;
429 
430         default:
431             break;
432         }
433     }
434 }
435 
436 
437 /*******************************************************************************
438  *
439  * FUNCTION:    AcpiDbExecuteMethod
440  *
441  * PARAMETERS:  Info            - Valid info segment
442  *              ReturnObj       - Where to put return object
443  *
444  * RETURN:      Status
445  *
446  * DESCRIPTION: Execute a control method.
447  *
448  ******************************************************************************/
449 
450 static ACPI_STATUS
451 AcpiDbExecuteMethod (
452     ACPI_DB_METHOD_INFO     *Info,
453     ACPI_BUFFER             *ReturnObj)
454 {
455     ACPI_STATUS             Status;
456     ACPI_OBJECT_LIST        ParamObjects;
457     ACPI_OBJECT             Params[ACPI_METHOD_NUM_ARGS];
458     ACPI_DEVICE_INFO        *ObjInfo;
459     UINT32                  i;
460 
461 
462     ACPI_FUNCTION_TRACE (DbExecuteMethod);
463 
464 
465     if (AcpiGbl_DbOutputToFile && !AcpiDbgLevel)
466     {
467         AcpiOsPrintf ("Warning: debug output is not enabled!\n");
468     }
469 
470     /* Get the object info for number of method parameters */
471 
472     Status = AcpiGetObjectInfo (Info->Method, &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 ("Evaluating %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, "Evaluating");
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 ("Evaluation of [%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:    AcpiDbEncodePldBuffer
724  *
725  * PARAMETERS:  PldInfo             - _PLD buffer struct (Using local struct)
726  *
727  * RETURN:      Encode _PLD buffer suitable for return value from _PLD
728  *
729  * DESCRIPTION: Bit-packs a _PLD buffer struct. Used to test the _PLD macros
730  *
731  ******************************************************************************/
732 
733 static UINT8 *
734 AcpiDbEncodePldBuffer (
735     ACPI_PLD_INFO           *PldInfo)
736 {
737     UINT32                  *Buffer;
738     UINT32                  Dword;
739 
740 
741     Buffer = ACPI_ALLOCATE_ZEROED (ACPI_PLD_BUFFER_SIZE);
742     if (!Buffer)
743     {
744         return (NULL);
745     }
746 
747     /* First 32 bits */
748 
749     Dword = 0;
750     ACPI_PLD_SET_REVISION       (&Dword, PldInfo->Revision);
751     ACPI_PLD_SET_IGNORE_COLOR   (&Dword, PldInfo->IgnoreColor);
752     ACPI_PLD_SET_COLOR          (&Dword, PldInfo->Color);
753     ACPI_MOVE_32_TO_32 (&Buffer[0], &Dword);
754 
755     /* Second 32 bits */
756 
757     Dword = 0;
758     ACPI_PLD_SET_WIDTH          (&Dword, PldInfo->Width);
759     ACPI_PLD_SET_HEIGHT         (&Dword, PldInfo->Height);
760     ACPI_MOVE_32_TO_32 (&Buffer[1], &Dword);
761 
762     /* Third 32 bits */
763 
764     Dword = 0;
765     ACPI_PLD_SET_USER_VISIBLE   (&Dword, PldInfo->UserVisible);
766     ACPI_PLD_SET_DOCK           (&Dword, PldInfo->Dock);
767     ACPI_PLD_SET_LID            (&Dword, PldInfo->Lid);
768     ACPI_PLD_SET_PANEL          (&Dword, PldInfo->Panel);
769     ACPI_PLD_SET_VERTICAL       (&Dword, PldInfo->VerticalPosition);
770     ACPI_PLD_SET_HORIZONTAL     (&Dword, PldInfo->HorizontalPosition);
771     ACPI_PLD_SET_SHAPE          (&Dword, PldInfo->Shape);
772     ACPI_PLD_SET_ORIENTATION    (&Dword, PldInfo->GroupOrientation);
773     ACPI_PLD_SET_TOKEN          (&Dword, PldInfo->GroupToken);
774     ACPI_PLD_SET_POSITION       (&Dword, PldInfo->GroupPosition);
775     ACPI_PLD_SET_BAY            (&Dword, PldInfo->Bay);
776     ACPI_MOVE_32_TO_32 (&Buffer[2], &Dword);
777 
778     /* Fourth 32 bits */
779 
780     Dword = 0;
781     ACPI_PLD_SET_EJECTABLE      (&Dword, PldInfo->Ejectable);
782     ACPI_PLD_SET_OSPM_EJECT     (&Dword, PldInfo->OspmEjectRequired);
783     ACPI_PLD_SET_CABINET        (&Dword, PldInfo->CabinetNumber);
784     ACPI_PLD_SET_CARD_CAGE      (&Dword, PldInfo->CardCageNumber);
785     ACPI_PLD_SET_REFERENCE      (&Dword, PldInfo->Reference);
786     ACPI_PLD_SET_ROTATION       (&Dword, PldInfo->Rotation);
787     ACPI_PLD_SET_ORDER          (&Dword, PldInfo->Order);
788     ACPI_MOVE_32_TO_32 (&Buffer[3], &Dword);
789 
790     if (PldInfo->Revision >= 2)
791     {
792         /* Fifth 32 bits */
793 
794         Dword = 0;
795         ACPI_PLD_SET_VERT_OFFSET    (&Dword, PldInfo->VerticalOffset);
796         ACPI_PLD_SET_HORIZ_OFFSET   (&Dword, PldInfo->HorizontalOffset);
797         ACPI_MOVE_32_TO_32 (&Buffer[4], &Dword);
798     }
799 
800     return (ACPI_CAST_PTR (UINT8, Buffer));
801 }
802 
803 
804 /*******************************************************************************
805  *
806  * FUNCTION:    AcpiDbDumpPldBuffer
807  *
808  * PARAMETERS:  ObjDesc             - Object returned from _PLD method
809  *
810  * RETURN:      None.
811  *
812  * DESCRIPTION: Dumps formatted contents of a _PLD return buffer.
813  *
814  ******************************************************************************/
815 
816 #define ACPI_PLD_OUTPUT     "%20s : %-6X\n"
817 
818 static void
819 AcpiDbDumpPldBuffer (
820     ACPI_OBJECT             *ObjDesc)
821 {
822     ACPI_OBJECT             *BufferDesc;
823     ACPI_PLD_INFO           *PldInfo;
824     UINT8                   *NewBuffer;
825     ACPI_STATUS             Status;
826 
827 
828     /* Object must be of type Package with at least one Buffer element */
829 
830     if (ObjDesc->Type != ACPI_TYPE_PACKAGE)
831     {
832         return;
833     }
834 
835     BufferDesc = &ObjDesc->Package.Elements[0];
836     if (BufferDesc->Type != ACPI_TYPE_BUFFER)
837     {
838         return;
839     }
840 
841     /* Convert _PLD buffer to local _PLD struct */
842 
843     Status = AcpiDecodePldBuffer (BufferDesc->Buffer.Pointer,
844         BufferDesc->Buffer.Length, &PldInfo);
845     if (ACPI_FAILURE (Status))
846     {
847         return;
848     }
849 
850     /* Encode local _PLD struct back to a _PLD buffer */
851 
852     NewBuffer = AcpiDbEncodePldBuffer (PldInfo);
853     if (!NewBuffer)
854     {
855         return;
856     }
857 
858     /* The two bit-packed buffers should match */
859 
860     if (ACPI_MEMCMP (NewBuffer, BufferDesc->Buffer.Pointer,
861         BufferDesc->Buffer.Length))
862     {
863         AcpiOsPrintf ("Converted _PLD buffer does not compare. New:\n");
864 
865         AcpiUtDumpBuffer2 (NewBuffer,
866             BufferDesc->Buffer.Length, DB_BYTE_DISPLAY);
867     }
868 
869     /* First 32-bit dword */
870 
871     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Revision", PldInfo->Revision);
872     AcpiOsPrintf (ACPI_PLD_OUTPUT, "IgnoreColor", PldInfo->IgnoreColor);
873     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Color", PldInfo->Color);
874 
875     /* Second 32-bit dword */
876 
877     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Width", PldInfo->Width);
878     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Height", PldInfo->Height);
879 
880     /* Third 32-bit dword */
881 
882     AcpiOsPrintf (ACPI_PLD_OUTPUT, "UserVisible", PldInfo->UserVisible);
883     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Dock", PldInfo->Dock);
884     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Lid", PldInfo->Lid);
885     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Panel", PldInfo->Panel);
886     AcpiOsPrintf (ACPI_PLD_OUTPUT, "VerticalPosition", PldInfo->VerticalPosition);
887     AcpiOsPrintf (ACPI_PLD_OUTPUT, "HorizontalPosition", PldInfo->HorizontalPosition);
888     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Shape", PldInfo->Shape);
889     AcpiOsPrintf (ACPI_PLD_OUTPUT, "GroupOrientation", PldInfo->GroupOrientation);
890     AcpiOsPrintf (ACPI_PLD_OUTPUT, "GroupToken", PldInfo->GroupToken);
891     AcpiOsPrintf (ACPI_PLD_OUTPUT, "GroupPosition", PldInfo->GroupPosition);
892     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Bay", PldInfo->Bay);
893 
894     /* Fourth 32-bit dword */
895 
896     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Ejectable", PldInfo->Ejectable);
897     AcpiOsPrintf (ACPI_PLD_OUTPUT, "OspmEjectRequired", PldInfo->OspmEjectRequired);
898     AcpiOsPrintf (ACPI_PLD_OUTPUT, "CabinetNumber", PldInfo->CabinetNumber);
899     AcpiOsPrintf (ACPI_PLD_OUTPUT, "CardCageNumber", PldInfo->CardCageNumber);
900     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Reference", PldInfo->Reference);
901     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Rotation", PldInfo->Rotation);
902     AcpiOsPrintf (ACPI_PLD_OUTPUT, "Order", PldInfo->Order);
903 
904     /* Fifth 32-bit dword */
905 
906     if (BufferDesc->Buffer.Length > 16)
907     {
908         AcpiOsPrintf (ACPI_PLD_OUTPUT, "VerticalOffset", PldInfo->VerticalOffset);
909         AcpiOsPrintf (ACPI_PLD_OUTPUT, "HorizontalOffset", PldInfo->HorizontalOffset);
910     }
911 
912     ACPI_FREE (PldInfo);
913     ACPI_FREE (NewBuffer);
914 }
915 
916 
917 /*******************************************************************************
918  *
919  * FUNCTION:    AcpiDbExecute
920  *
921  * PARAMETERS:  Name                - Name of method to execute
922  *              Args                - Parameters to the method
923  *              Flags               - single step/no single step
924  *
925  * RETURN:      None
926  *
927  * DESCRIPTION: Execute a control method.  Name is relative to the current
928  *              scope.
929  *
930  ******************************************************************************/
931 
932 void
933 AcpiDbExecute (
934     char                    *Name,
935     char                    **Args,
936     ACPI_OBJECT_TYPE        *Types,
937     UINT32                  Flags)
938 {
939     ACPI_STATUS             Status;
940     ACPI_BUFFER             ReturnObj;
941     char                    *NameString;
942 
943 
944 #ifdef ACPI_DEBUG_OUTPUT
945     UINT32                  PreviousAllocations;
946     UINT32                  Allocations;
947 
948 
949     /* Memory allocation tracking */
950 
951     PreviousAllocations = AcpiDbGetOutstandingAllocations ();
952 #endif
953 
954     if (*Name == '*')
955     {
956         (void) AcpiWalkNamespace (ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
957                     ACPI_UINT32_MAX, AcpiDbExecutionWalk, NULL, NULL, NULL);
958         return;
959     }
960     else
961     {
962         NameString = ACPI_ALLOCATE (ACPI_STRLEN (Name) + 1);
963         if (!NameString)
964         {
965             return;
966         }
967 
968         ACPI_MEMSET (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
969 
970         ACPI_STRCPY (NameString, Name);
971         AcpiUtStrupr (NameString);
972         AcpiGbl_DbMethodInfo.Name = NameString;
973         AcpiGbl_DbMethodInfo.Args = Args;
974         AcpiGbl_DbMethodInfo.Types = Types;
975         AcpiGbl_DbMethodInfo.Flags = Flags;
976 
977         ReturnObj.Pointer = NULL;
978         ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
979 
980         AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
981 
982         /* Get the NS node, determines existence also */
983 
984         Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
985             &AcpiGbl_DbMethodInfo.Method);
986         if (ACPI_FAILURE (Status))
987         {
988             return;
989         }
990 
991         Status = AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo, &ReturnObj);
992         ACPI_FREE (NameString);
993     }
994 
995     /*
996      * Allow any handlers in separate threads to complete.
997      * (Such as Notify handlers invoked from AML executed above).
998      */
999     AcpiOsSleep ((UINT64) 10);
1000 
1001 
1002 #ifdef ACPI_DEBUG_OUTPUT
1003 
1004     /* Memory allocation tracking */
1005 
1006     Allocations = AcpiDbGetOutstandingAllocations () - PreviousAllocations;
1007 
1008     AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
1009 
1010     if (Allocations > 0)
1011     {
1012         AcpiOsPrintf ("0x%X Outstanding allocations after evaluation of %s\n",
1013                         Allocations, AcpiGbl_DbMethodInfo.Pathname);
1014     }
1015 #endif
1016 
1017     if (ACPI_FAILURE (Status))
1018     {
1019         AcpiOsPrintf ("Evaluation of %s failed with status %s\n",
1020             AcpiGbl_DbMethodInfo.Pathname, AcpiFormatException (Status));
1021     }
1022     else
1023     {
1024         /* Display a return object, if any */
1025 
1026         if (ReturnObj.Length)
1027         {
1028             AcpiOsPrintf (
1029                 "Evaluation of %s returned object %p, external buffer length %X\n",
1030                 AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer,
1031                 (UINT32) ReturnObj.Length);
1032             AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
1033 
1034             /* Dump a _PLD buffer if present */
1035 
1036             if (ACPI_COMPARE_NAME ((ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
1037                     AcpiGbl_DbMethodInfo.Method)->Name.Ascii), METHOD_NAME__PLD))
1038             {
1039                 AcpiDbDumpPldBuffer (ReturnObj.Pointer);
1040             }
1041         }
1042         else
1043         {
1044             AcpiOsPrintf ("No object was returned from evaluation of %s\n",
1045                 AcpiGbl_DbMethodInfo.Pathname);
1046         }
1047     }
1048 
1049     AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
1050 }
1051 
1052 
1053 /*******************************************************************************
1054  *
1055  * FUNCTION:    AcpiDbMethodThread
1056  *
1057  * PARAMETERS:  Context             - Execution info segment
1058  *
1059  * RETURN:      None
1060  *
1061  * DESCRIPTION: Debugger execute thread.  Waits for a command line, then
1062  *              simply dispatches it.
1063  *
1064  ******************************************************************************/
1065 
1066 static void ACPI_SYSTEM_XFACE
1067 AcpiDbMethodThread (
1068     void                    *Context)
1069 {
1070     ACPI_STATUS             Status;
1071     ACPI_DB_METHOD_INFO     *Info = Context;
1072     ACPI_DB_METHOD_INFO     LocalInfo;
1073     UINT32                  i;
1074     UINT8                   Allow;
1075     ACPI_BUFFER             ReturnObj;
1076 
1077 
1078     /*
1079      * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments.
1080      * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads
1081      * concurrently.
1082      *
1083      * Note: The arguments we are passing are used by the ASL test suite
1084      * (aslts). Do not change them without updating the tests.
1085      */
1086     (void) AcpiOsWaitSemaphore (Info->InfoGate, 1, ACPI_WAIT_FOREVER);
1087 
1088     if (Info->InitArgs)
1089     {
1090         AcpiDbUint32ToHexString (Info->NumCreated, Info->IndexOfThreadStr);
1091         AcpiDbUint32ToHexString ((UINT32) AcpiOsGetThreadId (), Info->IdOfThreadStr);
1092     }
1093 
1094     if (Info->Threads && (Info->NumCreated < Info->NumThreads))
1095     {
1096         Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId();
1097     }
1098 
1099     LocalInfo = *Info;
1100     LocalInfo.Args = LocalInfo.Arguments;
1101     LocalInfo.Arguments[0] = LocalInfo.NumThreadsStr;
1102     LocalInfo.Arguments[1] = LocalInfo.IdOfThreadStr;
1103     LocalInfo.Arguments[2] = LocalInfo.IndexOfThreadStr;
1104     LocalInfo.Arguments[3] = NULL;
1105 
1106     LocalInfo.Types = LocalInfo.ArgTypes;
1107 
1108     (void) AcpiOsSignalSemaphore (Info->InfoGate, 1);
1109 
1110     for (i = 0; i < Info->NumLoops; i++)
1111     {
1112         Status = AcpiDbExecuteMethod (&LocalInfo, &ReturnObj);
1113         if (ACPI_FAILURE (Status))
1114         {
1115             AcpiOsPrintf ("%s During evaluation of %s at iteration %X\n",
1116                 AcpiFormatException (Status), Info->Pathname, i);
1117             if (Status == AE_ABORT_METHOD)
1118             {
1119                 break;
1120             }
1121         }
1122 
1123 #if 0
1124         if ((i % 100) == 0)
1125         {
1126             AcpiOsPrintf ("%u loops, Thread 0x%x\n", i, AcpiOsGetThreadId ());
1127         }
1128 
1129         if (ReturnObj.Length)
1130         {
1131             AcpiOsPrintf ("Evaluation of %s returned object %p Buflen %X\n",
1132                 Info->Pathname, ReturnObj.Pointer, (UINT32) ReturnObj.Length);
1133             AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
1134         }
1135 #endif
1136     }
1137 
1138     /* Signal our completion */
1139 
1140     Allow = 0;
1141     (void) AcpiOsWaitSemaphore (Info->ThreadCompleteGate, 1, ACPI_WAIT_FOREVER);
1142     Info->NumCompleted++;
1143 
1144     if (Info->NumCompleted == Info->NumThreads)
1145     {
1146         /* Do signal for main thread once only */
1147         Allow = 1;
1148     }
1149 
1150     (void) AcpiOsSignalSemaphore (Info->ThreadCompleteGate, 1);
1151 
1152     if (Allow)
1153     {
1154         Status = AcpiOsSignalSemaphore (Info->MainThreadGate, 1);
1155         if (ACPI_FAILURE (Status))
1156         {
1157             AcpiOsPrintf ("Could not signal debugger thread sync semaphore, %s\n",
1158                 AcpiFormatException (Status));
1159         }
1160     }
1161 }
1162 
1163 
1164 /*******************************************************************************
1165  *
1166  * FUNCTION:    AcpiDbCreateExecutionThreads
1167  *
1168  * PARAMETERS:  NumThreadsArg           - Number of threads to create
1169  *              NumLoopsArg             - Loop count for the thread(s)
1170  *              MethodNameArg           - Control method to execute
1171  *
1172  * RETURN:      None
1173  *
1174  * DESCRIPTION: Create threads to execute method(s)
1175  *
1176  ******************************************************************************/
1177 
1178 void
1179 AcpiDbCreateExecutionThreads (
1180     char                    *NumThreadsArg,
1181     char                    *NumLoopsArg,
1182     char                    *MethodNameArg)
1183 {
1184     ACPI_STATUS             Status;
1185     UINT32                  NumThreads;
1186     UINT32                  NumLoops;
1187     UINT32                  i;
1188     UINT32                  Size;
1189     ACPI_MUTEX              MainThreadGate;
1190     ACPI_MUTEX              ThreadCompleteGate;
1191     ACPI_MUTEX              InfoGate;
1192 
1193 
1194     /* Get the arguments */
1195 
1196     NumThreads = ACPI_STRTOUL (NumThreadsArg, NULL, 0);
1197     NumLoops   = ACPI_STRTOUL (NumLoopsArg, NULL, 0);
1198 
1199     if (!NumThreads || !NumLoops)
1200     {
1201         AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n",
1202             NumThreads, NumLoops);
1203         return;
1204     }
1205 
1206     /*
1207      * Create the semaphore for synchronization of
1208      * the created threads with the main thread.
1209      */
1210     Status = AcpiOsCreateSemaphore (1, 0, &MainThreadGate);
1211     if (ACPI_FAILURE (Status))
1212     {
1213         AcpiOsPrintf ("Could not create semaphore for synchronization with the main thread, %s\n",
1214             AcpiFormatException (Status));
1215         return;
1216     }
1217 
1218     /*
1219      * Create the semaphore for synchronization
1220      * between the created threads.
1221      */
1222     Status = AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate);
1223     if (ACPI_FAILURE (Status))
1224     {
1225         AcpiOsPrintf ("Could not create semaphore for synchronization between the created threads, %s\n",
1226             AcpiFormatException (Status));
1227         (void) AcpiOsDeleteSemaphore (MainThreadGate);
1228         return;
1229     }
1230 
1231     Status = AcpiOsCreateSemaphore (1, 1, &InfoGate);
1232     if (ACPI_FAILURE (Status))
1233     {
1234         AcpiOsPrintf ("Could not create semaphore for synchronization of AcpiGbl_DbMethodInfo, %s\n",
1235             AcpiFormatException (Status));
1236         (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
1237         (void) AcpiOsDeleteSemaphore (MainThreadGate);
1238         return;
1239     }
1240 
1241     ACPI_MEMSET (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
1242 
1243     /* Array to store IDs of threads */
1244 
1245     AcpiGbl_DbMethodInfo.NumThreads = NumThreads;
1246     Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads;
1247     AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size);
1248     if (AcpiGbl_DbMethodInfo.Threads == NULL)
1249     {
1250         AcpiOsPrintf ("No memory for thread IDs array\n");
1251         (void) AcpiOsDeleteSemaphore (MainThreadGate);
1252         (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
1253         (void) AcpiOsDeleteSemaphore (InfoGate);
1254         return;
1255     }
1256     ACPI_MEMSET (AcpiGbl_DbMethodInfo.Threads, 0, Size);
1257 
1258     /* Setup the context to be passed to each thread */
1259 
1260     AcpiGbl_DbMethodInfo.Name = MethodNameArg;
1261     AcpiGbl_DbMethodInfo.Flags = 0;
1262     AcpiGbl_DbMethodInfo.NumLoops = NumLoops;
1263     AcpiGbl_DbMethodInfo.MainThreadGate = MainThreadGate;
1264     AcpiGbl_DbMethodInfo.ThreadCompleteGate = ThreadCompleteGate;
1265     AcpiGbl_DbMethodInfo.InfoGate = InfoGate;
1266 
1267     /* Init arguments to be passed to method */
1268 
1269     AcpiGbl_DbMethodInfo.InitArgs = 1;
1270     AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments;
1271     AcpiGbl_DbMethodInfo.Arguments[0] = AcpiGbl_DbMethodInfo.NumThreadsStr;
1272     AcpiGbl_DbMethodInfo.Arguments[1] = AcpiGbl_DbMethodInfo.IdOfThreadStr;
1273     AcpiGbl_DbMethodInfo.Arguments[2] = AcpiGbl_DbMethodInfo.IndexOfThreadStr;
1274     AcpiGbl_DbMethodInfo.Arguments[3] = NULL;
1275 
1276     AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes;
1277     AcpiGbl_DbMethodInfo.ArgTypes[0] = ACPI_TYPE_INTEGER;
1278     AcpiGbl_DbMethodInfo.ArgTypes[1] = ACPI_TYPE_INTEGER;
1279     AcpiGbl_DbMethodInfo.ArgTypes[2] = ACPI_TYPE_INTEGER;
1280 
1281     AcpiDbUint32ToHexString (NumThreads, AcpiGbl_DbMethodInfo.NumThreadsStr);
1282 
1283     AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
1284 
1285     /* Get the NS node, determines existence also */
1286 
1287     Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
1288         &AcpiGbl_DbMethodInfo.Method);
1289     if (ACPI_FAILURE (Status))
1290     {
1291         AcpiOsPrintf ("%s Could not get handle for %s\n",
1292             AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname);
1293         goto CleanupAndExit;
1294     }
1295 
1296     /* Create the threads */
1297 
1298     AcpiOsPrintf ("Creating %X threads to execute %X times each\n",
1299         NumThreads, NumLoops);
1300 
1301     for (i = 0; i < (NumThreads); i++)
1302     {
1303         Status = AcpiOsExecute (OSL_DEBUGGER_THREAD, AcpiDbMethodThread,
1304             &AcpiGbl_DbMethodInfo);
1305         if (ACPI_FAILURE (Status))
1306         {
1307             break;
1308         }
1309     }
1310 
1311     /* Wait for all threads to complete */
1312 
1313     (void) AcpiOsWaitSemaphore (MainThreadGate, 1, ACPI_WAIT_FOREVER);
1314 
1315     AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
1316     AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads);
1317     AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
1318 
1319 CleanupAndExit:
1320 
1321     /* Cleanup and exit */
1322 
1323     (void) AcpiOsDeleteSemaphore (MainThreadGate);
1324     (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
1325     (void) AcpiOsDeleteSemaphore (InfoGate);
1326 
1327     AcpiOsFree (AcpiGbl_DbMethodInfo.Threads);
1328     AcpiGbl_DbMethodInfo.Threads = NULL;
1329 }
1330 
1331 #endif /* ACPI_DEBUGGER */
1332 
1333 
1334