dbexec.c revision 1.1.1.19 1 /*******************************************************************************
2 *
3 * Module Name: dbexec - debugger control method execution
4 *
5 ******************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acdebug.h"
47 #include "acnamesp.h"
48
49
50 #define _COMPONENT ACPI_CA_DEBUGGER
51 ACPI_MODULE_NAME ("dbexec")
52
53
54 static ACPI_DB_METHOD_INFO AcpiGbl_DbMethodInfo;
55
56 /* Local prototypes */
57
58 static ACPI_STATUS
59 AcpiDbExecuteMethod (
60 ACPI_DB_METHOD_INFO *Info,
61 ACPI_BUFFER *ReturnObj);
62
63 static ACPI_STATUS
64 AcpiDbExecuteSetup (
65 ACPI_DB_METHOD_INFO *Info);
66
67 static UINT32
68 AcpiDbGetOutstandingAllocations (
69 void);
70
71 static void ACPI_SYSTEM_XFACE
72 AcpiDbMethodThread (
73 void *Context);
74
75 static ACPI_STATUS
76 AcpiDbExecutionWalk (
77 ACPI_HANDLE ObjHandle,
78 UINT32 NestingLevel,
79 void *Context,
80 void **ReturnValue);
81
82 static void ACPI_SYSTEM_XFACE
83 AcpiDbSingleExecutionThread (
84 void *Context);
85
86
87 /*******************************************************************************
88 *
89 * FUNCTION: AcpiDbDeleteObjects
90 *
91 * PARAMETERS: Count - Count of objects in the list
92 * Objects - Array of ACPI_OBJECTs to be deleted
93 *
94 * RETURN: None
95 *
96 * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
97 * packages via recursion.
98 *
99 ******************************************************************************/
100
101 void
102 AcpiDbDeleteObjects (
103 UINT32 Count,
104 ACPI_OBJECT *Objects)
105 {
106 UINT32 i;
107
108
109 for (i = 0; i < Count; i++)
110 {
111 switch (Objects[i].Type)
112 {
113 case ACPI_TYPE_BUFFER:
114
115 ACPI_FREE (Objects[i].Buffer.Pointer);
116 break;
117
118 case ACPI_TYPE_PACKAGE:
119
120 /* Recursive call to delete package elements */
121
122 AcpiDbDeleteObjects (Objects[i].Package.Count,
123 Objects[i].Package.Elements);
124
125 /* Free the elements array */
126
127 ACPI_FREE (Objects[i].Package.Elements);
128 break;
129
130 default:
131
132 break;
133 }
134 }
135 }
136
137
138 /*******************************************************************************
139 *
140 * FUNCTION: AcpiDbExecuteMethod
141 *
142 * PARAMETERS: Info - Valid info segment
143 * ReturnObj - Where to put return object
144 *
145 * RETURN: Status
146 *
147 * DESCRIPTION: Execute a control method. Used to evaluate objects via the
148 * "EXECUTE" or "EVALUATE" commands.
149 *
150 ******************************************************************************/
151
152 static ACPI_STATUS
153 AcpiDbExecuteMethod (
154 ACPI_DB_METHOD_INFO *Info,
155 ACPI_BUFFER *ReturnObj)
156 {
157 ACPI_STATUS Status;
158 ACPI_OBJECT_LIST ParamObjects;
159 ACPI_OBJECT Params[ACPI_DEBUGGER_MAX_ARGS + 1];
160 UINT32 i;
161
162
163 ACPI_FUNCTION_TRACE (DbExecuteMethod);
164
165
166 if (AcpiGbl_DbOutputToFile && !AcpiDbgLevel)
167 {
168 AcpiOsPrintf ("Warning: debug output is not enabled!\n");
169 }
170
171 ParamObjects.Count = 0;
172 ParamObjects.Pointer = NULL;
173
174 /* Pass through any command-line arguments */
175
176 if (Info->Args && Info->Args[0])
177 {
178 /* Get arguments passed on the command line */
179
180 for (i = 0; (Info->Args[i] && *(Info->Args[i])); i++)
181 {
182 /* Convert input string (token) to an actual ACPI_OBJECT */
183
184 Status = AcpiDbConvertToObject (Info->Types[i],
185 Info->Args[i], &Params[i]);
186 if (ACPI_FAILURE (Status))
187 {
188 ACPI_EXCEPTION ((AE_INFO, Status,
189 "While parsing method arguments"));
190 goto Cleanup;
191 }
192 }
193
194 ParamObjects.Count = i;
195 ParamObjects.Pointer = Params;
196 }
197
198 /* Prepare for a return object of arbitrary size */
199
200 ReturnObj->Pointer = AcpiGbl_DbBuffer;
201 ReturnObj->Length = ACPI_DEBUG_BUFFER_SIZE;
202
203 /* Do the actual method execution */
204
205 AcpiGbl_MethodExecuting = TRUE;
206 Status = AcpiEvaluateObject (NULL, Info->Pathname,
207 &ParamObjects, ReturnObj);
208
209 AcpiGbl_CmSingleStep = FALSE;
210 AcpiGbl_MethodExecuting = FALSE;
211
212 if (ACPI_FAILURE (Status))
213 {
214 if ((Status == AE_ABORT_METHOD) || AcpiGbl_AbortMethod)
215 {
216 /* Clear the abort and fall back to the debugger prompt */
217
218 ACPI_EXCEPTION ((AE_INFO, Status,
219 "Aborting top-level method"));
220
221 AcpiGbl_AbortMethod = FALSE;
222 Status = AE_OK;
223 goto Cleanup;
224 }
225
226 ACPI_EXCEPTION ((AE_INFO, Status,
227 "while executing %s from AML Debugger", Info->Pathname));
228
229 if (Status == AE_BUFFER_OVERFLOW)
230 {
231 ACPI_ERROR ((AE_INFO,
232 "Possible buffer overflow within AML Debugger "
233 "buffer (size 0x%X needed 0x%X)",
234 ACPI_DEBUG_BUFFER_SIZE, (UINT32) ReturnObj->Length));
235 }
236 }
237
238 Cleanup:
239 AcpiDbDeleteObjects (ParamObjects.Count, Params);
240 return_ACPI_STATUS (Status);
241 }
242
243
244 /*******************************************************************************
245 *
246 * FUNCTION: AcpiDbExecuteSetup
247 *
248 * PARAMETERS: Info - Valid method info
249 *
250 * RETURN: None
251 *
252 * DESCRIPTION: Setup info segment prior to method execution
253 *
254 ******************************************************************************/
255
256 static ACPI_STATUS
257 AcpiDbExecuteSetup (
258 ACPI_DB_METHOD_INFO *Info)
259 {
260 ACPI_STATUS Status;
261
262
263 ACPI_FUNCTION_NAME (DbExecuteSetup);
264
265
266 /* Concatenate the current scope to the supplied name */
267
268 Info->Pathname[0] = 0;
269 if ((Info->Name[0] != '\\') &&
270 (Info->Name[0] != '/'))
271 {
272 if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname),
273 AcpiGbl_DbScopeBuf))
274 {
275 Status = AE_BUFFER_OVERFLOW;
276 goto ErrorExit;
277 }
278 }
279
280 if (AcpiUtSafeStrcat (Info->Pathname, sizeof (Info->Pathname),
281 Info->Name))
282 {
283 Status = AE_BUFFER_OVERFLOW;
284 goto ErrorExit;
285 }
286
287 AcpiDbPrepNamestring (Info->Pathname);
288
289 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
290 AcpiOsPrintf ("Evaluating %s\n", Info->Pathname);
291
292 if (Info->Flags & EX_SINGLE_STEP)
293 {
294 AcpiGbl_CmSingleStep = TRUE;
295 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
296 }
297
298 else
299 {
300 /* No single step, allow redirection to a file */
301
302 AcpiDbSetOutputDestination (ACPI_DB_REDIRECTABLE_OUTPUT);
303 }
304
305 return (AE_OK);
306
307 ErrorExit:
308
309 ACPI_EXCEPTION ((AE_INFO, Status, "During setup for method execution"));
310 return (Status);
311 }
312
313
314 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
315 UINT32
316 AcpiDbGetCacheInfo (
317 ACPI_MEMORY_LIST *Cache)
318 {
319
320 return (Cache->TotalAllocated - Cache->TotalFreed - Cache->CurrentDepth);
321 }
322 #endif
323
324 /*******************************************************************************
325 *
326 * FUNCTION: AcpiDbGetOutstandingAllocations
327 *
328 * PARAMETERS: None
329 *
330 * RETURN: Current global allocation count minus cache entries
331 *
332 * DESCRIPTION: Determine the current number of "outstanding" allocations --
333 * those allocations that have not been freed and also are not
334 * in one of the various object caches.
335 *
336 ******************************************************************************/
337
338 static UINT32
339 AcpiDbGetOutstandingAllocations (
340 void)
341 {
342 UINT32 Outstanding = 0;
343
344 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
345
346 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_StateCache);
347 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeCache);
348 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeExtCache);
349 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_OperandCache);
350 #endif
351
352 return (Outstanding);
353 }
354
355
356 /*******************************************************************************
357 *
358 * FUNCTION: AcpiDbExecutionWalk
359 *
360 * PARAMETERS: WALK_CALLBACK
361 *
362 * RETURN: Status
363 *
364 * DESCRIPTION: Execute a control method. Name is relative to the current
365 * scope.
366 *
367 ******************************************************************************/
368
369 static ACPI_STATUS
370 AcpiDbExecutionWalk (
371 ACPI_HANDLE ObjHandle,
372 UINT32 NestingLevel,
373 void *Context,
374 void **ReturnValue)
375 {
376 ACPI_OPERAND_OBJECT *ObjDesc;
377 ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
378 ACPI_BUFFER ReturnObj;
379 ACPI_STATUS Status;
380
381
382 ObjDesc = AcpiNsGetAttachedObject (Node);
383 if (ObjDesc->Method.ParamCount)
384 {
385 return (AE_OK);
386 }
387
388 ReturnObj.Pointer = NULL;
389 ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
390
391 AcpiNsPrintNodePathname (Node, "Evaluating");
392
393 /* Do the actual method execution */
394
395 AcpiOsPrintf ("\n");
396 AcpiGbl_MethodExecuting = TRUE;
397
398 Status = AcpiEvaluateObject (Node, NULL, NULL, &ReturnObj);
399
400 AcpiGbl_MethodExecuting = FALSE;
401
402 AcpiOsPrintf ("Evaluation of [%4.4s] returned %s\n",
403 AcpiUtGetNodeName (Node),
404 AcpiFormatException (Status));
405
406 return (AE_OK);
407 }
408
409
410 /*******************************************************************************
411 *
412 * FUNCTION: AcpiDbExecute
413 *
414 * PARAMETERS: Name - Name of method to execute
415 * Args - Parameters to the method
416 * Types -
417 * Flags - single step/no single step
418 *
419 * RETURN: None
420 *
421 * DESCRIPTION: Execute a control method. Name is relative to the current
422 * scope. Function used for the "EXECUTE", "EVALUATE", and
423 * "ALL" commands
424 *
425 ******************************************************************************/
426
427 void
428 AcpiDbExecute (
429 char *Name,
430 char **Args,
431 ACPI_OBJECT_TYPE *Types,
432 UINT32 Flags)
433 {
434 ACPI_STATUS Status;
435 ACPI_BUFFER ReturnObj;
436 char *NameString;
437
438 #ifdef ACPI_DEBUG_OUTPUT
439 UINT32 PreviousAllocations;
440 UINT32 Allocations;
441 #endif
442
443
444 /*
445 * Allow one execution to be performed by debugger or single step
446 * execution will be dead locked by the interpreter mutexes.
447 */
448 if (AcpiGbl_MethodExecuting)
449 {
450 AcpiOsPrintf ("Only one debugger execution is allowed.\n");
451 return;
452 }
453
454 #ifdef ACPI_DEBUG_OUTPUT
455 /* Memory allocation tracking */
456
457 PreviousAllocations = AcpiDbGetOutstandingAllocations ();
458 #endif
459
460 if (*Name == '*')
461 {
462 (void) AcpiWalkNamespace (ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
463 ACPI_UINT32_MAX, AcpiDbExecutionWalk, NULL, NULL, NULL);
464 return;
465 }
466
467 if ((Flags & EX_ALL) && (strlen (Name) > 4))
468 {
469 AcpiOsPrintf ("Input name (%s) must be a 4-char NameSeg\n", Name);
470 return;
471 }
472
473 NameString = ACPI_ALLOCATE (strlen (Name) + 1);
474 if (!NameString)
475 {
476 return;
477 }
478
479 memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
480 strcpy (NameString, Name);
481 AcpiUtStrupr (NameString);
482
483 /* Subcommand to Execute all predefined names in the namespace */
484
485 if (!strncmp (NameString, "PREDEF", 6))
486 {
487 AcpiDbEvaluatePredefinedNames ();
488 ACPI_FREE (NameString);
489 return;
490 }
491
492 /* Command (ALL <nameseg>) to execute all methods of a particular name */
493
494 else if (Flags & EX_ALL)
495 {
496 AcpiGbl_DbMethodInfo.Name = NameString;
497 ReturnObj.Pointer = NULL;
498 ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
499 AcpiDbEvaluateAll (NameString);
500 ACPI_FREE (NameString);
501 return;
502 }
503 else
504 {
505 AcpiGbl_DbMethodInfo.Name = NameString;
506 AcpiGbl_DbMethodInfo.Args = Args;
507 AcpiGbl_DbMethodInfo.Types = Types;
508 AcpiGbl_DbMethodInfo.Flags = Flags;
509
510 ReturnObj.Pointer = NULL;
511 ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
512 }
513
514 Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
515 if (ACPI_FAILURE (Status))
516 {
517 ACPI_FREE (NameString);
518 return;
519 }
520
521 /* Get the NS node, determines existence also */
522
523 Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
524 &AcpiGbl_DbMethodInfo.Method);
525 if (ACPI_SUCCESS (Status))
526 {
527 Status = AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo,
528 &ReturnObj);
529 }
530 ACPI_FREE (NameString);
531
532 /*
533 * Allow any handlers in separate threads to complete.
534 * (Such as Notify handlers invoked from AML executed above).
535 */
536 AcpiOsSleep ((UINT64) 10);
537
538 #ifdef ACPI_DEBUG_OUTPUT
539
540 /* Memory allocation tracking */
541
542 Allocations = AcpiDbGetOutstandingAllocations () - PreviousAllocations;
543
544 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
545
546 if (Allocations > 0)
547 {
548 AcpiOsPrintf (
549 "0x%X Outstanding allocations after evaluation of %s\n",
550 Allocations, AcpiGbl_DbMethodInfo.Pathname);
551 }
552 #endif
553
554 if (ACPI_FAILURE (Status))
555 {
556 AcpiOsPrintf ("Evaluation of %s failed with status %s\n",
557 AcpiGbl_DbMethodInfo.Pathname,
558 AcpiFormatException (Status));
559 }
560 else
561 {
562 /* Display a return object, if any */
563
564 if (ReturnObj.Length)
565 {
566 AcpiOsPrintf (
567 "Evaluation of %s returned object %p, "
568 "external buffer length %X\n",
569 AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer,
570 (UINT32) ReturnObj.Length);
571
572 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
573 AcpiOsPrintf ("\n");
574
575 /* Dump a _PLD buffer if present */
576
577 if (ACPI_COMPARE_NAMESEG ((ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
578 AcpiGbl_DbMethodInfo.Method)->Name.Ascii),
579 METHOD_NAME__PLD))
580 {
581 AcpiDbDumpPldBuffer (ReturnObj.Pointer);
582 }
583 }
584 else
585 {
586 AcpiOsPrintf ("No object was returned from evaluation of %s\n",
587 AcpiGbl_DbMethodInfo.Pathname);
588 }
589 }
590
591 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
592 }
593
594
595 /*******************************************************************************
596 *
597 * FUNCTION: AcpiDbMethodThread
598 *
599 * PARAMETERS: Context - Execution info segment
600 *
601 * RETURN: None
602 *
603 * DESCRIPTION: Debugger execute thread. Waits for a command line, then
604 * simply dispatches it.
605 *
606 ******************************************************************************/
607
608 static void ACPI_SYSTEM_XFACE
609 AcpiDbMethodThread (
610 void *Context)
611 {
612 ACPI_STATUS Status;
613 ACPI_DB_METHOD_INFO *Info = Context;
614 ACPI_DB_METHOD_INFO LocalInfo;
615 UINT32 i;
616 UINT8 Allow;
617 ACPI_BUFFER ReturnObj;
618
619
620 /*
621 * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments.
622 * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads
623 * concurrently.
624 *
625 * Note: The arguments we are passing are used by the ASL test suite
626 * (aslts). Do not change them without updating the tests.
627 */
628 (void) AcpiOsWaitSemaphore (Info->InfoGate, 1, ACPI_WAIT_FOREVER);
629
630 if (Info->InitArgs)
631 {
632 AcpiDbUint32ToHexString (Info->NumCreated,
633 Info->IndexOfThreadStr);
634 AcpiDbUint32ToHexString ((UINT32) AcpiOsGetThreadId (),
635 Info->IdOfThreadStr);
636 }
637
638 if (Info->Threads && (Info->NumCreated < Info->NumThreads))
639 {
640 Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId();
641 }
642
643 LocalInfo = *Info;
644 LocalInfo.Args = LocalInfo.Arguments;
645 LocalInfo.Arguments[0] = LocalInfo.NumThreadsStr;
646 LocalInfo.Arguments[1] = LocalInfo.IdOfThreadStr;
647 LocalInfo.Arguments[2] = LocalInfo.IndexOfThreadStr;
648 LocalInfo.Arguments[3] = NULL;
649
650 LocalInfo.Types = LocalInfo.ArgTypes;
651
652 (void) AcpiOsSignalSemaphore (Info->InfoGate, 1);
653
654 for (i = 0; i < Info->NumLoops; i++)
655 {
656 Status = AcpiDbExecuteMethod (&LocalInfo, &ReturnObj);
657 if (ACPI_FAILURE (Status))
658 {
659 AcpiOsPrintf ("%s During evaluation of %s at iteration %X\n",
660 AcpiFormatException (Status), Info->Pathname, i);
661 if (Status == AE_ABORT_METHOD)
662 {
663 break;
664 }
665 }
666
667 #if 0
668 if ((i % 100) == 0)
669 {
670 AcpiOsPrintf ("%u loops, Thread 0x%x\n",
671 i, AcpiOsGetThreadId ());
672 }
673
674 if (ReturnObj.Length)
675 {
676 AcpiOsPrintf ("Evaluation of %s returned object %p Buflen %X\n",
677 Info->Pathname, ReturnObj.Pointer,
678 (UINT32) ReturnObj.Length);
679 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
680 }
681 #endif
682 }
683
684 /* Signal our completion */
685
686 Allow = 0;
687 (void) AcpiOsWaitSemaphore (Info->ThreadCompleteGate,
688 1, ACPI_WAIT_FOREVER);
689 Info->NumCompleted++;
690
691 if (Info->NumCompleted == Info->NumThreads)
692 {
693 /* Do signal for main thread once only */
694 Allow = 1;
695 }
696
697 (void) AcpiOsSignalSemaphore (Info->ThreadCompleteGate, 1);
698
699 if (Allow)
700 {
701 Status = AcpiOsSignalSemaphore (Info->MainThreadGate, 1);
702 if (ACPI_FAILURE (Status))
703 {
704 AcpiOsPrintf (
705 "Could not signal debugger thread sync semaphore, %s\n",
706 AcpiFormatException (Status));
707 }
708 }
709 }
710
711
712 /*******************************************************************************
713 *
714 * FUNCTION: AcpiDbSingleExecutionThread
715 *
716 * PARAMETERS: Context - Method info struct
717 *
718 * RETURN: None
719 *
720 * DESCRIPTION: Create one thread and execute a method
721 *
722 ******************************************************************************/
723
724 static void ACPI_SYSTEM_XFACE
725 AcpiDbSingleExecutionThread (
726 void *Context)
727 {
728 ACPI_DB_METHOD_INFO *Info = Context;
729 ACPI_STATUS Status;
730 ACPI_BUFFER ReturnObj;
731
732
733 AcpiOsPrintf ("\n");
734
735 Status = AcpiDbExecuteMethod (Info, &ReturnObj);
736 if (ACPI_FAILURE (Status))
737 {
738 AcpiOsPrintf ("%s During evaluation of %s\n",
739 AcpiFormatException (Status), Info->Pathname);
740 return;
741 }
742
743 /* Display a return object, if any */
744
745 if (ReturnObj.Length)
746 {
747 AcpiOsPrintf ("Evaluation of %s returned object %p, "
748 "external buffer length %X\n",
749 AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer,
750 (UINT32) ReturnObj.Length);
751
752 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
753 }
754
755 AcpiOsPrintf ("\nBackground thread completed\n%c ",
756 ACPI_DEBUGGER_COMMAND_PROMPT);
757 }
758
759
760 /*******************************************************************************
761 *
762 * FUNCTION: AcpiDbCreateExecutionThread
763 *
764 * PARAMETERS: MethodNameArg - Control method to execute
765 * Arguments - Array of arguments to the method
766 * Types - Corresponding array of object types
767 *
768 * RETURN: None
769 *
770 * DESCRIPTION: Create a single thread to evaluate a namespace object. Handles
771 * arguments passed on command line for control methods.
772 *
773 ******************************************************************************/
774
775 void
776 AcpiDbCreateExecutionThread (
777 char *MethodNameArg,
778 char **Arguments,
779 ACPI_OBJECT_TYPE *Types)
780 {
781 ACPI_STATUS Status;
782 UINT32 i;
783
784
785 memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
786 AcpiGbl_DbMethodInfo.Name = MethodNameArg;
787 AcpiGbl_DbMethodInfo.InitArgs = 1;
788 AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments;
789 AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes;
790
791 /* Setup method arguments, up to 7 (0-6) */
792
793 for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && *Arguments; i++)
794 {
795 AcpiGbl_DbMethodInfo.Arguments[i] = *Arguments;
796 Arguments++;
797
798 AcpiGbl_DbMethodInfo.ArgTypes[i] = *Types;
799 Types++;
800 }
801
802 Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
803 if (ACPI_FAILURE (Status))
804 {
805 return;
806 }
807
808 /* Get the NS node, determines existence also */
809
810 Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
811 &AcpiGbl_DbMethodInfo.Method);
812 if (ACPI_FAILURE (Status))
813 {
814 AcpiOsPrintf ("%s Could not get handle for %s\n",
815 AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname);
816 return;
817 }
818
819 Status = AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD,
820 AcpiDbSingleExecutionThread, &AcpiGbl_DbMethodInfo);
821 if (ACPI_FAILURE (Status))
822 {
823 return;
824 }
825
826 AcpiOsPrintf ("\nBackground thread started\n");
827 }
828
829
830 /*******************************************************************************
831 *
832 * FUNCTION: AcpiDbCreateExecutionThreads
833 *
834 * PARAMETERS: NumThreadsArg - Number of threads to create
835 * NumLoopsArg - Loop count for the thread(s)
836 * MethodNameArg - Control method to execute
837 *
838 * RETURN: None
839 *
840 * DESCRIPTION: Create threads to execute method(s)
841 *
842 ******************************************************************************/
843
844 void
845 AcpiDbCreateExecutionThreads (
846 char *NumThreadsArg,
847 char *NumLoopsArg,
848 char *MethodNameArg)
849 {
850 ACPI_STATUS Status;
851 UINT32 NumThreads;
852 UINT32 NumLoops;
853 UINT32 i;
854 UINT32 Size;
855 ACPI_MUTEX MainThreadGate;
856 ACPI_MUTEX ThreadCompleteGate;
857 ACPI_MUTEX InfoGate;
858
859
860 /* Get the arguments */
861
862 NumThreads = strtoul (NumThreadsArg, NULL, 0);
863 NumLoops = strtoul (NumLoopsArg, NULL, 0);
864
865 if (!NumThreads || !NumLoops)
866 {
867 AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n",
868 NumThreads, NumLoops);
869 return;
870 }
871
872 /*
873 * Create the semaphore for synchronization of
874 * the created threads with the main thread.
875 */
876 Status = AcpiOsCreateSemaphore (1, 0, &MainThreadGate);
877 if (ACPI_FAILURE (Status))
878 {
879 AcpiOsPrintf ("Could not create semaphore for "
880 "synchronization with the main thread, %s\n",
881 AcpiFormatException (Status));
882 return;
883 }
884
885 /*
886 * Create the semaphore for synchronization
887 * between the created threads.
888 */
889 Status = AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate);
890 if (ACPI_FAILURE (Status))
891 {
892 AcpiOsPrintf ("Could not create semaphore for "
893 "synchronization between the created threads, %s\n",
894 AcpiFormatException (Status));
895
896 (void) AcpiOsDeleteSemaphore (MainThreadGate);
897 return;
898 }
899
900 Status = AcpiOsCreateSemaphore (1, 1, &InfoGate);
901 if (ACPI_FAILURE (Status))
902 {
903 AcpiOsPrintf ("Could not create semaphore for "
904 "synchronization of AcpiGbl_DbMethodInfo, %s\n",
905 AcpiFormatException (Status));
906
907 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
908 (void) AcpiOsDeleteSemaphore (MainThreadGate);
909 return;
910 }
911
912 memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
913
914 /* Array to store IDs of threads */
915
916 AcpiGbl_DbMethodInfo.NumThreads = NumThreads;
917 Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads;
918
919 AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size);
920 if (AcpiGbl_DbMethodInfo.Threads == NULL)
921 {
922 AcpiOsPrintf ("No memory for thread IDs array\n");
923 (void) AcpiOsDeleteSemaphore (MainThreadGate);
924 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
925 (void) AcpiOsDeleteSemaphore (InfoGate);
926 return;
927 }
928 memset (AcpiGbl_DbMethodInfo.Threads, 0, Size);
929
930 /* Setup the context to be passed to each thread */
931
932 AcpiGbl_DbMethodInfo.Name = MethodNameArg;
933 AcpiGbl_DbMethodInfo.Flags = 0;
934 AcpiGbl_DbMethodInfo.NumLoops = NumLoops;
935 AcpiGbl_DbMethodInfo.MainThreadGate = MainThreadGate;
936 AcpiGbl_DbMethodInfo.ThreadCompleteGate = ThreadCompleteGate;
937 AcpiGbl_DbMethodInfo.InfoGate = InfoGate;
938
939 /* Init arguments to be passed to method */
940
941 AcpiGbl_DbMethodInfo.InitArgs = 1;
942 AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments;
943 AcpiGbl_DbMethodInfo.Arguments[0] = AcpiGbl_DbMethodInfo.NumThreadsStr;
944 AcpiGbl_DbMethodInfo.Arguments[1] = AcpiGbl_DbMethodInfo.IdOfThreadStr;
945 AcpiGbl_DbMethodInfo.Arguments[2] = AcpiGbl_DbMethodInfo.IndexOfThreadStr;
946 AcpiGbl_DbMethodInfo.Arguments[3] = NULL;
947
948 AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes;
949 AcpiGbl_DbMethodInfo.ArgTypes[0] = ACPI_TYPE_INTEGER;
950 AcpiGbl_DbMethodInfo.ArgTypes[1] = ACPI_TYPE_INTEGER;
951 AcpiGbl_DbMethodInfo.ArgTypes[2] = ACPI_TYPE_INTEGER;
952
953 AcpiDbUint32ToHexString (NumThreads, AcpiGbl_DbMethodInfo.NumThreadsStr);
954
955 Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
956 if (ACPI_FAILURE (Status))
957 {
958 goto CleanupAndExit;
959 }
960
961 /* Get the NS node, determines existence also */
962
963 Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
964 &AcpiGbl_DbMethodInfo.Method);
965 if (ACPI_FAILURE (Status))
966 {
967 AcpiOsPrintf ("%s Could not get handle for %s\n",
968 AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname);
969 goto CleanupAndExit;
970 }
971
972 /* Create the threads */
973
974 AcpiOsPrintf ("Creating %X threads to execute %X times each\n",
975 NumThreads, NumLoops);
976
977 for (i = 0; i < (NumThreads); i++)
978 {
979 Status = AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD, AcpiDbMethodThread,
980 &AcpiGbl_DbMethodInfo);
981 if (ACPI_FAILURE (Status))
982 {
983 break;
984 }
985 }
986
987 /* Wait for all threads to complete */
988
989 (void) AcpiOsWaitSemaphore (MainThreadGate, 1, ACPI_WAIT_FOREVER);
990
991 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
992 AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads);
993 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
994
995 CleanupAndExit:
996
997 /* Cleanup and exit */
998
999 (void) AcpiOsDeleteSemaphore (MainThreadGate);
1000 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
1001 (void) AcpiOsDeleteSemaphore (InfoGate);
1002
1003 AcpiOsFree (AcpiGbl_DbMethodInfo.Threads);
1004 AcpiGbl_DbMethodInfo.Threads = NULL;
1005 }
1006