mkdep(1) seems to want the current directory on the include path,
[dragonfly.git] / sys / contrib / dev / acpica-unix-20031203 / interpreter / dispatcher / dsmethod.c
1 /******************************************************************************
2  *
3  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
4  *              $Revision: 92 $
5  *
6  *****************************************************************************/
7
8 /******************************************************************************
9  *
10  * 1. Copyright Notice
11  *
12  * Some or all of this work - Copyright (c) 1999 - 2003, Intel Corp.
13  * All rights reserved.
14  *
15  * 2. License
16  *
17  * 2.1. This is your license from Intel Corp. under its intellectual property
18  * rights.  You may have additional license terms from the party that provided
19  * you this software, covering your right to use that party's intellectual
20  * property rights.
21  *
22  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
23  * copy of the source code appearing in this file ("Covered Code") an
24  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
25  * base code distributed originally by Intel ("Original Intel Code") to copy,
26  * make derivatives, distribute, use and display any portion of the Covered
27  * Code in any form, with the right to sublicense such rights; and
28  *
29  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
30  * license (with the right to sublicense), under only those claims of Intel
31  * patents that are infringed by the Original Intel Code, to make, use, sell,
32  * offer to sell, and import the Covered Code and derivative works thereof
33  * solely to the minimum extent necessary to exercise the above copyright
34  * license, and in no event shall the patent license extend to any additions
35  * to or modifications of the Original Intel Code.  No other license or right
36  * is granted directly or by implication, estoppel or otherwise;
37  *
38  * The above copyright and patent license is granted only if the following
39  * conditions are met:
40  *
41  * 3. Conditions
42  *
43  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
44  * Redistribution of source code of any substantial portion of the Covered
45  * Code or modification with rights to further distribute source must include
46  * the above Copyright Notice, the above License, this list of Conditions,
47  * and the following Disclaimer and Export Compliance provision.  In addition,
48  * Licensee must cause all Covered Code to which Licensee contributes to
49  * contain a file documenting the changes Licensee made to create that Covered
50  * Code and the date of any change.  Licensee must include in that file the
51  * documentation of any changes made by any predecessor Licensee.  Licensee
52  * must include a prominent statement that the modification is derived,
53  * directly or indirectly, from Original Intel Code.
54  *
55  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
56  * Redistribution of source code of any substantial portion of the Covered
57  * Code or modification without rights to further distribute source must
58  * include the following Disclaimer and Export Compliance provision in the
59  * documentation and/or other materials provided with distribution.  In
60  * addition, Licensee may not authorize further sublicense of source of any
61  * portion of the Covered Code, and must include terms to the effect that the
62  * license from Licensee to its licensee is limited to the intellectual
63  * property embodied in the software Licensee provides to its licensee, and
64  * not to intellectual property embodied in modifications its licensee may
65  * make.
66  *
67  * 3.3. Redistribution of Executable. Redistribution in executable form of any
68  * substantial portion of the Covered Code or modification must reproduce the
69  * above Copyright Notice, and the following Disclaimer and Export Compliance
70  * provision in the documentation and/or other materials provided with the
71  * distribution.
72  *
73  * 3.4. Intel retains all right, title, and interest in and to the Original
74  * Intel Code.
75  *
76  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
77  * Intel shall be used in advertising or otherwise to promote the sale, use or
78  * other dealings in products derived from or relating to the Covered Code
79  * without prior written authorization from Intel.
80  *
81  * 4. Disclaimer and Export Compliance
82  *
83  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
84  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
85  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
86  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
87  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
88  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
89  * PARTICULAR PURPOSE.
90  *
91  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
92  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
93  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
94  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
95  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
96  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
97  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
98  * LIMITED REMEDY.
99  *
100  * 4.3. Licensee shall not export, either directly or indirectly, any of this
101  * software or system incorporating such software without first obtaining any
102  * required license or other approval from the U. S. Department of Commerce or
103  * any other agency or department of the United States Government.  In the
104  * event Licensee exports any such software from the United States or
105  * re-exports any such software from a foreign destination, Licensee shall
106  * ensure that the distribution and export/re-export of the software is in
107  * compliance with all laws, regulations, orders, or other restrictions of the
108  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
109  * any of its subsidiaries will export/re-export any technical data, process,
110  * software, or service, directly or indirectly, to any country for which the
111  * United States government or any agency thereof requires an export license,
112  * other governmental approval, or letter of assurance, without first obtaining
113  * such license, approval or letter.
114  *
115  *****************************************************************************/
116
117 #define __DSMETHOD_C__
118
119 #include "acpi.h"
120 #include "acparser.h"
121 #include "amlcode.h"
122 #include "acdispat.h"
123 #include "acinterp.h"
124 #include "acnamesp.h"
125
126
127 #define _COMPONENT          ACPI_DISPATCHER
128         ACPI_MODULE_NAME    ("dsmethod")
129
130
131 /*******************************************************************************
132  *
133  * FUNCTION:    AcpiDsParseMethod
134  *
135  * PARAMETERS:  ObjHandle       - Node of the method
136  *              Level           - Current nesting level
137  *              Context         - Points to a method counter
138  *              ReturnValue     - Not used
139  *
140  * RETURN:      Status
141  *
142  * DESCRIPTION: Call the parser and parse the AML that is
143  *              associated with the method.
144  *
145  * MUTEX:       Assumes parser is locked
146  *
147  ******************************************************************************/
148
149 ACPI_STATUS
150 AcpiDsParseMethod (
151     ACPI_HANDLE             ObjHandle)
152 {
153     ACPI_STATUS             Status;
154     ACPI_OPERAND_OBJECT     *ObjDesc;
155     ACPI_PARSE_OBJECT       *Op;
156     ACPI_NAMESPACE_NODE     *Node;
157     ACPI_OWNER_ID           OwnerId;
158     ACPI_WALK_STATE         *WalkState;
159
160
161     ACPI_FUNCTION_TRACE_PTR ("DsParseMethod", ObjHandle);
162
163
164     /* Parameter Validation */
165
166     if (!ObjHandle)
167     {
168         return_ACPI_STATUS (AE_NULL_ENTRY);
169     }
170
171     ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** NamedObj=%p\n",
172         AcpiUtGetNodeName (ObjHandle), ObjHandle));
173
174     /* Extract the method object from the method Node */
175
176     Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
177     ObjDesc = AcpiNsGetAttachedObject (Node);
178     if (!ObjDesc)
179     {
180         return_ACPI_STATUS (AE_NULL_OBJECT);
181     }
182
183     /* Create a mutex for the method if there is a concurrency limit */
184
185     if ((ObjDesc->Method.Concurrency != INFINITE_CONCURRENCY) &&
186         (!ObjDesc->Method.Semaphore))
187     {
188         Status = AcpiOsCreateSemaphore (ObjDesc->Method.Concurrency,
189                                         ObjDesc->Method.Concurrency,
190                                         &ObjDesc->Method.Semaphore);
191         if (ACPI_FAILURE (Status))
192         {
193             return_ACPI_STATUS (Status);
194         }
195     }
196
197     /*
198      * Allocate a new parser op to be the root of the parsed
199      * method tree
200      */
201     Op = AcpiPsAllocOp (AML_METHOD_OP);
202     if (!Op)
203     {
204         return_ACPI_STATUS (AE_NO_MEMORY);
205     }
206
207     /* Init new op with the method name and pointer back to the Node */
208
209     AcpiPsSetName (Op, Node->Name.Integer);
210     Op->Common.Node = Node;
211
212     /*
213      * Get a new OwnerId for objects created by this method.  Namespace
214      * objects (such as Operation Regions) can be created during the
215      * first pass parse.
216      */
217     OwnerId = AcpiUtAllocateOwnerId (ACPI_OWNER_TYPE_METHOD);
218     ObjDesc->Method.OwningId = OwnerId;
219
220     /* Create and initialize a new walk state */
221
222     WalkState = AcpiDsCreateWalkState (OwnerId, NULL, NULL, NULL);
223     if (!WalkState)
224     {
225         return_ACPI_STATUS (AE_NO_MEMORY);
226     }
227
228     Status = AcpiDsInitAmlWalk (WalkState, Op, Node, ObjDesc->Method.AmlStart,
229                     ObjDesc->Method.AmlLength, NULL, NULL, 1);
230     if (ACPI_FAILURE (Status))
231     {
232         AcpiDsDeleteWalkState (WalkState);
233         return_ACPI_STATUS (Status);
234     }
235
236     /*
237      * Parse the method, first pass
238      *
239      * The first pass load is where newly declared named objects are
240      * added into the namespace.  Actual evaluation of
241      * the named objects (what would be called a "second
242      * pass") happens during the actual execution of the
243      * method so that operands to the named objects can
244      * take on dynamic run-time values.
245      */
246     Status = AcpiPsParseAml (WalkState);
247     if (ACPI_FAILURE (Status))
248     {
249         return_ACPI_STATUS (Status);
250     }
251
252     ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
253         "**** [%4.4s] Parsed **** NamedObj=%p Op=%p\n",
254         AcpiUtGetNodeName (ObjHandle), ObjHandle, Op));
255
256     AcpiPsDeleteParseTree (Op);
257     return_ACPI_STATUS (Status);
258 }
259
260
261 /*******************************************************************************
262  *
263  * FUNCTION:    AcpiDsBeginMethodExecution
264  *
265  * PARAMETERS:  MethodNode          - Node of the method
266  *              ObjDesc             - The method object
267  *              CallingMethodNode   - Caller of this method (if non-null)
268  *
269  * RETURN:      Status
270  *
271  * DESCRIPTION: Prepare a method for execution.  Parses the method if necessary,
272  *              increments the thread count, and waits at the method semaphore
273  *              for clearance to execute.
274  *
275  * MUTEX:       Locks/unlocks parser.
276  *
277  ******************************************************************************/
278
279 ACPI_STATUS
280 AcpiDsBeginMethodExecution (
281     ACPI_NAMESPACE_NODE     *MethodNode,
282     ACPI_OPERAND_OBJECT     *ObjDesc,
283     ACPI_NAMESPACE_NODE     *CallingMethodNode)
284 {
285     ACPI_STATUS             Status = AE_OK;
286
287
288     ACPI_FUNCTION_TRACE_PTR ("DsBeginMethodExecution", MethodNode);
289
290
291     if (!MethodNode)
292     {
293         return_ACPI_STATUS (AE_NULL_ENTRY);
294     }
295
296     /*
297      * If there is a concurrency limit on this method, we need to
298      * obtain a unit from the method semaphore.
299      */
300     if (ObjDesc->Method.Semaphore)
301     {
302         /*
303          * Allow recursive method calls, up to the reentrancy/concurrency
304          * limit imposed by the SERIALIZED rule and the SyncLevel method
305          * parameter.
306          *
307          * The point of this code is to avoid permanently blocking a
308          * thread that is making recursive method calls.
309          */
310         if (MethodNode == CallingMethodNode)
311         {
312             if (ObjDesc->Method.ThreadCount >= ObjDesc->Method.Concurrency)
313             {
314                 return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
315             }
316         }
317
318         /*
319          * Get a unit from the method semaphore. This releases the
320          * interpreter if we block
321          */
322         Status = AcpiExSystemWaitSemaphore (ObjDesc->Method.Semaphore,
323                                             ACPI_WAIT_FOREVER);
324     }
325
326     /*
327      * Increment the method parse tree thread count since it has been
328      * reentered one more time (even if it is the same thread)
329      */
330     ObjDesc->Method.ThreadCount++;
331     return_ACPI_STATUS (Status);
332 }
333
334
335 /*******************************************************************************
336  *
337  * FUNCTION:    AcpiDsCallControlMethod
338  *
339  * PARAMETERS:  WalkState           - Current state of the walk
340  *              Op                  - Current Op to be walked
341  *
342  * RETURN:      Status
343  *
344  * DESCRIPTION: Transfer execution to a called control method
345  *
346  ******************************************************************************/
347
348 ACPI_STATUS
349 AcpiDsCallControlMethod (
350     ACPI_THREAD_STATE       *Thread,
351     ACPI_WALK_STATE         *ThisWalkState,
352     ACPI_PARSE_OBJECT       *Op)
353 {
354     ACPI_STATUS             Status;
355     ACPI_NAMESPACE_NODE     *MethodNode;
356     ACPI_OPERAND_OBJECT     *ObjDesc;
357     ACPI_WALK_STATE         *NextWalkState;
358     UINT32                  i;
359
360
361     ACPI_FUNCTION_TRACE_PTR ("DsCallControlMethod", ThisWalkState);
362
363     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n",
364         ThisWalkState->PrevOp, ThisWalkState));
365
366     /*
367      * Get the namespace entry for the control method we are about to call
368      */
369     MethodNode = ThisWalkState->MethodCallNode;
370     if (!MethodNode)
371     {
372         return_ACPI_STATUS (AE_NULL_ENTRY);
373     }
374
375     ObjDesc = AcpiNsGetAttachedObject (MethodNode);
376     if (!ObjDesc)
377     {
378         return_ACPI_STATUS (AE_NULL_OBJECT);
379     }
380
381     ObjDesc->Method.OwningId = AcpiUtAllocateOwnerId (ACPI_OWNER_TYPE_METHOD);
382
383     /* Init for new method, wait on concurrency semaphore */
384
385     Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc,
386                     ThisWalkState->MethodNode);
387     if (ACPI_FAILURE (Status))
388     {
389         return_ACPI_STATUS (Status);
390     }
391
392     /* 1) Parse: Create a new walk state for the preempting walk */
393
394     NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwningId,
395                                             Op, ObjDesc, NULL);
396     if (!NextWalkState)
397     {
398         return_ACPI_STATUS (AE_NO_MEMORY);
399     }
400
401     /* Create and init a Root Node */
402
403     Op = AcpiPsCreateScopeOp ();
404     if (!Op)
405     {
406         Status = AE_NO_MEMORY;
407         goto Cleanup;
408     }
409
410     Status = AcpiDsInitAmlWalk (NextWalkState, Op, MethodNode,
411                     ObjDesc->Method.AmlStart,  ObjDesc->Method.AmlLength,
412                     NULL, NULL, 1);
413     if (ACPI_FAILURE (Status))
414     {
415         AcpiDsDeleteWalkState (NextWalkState);
416         goto Cleanup;
417     }
418
419     /* Begin AML parse */
420
421     Status = AcpiPsParseAml (NextWalkState);
422     AcpiPsDeleteParseTree (Op);
423
424     /* 2) Execute: Create a new state for the preempting walk */
425
426     NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwningId,
427                                             NULL, ObjDesc, Thread);
428     if (!NextWalkState)
429     {
430         Status = AE_NO_MEMORY;
431         goto Cleanup;
432     }
433
434     /*
435      * The resolved arguments were put on the previous walk state's operand
436      * stack.  Operands on the previous walk state stack always
437      * start at index 0.
438      * Null terminate the list of arguments
439      */
440     ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL;
441
442     Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode,
443                     ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength,
444                     &ThisWalkState->Operands[0], NULL, 3);
445     if (ACPI_FAILURE (Status))
446     {
447         goto Cleanup;
448     }
449
450     /*
451      * Delete the operands on the previous walkstate operand stack
452      * (they were copied to new objects)
453      */
454     for (i = 0; i < ObjDesc->Method.ParamCount; i++)
455     {
456         AcpiUtRemoveReference (ThisWalkState->Operands [i]);
457         ThisWalkState->Operands [i] = NULL;
458     }
459
460     /* Clear the operand stack */
461
462     ThisWalkState->NumOperands = 0;
463
464     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
465         "Starting nested execution, newstate=%p\n", NextWalkState));
466
467     return_ACPI_STATUS (AE_OK);
468
469
470     /* On error, we must delete the new walk state */
471
472 Cleanup:
473     (void) AcpiDsTerminateControlMethod (NextWalkState);
474     AcpiDsDeleteWalkState (NextWalkState);
475     return_ACPI_STATUS (Status);
476
477 }
478
479
480 /*******************************************************************************
481  *
482  * FUNCTION:    AcpiDsRestartControlMethod
483  *
484  * PARAMETERS:  WalkState           - State of the method when it was preempted
485  *              Op                  - Pointer to new current op
486  *
487  * RETURN:      Status
488  *
489  * DESCRIPTION: Restart a method that was preempted
490  *
491  ******************************************************************************/
492
493 ACPI_STATUS
494 AcpiDsRestartControlMethod (
495     ACPI_WALK_STATE         *WalkState,
496     ACPI_OPERAND_OBJECT     *ReturnDesc)
497 {
498     ACPI_STATUS             Status;
499
500
501     ACPI_FUNCTION_TRACE_PTR ("DsRestartControlMethod", WalkState);
502
503
504     if (ReturnDesc)
505     {
506         if (WalkState->ReturnUsed)
507         {
508             /*
509              * Get the return value (if any) from the previous method.
510              * NULL if no return value
511              */
512             Status = AcpiDsResultPush (ReturnDesc, WalkState);
513             if (ACPI_FAILURE (Status))
514             {
515                 AcpiUtRemoveReference (ReturnDesc);
516                 return_ACPI_STATUS (Status);
517             }
518         }
519         else
520         {
521             /*
522              * Delete the return value if it will not be used by the
523              * calling method
524              */
525             AcpiUtRemoveReference (ReturnDesc);
526         }
527     }
528
529     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
530         "Method=%p Return=%p ReturnUsed?=%X ResStack=%p State=%p\n",
531         WalkState->MethodCallOp, ReturnDesc, WalkState->ReturnUsed,
532         WalkState->Results, WalkState));
533
534     return_ACPI_STATUS (AE_OK);
535 }
536
537
538 /*******************************************************************************
539  *
540  * FUNCTION:    AcpiDsTerminateControlMethod
541  *
542  * PARAMETERS:  WalkState           - State of the method
543  *
544  * RETURN:      Status
545  *
546  * DESCRIPTION: Terminate a control method.  Delete everything that the method
547  *              created, delete all locals and arguments, and delete the parse
548  *              tree if requested.
549  *
550  ******************************************************************************/
551
552 ACPI_STATUS
553 AcpiDsTerminateControlMethod (
554     ACPI_WALK_STATE         *WalkState)
555 {
556     ACPI_OPERAND_OBJECT     *ObjDesc;
557     ACPI_NAMESPACE_NODE     *MethodNode;
558     ACPI_STATUS             Status;
559
560
561     ACPI_FUNCTION_TRACE_PTR ("DsTerminateControlMethod", WalkState);
562
563
564     if (!WalkState)
565     {
566         return (AE_BAD_PARAMETER);
567     }
568
569     /* The current method object was saved in the walk state */
570
571     ObjDesc = WalkState->MethodDesc;
572     if (!ObjDesc)
573     {
574         return_ACPI_STATUS (AE_OK);
575     }
576
577     /* Delete all arguments and locals */
578
579     AcpiDsMethodDataDeleteAll (WalkState);
580
581     /*
582      * Lock the parser while we terminate this method.
583      * If this is the last thread executing the method,
584      * we have additional cleanup to perform
585      */
586     Status = AcpiUtAcquireMutex (ACPI_MTX_PARSER);
587     if (ACPI_FAILURE (Status))
588     {
589         return_ACPI_STATUS (Status);
590     }
591
592     /* Signal completion of the execution of this method if necessary */
593
594     if (WalkState->MethodDesc->Method.Semaphore)
595     {
596         Status = AcpiOsSignalSemaphore (
597                         WalkState->MethodDesc->Method.Semaphore, 1);
598         if (ACPI_FAILURE (Status))
599         {
600             ACPI_REPORT_ERROR (("Could not signal method semaphore\n"));
601             Status = AE_OK;
602
603             /* Ignore error and continue cleanup */
604         }
605     }
606
607     /* Decrement the thread count on the method parse tree */
608
609     WalkState->MethodDesc->Method.ThreadCount--;
610     if (!WalkState->MethodDesc->Method.ThreadCount)
611     {
612         /*
613          * There are no more threads executing this method.  Perform
614          * additional cleanup.
615          *
616          * The method Node is stored in the walk state
617          */
618         MethodNode = WalkState->MethodNode;
619
620         /*
621          * Delete any namespace entries created immediately underneath
622          * the method
623          */
624         Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
625         if (ACPI_FAILURE (Status))
626         {
627             return_ACPI_STATUS (Status);
628         }
629
630         if (MethodNode->Child)
631         {
632             AcpiNsDeleteNamespaceSubtree (MethodNode);
633         }
634
635         /*
636          * Delete any namespace entries created anywhere else within
637          * the namespace
638          */
639         AcpiNsDeleteNamespaceByOwner (WalkState->MethodDesc->Method.OwningId);
640         Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
641         if (ACPI_FAILURE (Status))
642         {
643             return_ACPI_STATUS (Status);
644         }
645     }
646
647     Status = AcpiUtReleaseMutex (ACPI_MTX_PARSER);
648     return_ACPI_STATUS (Status);
649 }
650
651