nseval.c revision 1.3.8.2 1 /*******************************************************************************
2 *
3 * Module Name: nseval - Object evaluation, includes control method execution
4 *
5 ******************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2011, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #define __NSEVAL_C__
45
46 #include "acpi.h"
47 #include "accommon.h"
48 #include "acparser.h"
49 #include "acinterp.h"
50 #include "acnamesp.h"
51
52
53 #define _COMPONENT ACPI_NAMESPACE
54 ACPI_MODULE_NAME ("nseval")
55
56 /* Local prototypes */
57
58 static void
59 AcpiNsExecModuleCode (
60 ACPI_OPERAND_OBJECT *MethodObj,
61 ACPI_EVALUATE_INFO *Info);
62
63
64 /*******************************************************************************
65 *
66 * FUNCTION: AcpiNsEvaluate
67 *
68 * PARAMETERS: Info - Evaluation info block, contains:
69 * PrefixNode - Prefix or Method/Object Node to execute
70 * Pathname - Name of method to execute, If NULL, the
71 * Node is the object to execute
72 * Parameters - List of parameters to pass to the method,
73 * terminated by NULL. Params itself may be
74 * NULL if no parameters are being passed.
75 * ReturnObject - Where to put method's return value (if
76 * any). If NULL, no value is returned.
77 * ParameterType - Type of Parameter list
78 * ReturnObject - Where to put method's return value (if
79 * any). If NULL, no value is returned.
80 * Flags - ACPI_IGNORE_RETURN_VALUE to delete return
81 *
82 * RETURN: Status
83 *
84 * DESCRIPTION: Execute a control method or return the current value of an
85 * ACPI namespace object.
86 *
87 * MUTEX: Locks interpreter
88 *
89 ******************************************************************************/
90
91 ACPI_STATUS
92 AcpiNsEvaluate (
93 ACPI_EVALUATE_INFO *Info)
94 {
95 ACPI_STATUS Status;
96 ACPI_NAMESPACE_NODE *Node;
97
98
99 ACPI_FUNCTION_TRACE (NsEvaluate);
100
101
102 if (!Info)
103 {
104 return_ACPI_STATUS (AE_BAD_PARAMETER);
105 }
106
107 /* Initialize the return value to an invalid object */
108
109 Info->ReturnObject = NULL;
110 Info->ParamCount = 0;
111
112 /*
113 * Get the actual namespace node for the target object. Handles these cases:
114 *
115 * 1) Null node, Pathname (absolute path)
116 * 2) Node, Pathname (path relative to Node)
117 * 3) Node, Null Pathname
118 */
119 Status = AcpiNsGetNode (Info->PrefixNode, Info->Pathname,
120 ACPI_NS_NO_UPSEARCH, &Info->ResolvedNode);
121 if (ACPI_FAILURE (Status))
122 {
123 return_ACPI_STATUS (Status);
124 }
125
126 /*
127 * For a method alias, we must grab the actual method node so that proper
128 * scoping context will be established before execution.
129 */
130 if (AcpiNsGetType (Info->ResolvedNode) == ACPI_TYPE_LOCAL_METHOD_ALIAS)
131 {
132 Info->ResolvedNode =
133 ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Info->ResolvedNode->Object);
134 }
135
136 ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", Info->Pathname,
137 Info->ResolvedNode, AcpiNsGetAttachedObject (Info->ResolvedNode)));
138
139 Node = Info->ResolvedNode;
140
141 /*
142 * Two major cases here:
143 *
144 * 1) The object is a control method -- execute it
145 * 2) The object is not a method -- just return it's current value
146 */
147 if (AcpiNsGetType (Info->ResolvedNode) == ACPI_TYPE_METHOD)
148 {
149 /*
150 * 1) Object is a control method - execute it
151 */
152
153 /* Verify that there is a method object associated with this node */
154
155 Info->ObjDesc = AcpiNsGetAttachedObject (Info->ResolvedNode);
156 if (!Info->ObjDesc)
157 {
158 ACPI_ERROR ((AE_INFO, "Control method has no attached sub-object"));
159 return_ACPI_STATUS (AE_NULL_OBJECT);
160 }
161
162 /* Count the number of arguments being passed to the method */
163
164 if (Info->Parameters)
165 {
166 while (Info->Parameters[Info->ParamCount])
167 {
168 if (Info->ParamCount > ACPI_METHOD_MAX_ARG)
169 {
170 return_ACPI_STATUS (AE_LIMIT);
171 }
172 Info->ParamCount++;
173 }
174 }
175
176 ACPI_DUMP_PATHNAME (Info->ResolvedNode, "ACPI: Execute Method",
177 ACPI_LV_INFO, _COMPONENT);
178
179 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
180 "Method at AML address %p Length %X\n",
181 Info->ObjDesc->Method.AmlStart + 1,
182 Info->ObjDesc->Method.AmlLength - 1));
183
184 /*
185 * Any namespace deletion must acquire both the namespace and
186 * interpreter locks to ensure that no thread is using the portion of
187 * the namespace that is being deleted.
188 *
189 * Execute the method via the interpreter. The interpreter is locked
190 * here before calling into the AML parser
191 */
192 AcpiExEnterInterpreter ();
193 Status = AcpiPsExecuteMethod (Info);
194 AcpiExExitInterpreter ();
195 }
196 else
197 {
198 /*
199 * 2) Object is not a method, return its current value
200 *
201 * Disallow certain object types. For these, "evaluation" is undefined.
202 */
203 switch (Info->ResolvedNode->Type)
204 {
205 case ACPI_TYPE_DEVICE:
206 case ACPI_TYPE_EVENT:
207 case ACPI_TYPE_MUTEX:
208 case ACPI_TYPE_REGION:
209 case ACPI_TYPE_THERMAL:
210 case ACPI_TYPE_LOCAL_SCOPE:
211
212 ACPI_ERROR ((AE_INFO,
213 "[%4.4s] Evaluation of object type [%s] is not supported",
214 Info->ResolvedNode->Name.Ascii,
215 AcpiUtGetTypeName (Info->ResolvedNode->Type)));
216
217 return_ACPI_STATUS (AE_TYPE);
218
219 default:
220 break;
221 }
222
223 /*
224 * Objects require additional resolution steps (e.g., the Node may be
225 * a field that must be read, etc.) -- we can't just grab the object
226 * out of the node.
227 *
228 * Use ResolveNodeToValue() to get the associated value.
229 *
230 * NOTE: we can get away with passing in NULL for a walk state because
231 * ResolvedNode is guaranteed to not be a reference to either a method
232 * local or a method argument (because this interface is never called
233 * from a running method.)
234 *
235 * Even though we do not directly invoke the interpreter for object
236 * resolution, we must lock it because we could access an opregion.
237 * The opregion access code assumes that the interpreter is locked.
238 */
239 AcpiExEnterInterpreter ();
240
241 /* Function has a strange interface */
242
243 Status = AcpiExResolveNodeToValue (&Info->ResolvedNode, NULL);
244 AcpiExExitInterpreter ();
245
246 /*
247 * If AcpiExResolveNodeToValue() succeeded, the return value was placed
248 * in ResolvedNode.
249 */
250 if (ACPI_SUCCESS (Status))
251 {
252 Status = AE_CTRL_RETURN_VALUE;
253 Info->ReturnObject =
254 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Info->ResolvedNode);
255
256 ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n",
257 Info->ReturnObject,
258 AcpiUtGetObjectTypeName (Info->ReturnObject)));
259 }
260 }
261
262 /*
263 * Check input argument count against the ASL-defined count for a method.
264 * Also check predefined names: argument count and return value against
265 * the ACPI specification. Some incorrect return value types are repaired.
266 */
267 (void) AcpiNsCheckPredefinedNames (Node, Info->ParamCount,
268 Status, &Info->ReturnObject);
269
270 /* Check if there is a return value that must be dealt with */
271
272 if (Status == AE_CTRL_RETURN_VALUE)
273 {
274 /* If caller does not want the return value, delete it */
275
276 if (Info->Flags & ACPI_IGNORE_RETURN_VALUE)
277 {
278 AcpiUtRemoveReference (Info->ReturnObject);
279 Info->ReturnObject = NULL;
280 }
281
282 /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
283
284 Status = AE_OK;
285 }
286
287 ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
288 "*** Completed evaluation of object %s ***\n", Info->Pathname));
289
290 /*
291 * Namespace was unlocked by the handling AcpiNs* function, so we
292 * just return
293 */
294 return_ACPI_STATUS (Status);
295 }
296
297
298 /*******************************************************************************
299 *
300 * FUNCTION: AcpiNsExecModuleCodeList
301 *
302 * PARAMETERS: None
303 *
304 * RETURN: None. Exceptions during method execution are ignored, since
305 * we cannot abort a table load.
306 *
307 * DESCRIPTION: Execute all elements of the global module-level code list.
308 * Each element is executed as a single control method.
309 *
310 ******************************************************************************/
311
312 void
313 AcpiNsExecModuleCodeList (
314 void)
315 {
316 ACPI_OPERAND_OBJECT *Prev;
317 ACPI_OPERAND_OBJECT *Next;
318 ACPI_EVALUATE_INFO *Info;
319 UINT32 MethodCount = 0;
320
321
322 ACPI_FUNCTION_TRACE (NsExecModuleCodeList);
323
324
325 /* Exit now if the list is empty */
326
327 Next = AcpiGbl_ModuleCodeList;
328 if (!Next)
329 {
330 return_VOID;
331 }
332
333 /* Allocate the evaluation information block */
334
335 Info = ACPI_ALLOCATE (sizeof (ACPI_EVALUATE_INFO));
336 if (!Info)
337 {
338 return_VOID;
339 }
340
341 /* Walk the list, executing each "method" */
342
343 while (Next)
344 {
345 Prev = Next;
346 Next = Next->Method.Mutex;
347
348 /* Clear the link field and execute the method */
349
350 Prev->Method.Mutex = NULL;
351 AcpiNsExecModuleCode (Prev, Info);
352 MethodCount++;
353
354 /* Delete the (temporary) method object */
355
356 AcpiUtRemoveReference (Prev);
357 }
358
359 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
360 "Executed %u blocks of module-level executable AML code",
361 MethodCount));
362
363 ACPI_FREE (Info);
364 AcpiGbl_ModuleCodeList = NULL;
365 return_VOID;
366 }
367
368
369 /*******************************************************************************
370 *
371 * FUNCTION: AcpiNsExecModuleCode
372 *
373 * PARAMETERS: MethodObj - Object container for the module-level code
374 * Info - Info block for method evaluation
375 *
376 * RETURN: None. Exceptions during method execution are ignored, since
377 * we cannot abort a table load.
378 *
379 * DESCRIPTION: Execute a control method containing a block of module-level
380 * executable AML code. The control method is temporarily
381 * installed to the root node, then evaluated.
382 *
383 ******************************************************************************/
384
385 static void
386 AcpiNsExecModuleCode (
387 ACPI_OPERAND_OBJECT *MethodObj,
388 ACPI_EVALUATE_INFO *Info)
389 {
390 ACPI_OPERAND_OBJECT *ParentObj;
391 ACPI_NAMESPACE_NODE *ParentNode;
392 ACPI_OBJECT_TYPE Type;
393 ACPI_STATUS Status;
394
395
396 ACPI_FUNCTION_TRACE (NsExecModuleCode);
397
398
399 /*
400 * Get the parent node. We cheat by using the NextObject field
401 * of the method object descriptor.
402 */
403 ParentNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE,
404 MethodObj->Method.NextObject);
405 Type = AcpiNsGetType (ParentNode);
406
407 /*
408 * Get the region handler and save it in the method object. We may need
409 * this if an operation region declaration causes a _REG method to be run.
410 *
411 * We can't do this in AcpiPsLinkModuleCode because
412 * AcpiGbl_RootNode->Object is NULL at PASS1.
413 */
414 if ((Type == ACPI_TYPE_DEVICE) && ParentNode->Object)
415 {
416 MethodObj->Method.Dispatch.Handler =
417 ParentNode->Object->Device.Handler;
418 }
419
420 /* Must clear NextObject (AcpiNsAttachObject needs the field) */
421
422 MethodObj->Method.NextObject = NULL;
423
424 /* Initialize the evaluation information block */
425
426 ACPI_MEMSET (Info, 0, sizeof (ACPI_EVALUATE_INFO));
427 Info->PrefixNode = ParentNode;
428
429 /*
430 * Get the currently attached parent object. Add a reference, because the
431 * ref count will be decreased when the method object is installed to
432 * the parent node.
433 */
434 ParentObj = AcpiNsGetAttachedObject (ParentNode);
435 if (ParentObj)
436 {
437 AcpiUtAddReference (ParentObj);
438 }
439
440 /* Install the method (module-level code) in the parent node */
441
442 Status = AcpiNsAttachObject (ParentNode, MethodObj,
443 ACPI_TYPE_METHOD);
444 if (ACPI_FAILURE (Status))
445 {
446 goto Exit;
447 }
448
449 /* Execute the parent node as a control method */
450
451 Status = AcpiNsEvaluate (Info);
452
453 ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Executed module-level code at %p\n",
454 MethodObj->Method.AmlStart));
455
456 /* Delete a possible implicit return value (in slack mode) */
457
458 if (Info->ReturnObject)
459 {
460 AcpiUtRemoveReference (Info->ReturnObject);
461 }
462
463 /* Detach the temporary method object */
464
465 AcpiNsDetachObject (ParentNode);
466
467 /* Restore the original parent object */
468
469 if (ParentObj)
470 {
471 Status = AcpiNsAttachObject (ParentNode, ParentObj, Type);
472 }
473 else
474 {
475 ParentNode->Type = (UINT8) Type;
476 }
477
478 Exit:
479 if (ParentObj)
480 {
481 AcpiUtRemoveReference (ParentObj);
482 }
483 return_VOID;
484 }
485
486