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
AcpiDbDeleteObjects(UINT32 Count,ACPI_OBJECT * Objects)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
AcpiDbExecuteMethod(ACPI_DB_METHOD_INFO * Info,ACPI_BUFFER * ReturnObj)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
AcpiDbExecuteSetup(ACPI_DB_METHOD_INFO * Info)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
AcpiDbGetCacheInfo(ACPI_MEMORY_LIST * Cache)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 #ifdef ACPI_DEBUG_OUTPUT
339 static UINT32
AcpiDbGetOutstandingAllocations(void)340 AcpiDbGetOutstandingAllocations (
341 void)
342 {
343 UINT32 Outstanding = 0;
344
345 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
346
347 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_StateCache);
348 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeCache);
349 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_PsNodeExtCache);
350 Outstanding += AcpiDbGetCacheInfo (AcpiGbl_OperandCache);
351 #endif
352
353 return (Outstanding);
354 }
355 #endif
356
357
358 /*******************************************************************************
359 *
360 * FUNCTION: AcpiDbExecutionWalk
361 *
362 * PARAMETERS: WALK_CALLBACK
363 *
364 * RETURN: Status
365 *
366 * DESCRIPTION: Execute a control method. Name is relative to the current
367 * scope.
368 *
369 ******************************************************************************/
370
371 static ACPI_STATUS
AcpiDbExecutionWalk(ACPI_HANDLE ObjHandle,UINT32 NestingLevel,void * Context,void ** ReturnValue)372 AcpiDbExecutionWalk (
373 ACPI_HANDLE ObjHandle,
374 UINT32 NestingLevel,
375 void *Context,
376 void **ReturnValue)
377 {
378 ACPI_OPERAND_OBJECT *ObjDesc;
379 ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
380 ACPI_BUFFER ReturnObj;
381 ACPI_STATUS Status;
382
383
384 ObjDesc = AcpiNsGetAttachedObject (Node);
385 if (ObjDesc->Method.ParamCount)
386 {
387 return (AE_OK);
388 }
389
390 ReturnObj.Pointer = NULL;
391 ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
392
393 AcpiNsPrintNodePathname (Node, "Evaluating");
394
395 /* Do the actual method execution */
396
397 AcpiOsPrintf ("\n");
398 AcpiGbl_MethodExecuting = TRUE;
399
400 Status = AcpiEvaluateObject (Node, NULL, NULL, &ReturnObj);
401
402 AcpiGbl_MethodExecuting = FALSE;
403
404 AcpiOsPrintf ("Evaluation of [%4.4s] returned %s\n",
405 AcpiUtGetNodeName (Node),
406 AcpiFormatException (Status));
407
408 return (AE_OK);
409 }
410
411
412 /*******************************************************************************
413 *
414 * FUNCTION: AcpiDbExecute
415 *
416 * PARAMETERS: Name - Name of method to execute
417 * Args - Parameters to the method
418 * Types -
419 * Flags - single step/no single step
420 *
421 * RETURN: None
422 *
423 * DESCRIPTION: Execute a control method. Name is relative to the current
424 * scope. Function used for the "EXECUTE", "EVALUATE", and
425 * "ALL" commands
426 *
427 ******************************************************************************/
428
429 void
AcpiDbExecute(char * Name,char ** Args,ACPI_OBJECT_TYPE * Types,UINT32 Flags)430 AcpiDbExecute (
431 char *Name,
432 char **Args,
433 ACPI_OBJECT_TYPE *Types,
434 UINT32 Flags)
435 {
436 ACPI_STATUS Status;
437 ACPI_BUFFER ReturnObj;
438 char *NameString;
439
440 #ifdef ACPI_DEBUG_OUTPUT
441 UINT32 PreviousAllocations;
442 UINT32 Allocations;
443 #endif
444
445
446 /*
447 * Allow one execution to be performed by debugger or single step
448 * execution will be dead locked by the interpreter mutexes.
449 */
450 if (AcpiGbl_MethodExecuting)
451 {
452 AcpiOsPrintf ("Only one debugger execution is allowed.\n");
453 return;
454 }
455
456 #ifdef ACPI_DEBUG_OUTPUT
457 /* Memory allocation tracking */
458
459 PreviousAllocations = AcpiDbGetOutstandingAllocations ();
460 #endif
461
462 if (*Name == '*')
463 {
464 (void) AcpiWalkNamespace (ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
465 ACPI_UINT32_MAX, AcpiDbExecutionWalk, NULL, NULL, NULL);
466 return;
467 }
468
469 if ((Flags & EX_ALL) && (strlen (Name) > 4))
470 {
471 AcpiOsPrintf ("Input name (%s) must be a 4-char NameSeg\n", Name);
472 return;
473 }
474
475 NameString = ACPI_ALLOCATE (strlen (Name) + 1);
476 if (!NameString)
477 {
478 return;
479 }
480
481 memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
482 strcpy (NameString, Name);
483 AcpiUtStrupr (NameString);
484
485 /* Subcommand to Execute all predefined names in the namespace */
486
487 if (!strncmp (NameString, "PREDEF", 6))
488 {
489 AcpiDbEvaluatePredefinedNames ();
490 ACPI_FREE (NameString);
491 return;
492 }
493
494 /* Command (ALL <nameseg>) to execute all methods of a particular name */
495
496 else if (Flags & EX_ALL)
497 {
498 AcpiGbl_DbMethodInfo.Name = NameString;
499 ReturnObj.Pointer = NULL;
500 ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
501 AcpiDbEvaluateAll (NameString);
502 ACPI_FREE (NameString);
503 return;
504 }
505 else
506 {
507 AcpiGbl_DbMethodInfo.Name = NameString;
508 AcpiGbl_DbMethodInfo.Args = Args;
509 AcpiGbl_DbMethodInfo.Types = Types;
510 AcpiGbl_DbMethodInfo.Flags = Flags;
511
512 ReturnObj.Pointer = NULL;
513 ReturnObj.Length = ACPI_ALLOCATE_BUFFER;
514 }
515
516 Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
517 if (ACPI_FAILURE (Status))
518 {
519 ACPI_FREE (NameString);
520 return;
521 }
522
523 /* Get the NS node, determines existence also */
524
525 Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
526 &AcpiGbl_DbMethodInfo.Method);
527 if (ACPI_SUCCESS (Status))
528 {
529 Status = AcpiDbExecuteMethod (&AcpiGbl_DbMethodInfo,
530 &ReturnObj);
531 }
532 ACPI_FREE (NameString);
533
534 /*
535 * Allow any handlers in separate threads to complete.
536 * (Such as Notify handlers invoked from AML executed above).
537 */
538 AcpiOsSleep ((UINT64) 10);
539
540 #ifdef ACPI_DEBUG_OUTPUT
541
542 /* Memory allocation tracking */
543
544 Allocations = AcpiDbGetOutstandingAllocations () - PreviousAllocations;
545
546 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
547
548 if (Allocations > 0)
549 {
550 AcpiOsPrintf (
551 "0x%X Outstanding allocations after evaluation of %s\n",
552 Allocations, AcpiGbl_DbMethodInfo.Pathname);
553 }
554 #endif
555
556 if (ACPI_FAILURE (Status))
557 {
558 AcpiOsPrintf ("Evaluation of %s failed with status %s\n",
559 AcpiGbl_DbMethodInfo.Pathname,
560 AcpiFormatException (Status));
561 }
562 else
563 {
564 /* Display a return object, if any */
565
566 if (ReturnObj.Length)
567 {
568 AcpiOsPrintf (
569 "Evaluation of %s returned object %p, "
570 "external buffer length %X\n",
571 AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer,
572 (UINT32) ReturnObj.Length);
573
574 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
575 AcpiOsPrintf ("\n");
576
577 /* Dump a _PLD buffer if present */
578
579 if (ACPI_COMPARE_NAMESEG ((ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
580 AcpiGbl_DbMethodInfo.Method)->Name.Ascii),
581 METHOD_NAME__PLD))
582 {
583 AcpiDbDumpPldBuffer (ReturnObj.Pointer);
584 }
585 }
586 else
587 {
588 AcpiOsPrintf ("No object was returned from evaluation of %s\n",
589 AcpiGbl_DbMethodInfo.Pathname);
590 }
591 }
592
593 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
594 }
595
596
597 /*******************************************************************************
598 *
599 * FUNCTION: AcpiDbMethodThread
600 *
601 * PARAMETERS: Context - Execution info segment
602 *
603 * RETURN: None
604 *
605 * DESCRIPTION: Debugger execute thread. Waits for a command line, then
606 * simply dispatches it.
607 *
608 ******************************************************************************/
609
610 static void ACPI_SYSTEM_XFACE
AcpiDbMethodThread(void * Context)611 AcpiDbMethodThread (
612 void *Context)
613 {
614 ACPI_STATUS Status;
615 ACPI_DB_METHOD_INFO *Info = Context;
616 ACPI_DB_METHOD_INFO LocalInfo;
617 UINT32 i;
618 UINT8 Allow;
619 ACPI_BUFFER ReturnObj;
620
621
622 /*
623 * AcpiGbl_DbMethodInfo.Arguments will be passed as method arguments.
624 * Prevent AcpiGbl_DbMethodInfo from being modified by multiple threads
625 * concurrently.
626 *
627 * Note: The arguments we are passing are used by the ASL test suite
628 * (aslts). Do not change them without updating the tests.
629 */
630 (void) AcpiOsWaitSemaphore (Info->InfoGate, 1, ACPI_WAIT_FOREVER);
631
632 if (Info->InitArgs)
633 {
634 AcpiDbUint32ToHexString (Info->NumCreated,
635 Info->IndexOfThreadStr);
636 AcpiDbUint32ToHexString ((UINT32) AcpiOsGetThreadId (),
637 Info->IdOfThreadStr);
638 }
639
640 if (Info->Threads && (Info->NumCreated < Info->NumThreads))
641 {
642 Info->Threads[Info->NumCreated++] = AcpiOsGetThreadId();
643 }
644
645 LocalInfo = *Info;
646 LocalInfo.Args = LocalInfo.Arguments;
647 LocalInfo.Arguments[0] = LocalInfo.NumThreadsStr;
648 LocalInfo.Arguments[1] = LocalInfo.IdOfThreadStr;
649 LocalInfo.Arguments[2] = LocalInfo.IndexOfThreadStr;
650 LocalInfo.Arguments[3] = NULL;
651
652 LocalInfo.Types = LocalInfo.ArgTypes;
653
654 (void) AcpiOsSignalSemaphore (Info->InfoGate, 1);
655
656 for (i = 0; i < Info->NumLoops; i++)
657 {
658 Status = AcpiDbExecuteMethod (&LocalInfo, &ReturnObj);
659 if (ACPI_FAILURE (Status))
660 {
661 AcpiOsPrintf ("%s During evaluation of %s at iteration %X\n",
662 AcpiFormatException (Status), Info->Pathname, i);
663 if (Status == AE_ABORT_METHOD)
664 {
665 break;
666 }
667 }
668
669 #if 0
670 if ((i % 100) == 0)
671 {
672 AcpiOsPrintf ("%u loops, Thread 0x%x\n",
673 i, AcpiOsGetThreadId ());
674 }
675
676 if (ReturnObj.Length)
677 {
678 AcpiOsPrintf ("Evaluation of %s returned object %p Buflen %X\n",
679 Info->Pathname, ReturnObj.Pointer,
680 (UINT32) ReturnObj.Length);
681 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
682 }
683 #endif
684 }
685
686 /* Signal our completion */
687
688 Allow = 0;
689 (void) AcpiOsWaitSemaphore (Info->ThreadCompleteGate,
690 1, ACPI_WAIT_FOREVER);
691 Info->NumCompleted++;
692
693 if (Info->NumCompleted == Info->NumThreads)
694 {
695 /* Do signal for main thread once only */
696 Allow = 1;
697 }
698
699 (void) AcpiOsSignalSemaphore (Info->ThreadCompleteGate, 1);
700
701 if (Allow)
702 {
703 Status = AcpiOsSignalSemaphore (Info->MainThreadGate, 1);
704 if (ACPI_FAILURE (Status))
705 {
706 AcpiOsPrintf (
707 "Could not signal debugger thread sync semaphore, %s\n",
708 AcpiFormatException (Status));
709 }
710 }
711 }
712
713
714 /*******************************************************************************
715 *
716 * FUNCTION: AcpiDbSingleExecutionThread
717 *
718 * PARAMETERS: Context - Method info struct
719 *
720 * RETURN: None
721 *
722 * DESCRIPTION: Create one thread and execute a method
723 *
724 ******************************************************************************/
725
726 static void ACPI_SYSTEM_XFACE
AcpiDbSingleExecutionThread(void * Context)727 AcpiDbSingleExecutionThread (
728 void *Context)
729 {
730 ACPI_DB_METHOD_INFO *Info = Context;
731 ACPI_STATUS Status;
732 ACPI_BUFFER ReturnObj;
733
734
735 AcpiOsPrintf ("\n");
736
737 Status = AcpiDbExecuteMethod (Info, &ReturnObj);
738 if (ACPI_FAILURE (Status))
739 {
740 AcpiOsPrintf ("%s During evaluation of %s\n",
741 AcpiFormatException (Status), Info->Pathname);
742 return;
743 }
744
745 /* Display a return object, if any */
746
747 if (ReturnObj.Length)
748 {
749 AcpiOsPrintf ("Evaluation of %s returned object %p, "
750 "external buffer length %X\n",
751 AcpiGbl_DbMethodInfo.Pathname, ReturnObj.Pointer,
752 (UINT32) ReturnObj.Length);
753
754 AcpiDbDumpExternalObject (ReturnObj.Pointer, 1);
755 }
756
757 AcpiOsPrintf ("\nBackground thread completed\n%c ",
758 ACPI_DEBUGGER_COMMAND_PROMPT);
759 }
760
761
762 /*******************************************************************************
763 *
764 * FUNCTION: AcpiDbCreateExecutionThread
765 *
766 * PARAMETERS: MethodNameArg - Control method to execute
767 * Arguments - Array of arguments to the method
768 * Types - Corresponding array of object types
769 *
770 * RETURN: None
771 *
772 * DESCRIPTION: Create a single thread to evaluate a namespace object. Handles
773 * arguments passed on command line for control methods.
774 *
775 ******************************************************************************/
776
777 void
AcpiDbCreateExecutionThread(char * MethodNameArg,char ** Arguments,ACPI_OBJECT_TYPE * Types)778 AcpiDbCreateExecutionThread (
779 char *MethodNameArg,
780 char **Arguments,
781 ACPI_OBJECT_TYPE *Types)
782 {
783 ACPI_STATUS Status;
784 UINT32 i;
785
786
787 memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
788 AcpiGbl_DbMethodInfo.Name = MethodNameArg;
789 AcpiGbl_DbMethodInfo.InitArgs = 1;
790 AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments;
791 AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes;
792
793 /* Setup method arguments, up to 7 (0-6) */
794
795 for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && *Arguments; i++)
796 {
797 AcpiGbl_DbMethodInfo.Arguments[i] = *Arguments;
798 Arguments++;
799
800 AcpiGbl_DbMethodInfo.ArgTypes[i] = *Types;
801 Types++;
802 }
803
804 Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
805 if (ACPI_FAILURE (Status))
806 {
807 return;
808 }
809
810 /* Get the NS node, determines existence also */
811
812 Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
813 &AcpiGbl_DbMethodInfo.Method);
814 if (ACPI_FAILURE (Status))
815 {
816 AcpiOsPrintf ("%s Could not get handle for %s\n",
817 AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname);
818 return;
819 }
820
821 Status = AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD,
822 AcpiDbSingleExecutionThread, &AcpiGbl_DbMethodInfo);
823 if (ACPI_FAILURE (Status))
824 {
825 return;
826 }
827
828 AcpiOsPrintf ("\nBackground thread started\n");
829 }
830
831
832 /*******************************************************************************
833 *
834 * FUNCTION: AcpiDbCreateExecutionThreads
835 *
836 * PARAMETERS: NumThreadsArg - Number of threads to create
837 * NumLoopsArg - Loop count for the thread(s)
838 * MethodNameArg - Control method to execute
839 *
840 * RETURN: None
841 *
842 * DESCRIPTION: Create threads to execute method(s)
843 *
844 ******************************************************************************/
845
846 void
AcpiDbCreateExecutionThreads(char * NumThreadsArg,char * NumLoopsArg,char * MethodNameArg)847 AcpiDbCreateExecutionThreads (
848 char *NumThreadsArg,
849 char *NumLoopsArg,
850 char *MethodNameArg)
851 {
852 ACPI_STATUS Status;
853 UINT32 NumThreads;
854 UINT32 NumLoops;
855 UINT32 i;
856 UINT32 Size;
857 ACPI_MUTEX MainThreadGate;
858 ACPI_MUTEX ThreadCompleteGate;
859 ACPI_MUTEX InfoGate;
860
861
862 /* Get the arguments */
863
864 NumThreads = strtoul (NumThreadsArg, NULL, 0);
865 NumLoops = strtoul (NumLoopsArg, NULL, 0);
866
867 if (!NumThreads || !NumLoops)
868 {
869 AcpiOsPrintf ("Bad argument: Threads %X, Loops %X\n",
870 NumThreads, NumLoops);
871 return;
872 }
873
874 /*
875 * Create the semaphore for synchronization of
876 * the created threads with the main thread.
877 */
878 Status = AcpiOsCreateSemaphore (1, 0, &MainThreadGate);
879 if (ACPI_FAILURE (Status))
880 {
881 AcpiOsPrintf ("Could not create semaphore for "
882 "synchronization with the main thread, %s\n",
883 AcpiFormatException (Status));
884 return;
885 }
886
887 /*
888 * Create the semaphore for synchronization
889 * between the created threads.
890 */
891 Status = AcpiOsCreateSemaphore (1, 1, &ThreadCompleteGate);
892 if (ACPI_FAILURE (Status))
893 {
894 AcpiOsPrintf ("Could not create semaphore for "
895 "synchronization between the created threads, %s\n",
896 AcpiFormatException (Status));
897
898 (void) AcpiOsDeleteSemaphore (MainThreadGate);
899 return;
900 }
901
902 Status = AcpiOsCreateSemaphore (1, 1, &InfoGate);
903 if (ACPI_FAILURE (Status))
904 {
905 AcpiOsPrintf ("Could not create semaphore for "
906 "synchronization of AcpiGbl_DbMethodInfo, %s\n",
907 AcpiFormatException (Status));
908
909 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
910 (void) AcpiOsDeleteSemaphore (MainThreadGate);
911 return;
912 }
913
914 memset (&AcpiGbl_DbMethodInfo, 0, sizeof (ACPI_DB_METHOD_INFO));
915
916 /* Array to store IDs of threads */
917
918 AcpiGbl_DbMethodInfo.NumThreads = NumThreads;
919 Size = sizeof (ACPI_THREAD_ID) * AcpiGbl_DbMethodInfo.NumThreads;
920
921 AcpiGbl_DbMethodInfo.Threads = AcpiOsAllocate (Size);
922 if (AcpiGbl_DbMethodInfo.Threads == NULL)
923 {
924 AcpiOsPrintf ("No memory for thread IDs array\n");
925 (void) AcpiOsDeleteSemaphore (MainThreadGate);
926 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
927 (void) AcpiOsDeleteSemaphore (InfoGate);
928 return;
929 }
930 memset (AcpiGbl_DbMethodInfo.Threads, 0, Size);
931
932 /* Setup the context to be passed to each thread */
933
934 AcpiGbl_DbMethodInfo.Name = MethodNameArg;
935 AcpiGbl_DbMethodInfo.Flags = 0;
936 AcpiGbl_DbMethodInfo.NumLoops = NumLoops;
937 AcpiGbl_DbMethodInfo.MainThreadGate = MainThreadGate;
938 AcpiGbl_DbMethodInfo.ThreadCompleteGate = ThreadCompleteGate;
939 AcpiGbl_DbMethodInfo.InfoGate = InfoGate;
940
941 /* Init arguments to be passed to method */
942
943 AcpiGbl_DbMethodInfo.InitArgs = 1;
944 AcpiGbl_DbMethodInfo.Args = AcpiGbl_DbMethodInfo.Arguments;
945 AcpiGbl_DbMethodInfo.Arguments[0] = AcpiGbl_DbMethodInfo.NumThreadsStr;
946 AcpiGbl_DbMethodInfo.Arguments[1] = AcpiGbl_DbMethodInfo.IdOfThreadStr;
947 AcpiGbl_DbMethodInfo.Arguments[2] = AcpiGbl_DbMethodInfo.IndexOfThreadStr;
948 AcpiGbl_DbMethodInfo.Arguments[3] = NULL;
949
950 AcpiGbl_DbMethodInfo.Types = AcpiGbl_DbMethodInfo.ArgTypes;
951 AcpiGbl_DbMethodInfo.ArgTypes[0] = ACPI_TYPE_INTEGER;
952 AcpiGbl_DbMethodInfo.ArgTypes[1] = ACPI_TYPE_INTEGER;
953 AcpiGbl_DbMethodInfo.ArgTypes[2] = ACPI_TYPE_INTEGER;
954
955 AcpiDbUint32ToHexString (NumThreads, AcpiGbl_DbMethodInfo.NumThreadsStr);
956
957 Status = AcpiDbExecuteSetup (&AcpiGbl_DbMethodInfo);
958 if (ACPI_FAILURE (Status))
959 {
960 goto CleanupAndExit;
961 }
962
963 /* Get the NS node, determines existence also */
964
965 Status = AcpiGetHandle (NULL, AcpiGbl_DbMethodInfo.Pathname,
966 &AcpiGbl_DbMethodInfo.Method);
967 if (ACPI_FAILURE (Status))
968 {
969 AcpiOsPrintf ("%s Could not get handle for %s\n",
970 AcpiFormatException (Status), AcpiGbl_DbMethodInfo.Pathname);
971 goto CleanupAndExit;
972 }
973
974 /* Create the threads */
975
976 AcpiOsPrintf ("Creating %X threads to execute %X times each\n",
977 NumThreads, NumLoops);
978
979 for (i = 0; i < (NumThreads); i++)
980 {
981 Status = AcpiOsExecute (OSL_DEBUGGER_EXEC_THREAD, AcpiDbMethodThread,
982 &AcpiGbl_DbMethodInfo);
983 if (ACPI_FAILURE (Status))
984 {
985 break;
986 }
987 }
988
989 /* Wait for all threads to complete */
990
991 (void) AcpiOsWaitSemaphore (MainThreadGate, 1, ACPI_WAIT_FOREVER);
992
993 AcpiDbSetOutputDestination (ACPI_DB_DUPLICATE_OUTPUT);
994 AcpiOsPrintf ("All threads (%X) have completed\n", NumThreads);
995 AcpiDbSetOutputDestination (ACPI_DB_CONSOLE_OUTPUT);
996
997 CleanupAndExit:
998
999 /* Cleanup and exit */
1000
1001 (void) AcpiOsDeleteSemaphore (MainThreadGate);
1002 (void) AcpiOsDeleteSemaphore (ThreadCompleteGate);
1003 (void) AcpiOsDeleteSemaphore (InfoGate);
1004
1005 AcpiOsFree (AcpiGbl_DbMethodInfo.Threads);
1006 AcpiGbl_DbMethodInfo.Threads = NULL;
1007 }
1008