1 | /******************************************************************************* |
2 | * |
3 | * Module Name: nseval - Object evaluation, includes control method execution |
4 | * |
5 | ******************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, 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 | #include "acpi.h" |
45 | #include "accommon.h" |
46 | #include "acparser.h" |
47 | #include "acinterp.h" |
48 | #include "acnamesp.h" |
49 | |
50 | |
51 | #define _COMPONENT ACPI_NAMESPACE |
52 | ACPI_MODULE_NAME ("nseval" ) |
53 | |
54 | /* Local prototypes */ |
55 | |
56 | static void |
57 | AcpiNsExecModuleCode ( |
58 | ACPI_OPERAND_OBJECT *MethodObj, |
59 | ACPI_EVALUATE_INFO *Info); |
60 | |
61 | |
62 | /******************************************************************************* |
63 | * |
64 | * FUNCTION: AcpiNsEvaluate |
65 | * |
66 | * PARAMETERS: Info - Evaluation info block, contains these fields |
67 | * and more: |
68 | * PrefixNode - Prefix or Method/Object Node to execute |
69 | * RelativePath - Name of method to execute, If NULL, the |
70 | * Node is the object to execute |
71 | * Parameters - List of parameters to pass to the method, |
72 | * terminated by NULL. Params itself may be |
73 | * NULL if no parameters are being passed. |
74 | * ParameterType - Type of Parameter list |
75 | * ReturnObject - Where to put method's return value (if |
76 | * any). If NULL, no value is returned. |
77 | * Flags - ACPI_IGNORE_RETURN_VALUE to delete return |
78 | * |
79 | * RETURN: Status |
80 | * |
81 | * DESCRIPTION: Execute a control method or return the current value of an |
82 | * ACPI namespace object. |
83 | * |
84 | * MUTEX: Locks interpreter |
85 | * |
86 | ******************************************************************************/ |
87 | |
88 | ACPI_STATUS |
89 | AcpiNsEvaluate ( |
90 | ACPI_EVALUATE_INFO *Info) |
91 | { |
92 | ACPI_STATUS Status; |
93 | |
94 | |
95 | ACPI_FUNCTION_TRACE (NsEvaluate); |
96 | |
97 | |
98 | if (!Info) |
99 | { |
100 | return_ACPI_STATUS (AE_BAD_PARAMETER); |
101 | } |
102 | |
103 | if (!Info->Node) |
104 | { |
105 | /* |
106 | * Get the actual namespace node for the target object if we |
107 | * need to. Handles these cases: |
108 | * |
109 | * 1) Null node, valid pathname from root (absolute path) |
110 | * 2) Node and valid pathname (path relative to Node) |
111 | * 3) Node, Null pathname |
112 | */ |
113 | Status = AcpiNsGetNode (Info->PrefixNode, Info->RelativePathname, |
114 | ACPI_NS_NO_UPSEARCH, &Info->Node); |
115 | if (ACPI_FAILURE (Status)) |
116 | { |
117 | return_ACPI_STATUS (Status); |
118 | } |
119 | } |
120 | |
121 | /* |
122 | * For a method alias, we must grab the actual method node so that |
123 | * proper scoping context will be established before execution. |
124 | */ |
125 | if (AcpiNsGetType (Info->Node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) |
126 | { |
127 | Info->Node = ACPI_CAST_PTR ( |
128 | ACPI_NAMESPACE_NODE, Info->Node->Object); |
129 | } |
130 | |
131 | /* Complete the info block initialization */ |
132 | |
133 | Info->ReturnObject = NULL; |
134 | Info->NodeFlags = Info->Node->Flags; |
135 | Info->ObjDesc = AcpiNsGetAttachedObject (Info->Node); |
136 | |
137 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n" , |
138 | Info->RelativePathname, Info->Node, |
139 | AcpiNsGetAttachedObject (Info->Node))); |
140 | |
141 | /* Get info if we have a predefined name (_HID, etc.) */ |
142 | |
143 | Info->Predefined = AcpiUtMatchPredefinedMethod (Info->Node->Name.Ascii); |
144 | |
145 | /* Get the full pathname to the object, for use in warning messages */ |
146 | |
147 | Info->FullPathname = AcpiNsGetNormalizedPathname (Info->Node, TRUE); |
148 | if (!Info->FullPathname) |
149 | { |
150 | return_ACPI_STATUS (AE_NO_MEMORY); |
151 | } |
152 | |
153 | /* Count the number of arguments being passed in */ |
154 | |
155 | Info->ParamCount = 0; |
156 | if (Info->Parameters) |
157 | { |
158 | while (Info->Parameters[Info->ParamCount]) |
159 | { |
160 | Info->ParamCount++; |
161 | } |
162 | |
163 | /* Warn on impossible argument count */ |
164 | |
165 | if (Info->ParamCount > ACPI_METHOD_NUM_ARGS) |
166 | { |
167 | ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, ACPI_WARN_ALWAYS, |
168 | "Excess arguments (%u) - using only %u" , |
169 | Info->ParamCount, ACPI_METHOD_NUM_ARGS)); |
170 | |
171 | Info->ParamCount = ACPI_METHOD_NUM_ARGS; |
172 | } |
173 | } |
174 | |
175 | /* |
176 | * For predefined names: Check that the declared argument count |
177 | * matches the ACPI spec -- otherwise this is a BIOS error. |
178 | */ |
179 | AcpiNsCheckAcpiCompliance (Info->FullPathname, Info->Node, |
180 | Info->Predefined); |
181 | |
182 | /* |
183 | * For all names: Check that the incoming argument count for |
184 | * this method/object matches the actual ASL/AML definition. |
185 | */ |
186 | AcpiNsCheckArgumentCount (Info->FullPathname, Info->Node, |
187 | Info->ParamCount, Info->Predefined); |
188 | |
189 | /* For predefined names: Typecheck all incoming arguments */ |
190 | |
191 | AcpiNsCheckArgumentTypes (Info); |
192 | |
193 | /* |
194 | * Three major evaluation cases: |
195 | * |
196 | * 1) Object types that cannot be evaluated by definition |
197 | * 2) The object is a control method -- execute it |
198 | * 3) The object is not a method -- just return it's current value |
199 | */ |
200 | switch (AcpiNsGetType (Info->Node)) |
201 | { |
202 | case ACPI_TYPE_DEVICE: |
203 | case ACPI_TYPE_EVENT: |
204 | case ACPI_TYPE_MUTEX: |
205 | case ACPI_TYPE_REGION: |
206 | case ACPI_TYPE_THERMAL: |
207 | case ACPI_TYPE_LOCAL_SCOPE: |
208 | /* |
209 | * 1) Disallow evaluation of certain object types. For these, |
210 | * object evaluation is undefined and not supported. |
211 | */ |
212 | ACPI_ERROR ((AE_INFO, |
213 | "%s: Evaluation of object type [%s] is not supported" , |
214 | Info->FullPathname, |
215 | AcpiUtGetTypeName (Info->Node->Type))); |
216 | |
217 | Status = AE_TYPE; |
218 | goto Cleanup; |
219 | |
220 | case ACPI_TYPE_METHOD: |
221 | /* |
222 | * 2) Object is a control method - execute it |
223 | */ |
224 | |
225 | /* Verify that there is a method object associated with this node */ |
226 | |
227 | if (!Info->ObjDesc) |
228 | { |
229 | ACPI_ERROR ((AE_INFO, "%s: Method has no attached sub-object" , |
230 | Info->FullPathname)); |
231 | Status = AE_NULL_OBJECT; |
232 | goto Cleanup; |
233 | } |
234 | |
235 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, |
236 | "**** Execute method [%s] at AML address %p length %X\n" , |
237 | Info->FullPathname, |
238 | Info->ObjDesc->Method.AmlStart + 1, |
239 | Info->ObjDesc->Method.AmlLength - 1)); |
240 | |
241 | /* |
242 | * Any namespace deletion must acquire both the namespace and |
243 | * interpreter locks to ensure that no thread is using the portion of |
244 | * the namespace that is being deleted. |
245 | * |
246 | * Execute the method via the interpreter. The interpreter is locked |
247 | * here before calling into the AML parser |
248 | */ |
249 | AcpiExEnterInterpreter (); |
250 | Status = AcpiPsExecuteMethod (Info); |
251 | AcpiExExitInterpreter (); |
252 | break; |
253 | |
254 | default: |
255 | /* |
256 | * 3) All other non-method objects -- get the current object value |
257 | */ |
258 | |
259 | /* |
260 | * Some objects require additional resolution steps (e.g., the Node |
261 | * may be a field that must be read, etc.) -- we can't just grab |
262 | * the object out of the node. |
263 | * |
264 | * Use ResolveNodeToValue() to get the associated value. |
265 | * |
266 | * NOTE: we can get away with passing in NULL for a walk state because |
267 | * the Node is guaranteed to not be a reference to either a method |
268 | * local or a method argument (because this interface is never called |
269 | * from a running method.) |
270 | * |
271 | * Even though we do not directly invoke the interpreter for object |
272 | * resolution, we must lock it because we could access an OpRegion. |
273 | * The OpRegion access code assumes that the interpreter is locked. |
274 | */ |
275 | AcpiExEnterInterpreter (); |
276 | |
277 | /* TBD: ResolveNodeToValue has a strange interface, fix */ |
278 | |
279 | Info->ReturnObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Info->Node); |
280 | |
281 | Status = AcpiExResolveNodeToValue (ACPI_CAST_INDIRECT_PTR ( |
282 | ACPI_NAMESPACE_NODE, &Info->ReturnObject), NULL); |
283 | AcpiExExitInterpreter (); |
284 | |
285 | if (ACPI_FAILURE (Status)) |
286 | { |
287 | Info->ReturnObject = NULL; |
288 | goto Cleanup; |
289 | } |
290 | |
291 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returned object %p [%s]\n" , |
292 | Info->ReturnObject, |
293 | AcpiUtGetObjectTypeName (Info->ReturnObject))); |
294 | |
295 | Status = AE_CTRL_RETURN_VALUE; /* Always has a "return value" */ |
296 | break; |
297 | } |
298 | |
299 | /* |
300 | * For predefined names, check the return value against the ACPI |
301 | * specification. Some incorrect return value types are repaired. |
302 | */ |
303 | (void) AcpiNsCheckReturnValue (Info->Node, Info, Info->ParamCount, |
304 | Status, &Info->ReturnObject); |
305 | |
306 | /* Check if there is a return value that must be dealt with */ |
307 | |
308 | if (Status == AE_CTRL_RETURN_VALUE) |
309 | { |
310 | /* If caller does not want the return value, delete it */ |
311 | |
312 | if (Info->Flags & ACPI_IGNORE_RETURN_VALUE) |
313 | { |
314 | AcpiUtRemoveReference (Info->ReturnObject); |
315 | Info->ReturnObject = NULL; |
316 | } |
317 | |
318 | /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ |
319 | |
320 | Status = AE_OK; |
321 | } |
322 | |
323 | ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, |
324 | "*** Completed evaluation of object %s ***\n" , |
325 | Info->RelativePathname)); |
326 | |
327 | Cleanup: |
328 | /* |
329 | * Namespace was unlocked by the handling AcpiNs* function, so we |
330 | * just free the pathname and return |
331 | */ |
332 | ACPI_FREE (Info->FullPathname); |
333 | Info->FullPathname = NULL; |
334 | return_ACPI_STATUS (Status); |
335 | } |
336 | |
337 | |
338 | /******************************************************************************* |
339 | * |
340 | * FUNCTION: AcpiNsExecModuleCodeList |
341 | * |
342 | * PARAMETERS: None |
343 | * |
344 | * RETURN: None. Exceptions during method execution are ignored, since |
345 | * we cannot abort a table load. |
346 | * |
347 | * DESCRIPTION: Execute all elements of the global module-level code list. |
348 | * Each element is executed as a single control method. |
349 | * |
350 | ******************************************************************************/ |
351 | |
352 | void |
353 | AcpiNsExecModuleCodeList ( |
354 | void) |
355 | { |
356 | ACPI_OPERAND_OBJECT *Prev; |
357 | ACPI_OPERAND_OBJECT *Next; |
358 | ACPI_EVALUATE_INFO *Info; |
359 | UINT32 MethodCount = 0; |
360 | |
361 | |
362 | ACPI_FUNCTION_TRACE (NsExecModuleCodeList); |
363 | |
364 | |
365 | /* Exit now if the list is empty */ |
366 | |
367 | Next = AcpiGbl_ModuleCodeList; |
368 | if (!Next) |
369 | { |
370 | return_VOID; |
371 | } |
372 | |
373 | /* Allocate the evaluation information block */ |
374 | |
375 | Info = ACPI_ALLOCATE (sizeof (ACPI_EVALUATE_INFO)); |
376 | if (!Info) |
377 | { |
378 | return_VOID; |
379 | } |
380 | |
381 | /* Walk the list, executing each "method" */ |
382 | |
383 | while (Next) |
384 | { |
385 | Prev = Next; |
386 | Next = Next->Method.Mutex; |
387 | |
388 | /* Clear the link field and execute the method */ |
389 | |
390 | Prev->Method.Mutex = NULL; |
391 | AcpiNsExecModuleCode (Prev, Info); |
392 | MethodCount++; |
393 | |
394 | /* Delete the (temporary) method object */ |
395 | |
396 | AcpiUtRemoveReference (Prev); |
397 | } |
398 | |
399 | ACPI_INFO (( |
400 | "Executed %u blocks of module-level executable AML code" , |
401 | MethodCount)); |
402 | |
403 | ACPI_FREE (Info); |
404 | AcpiGbl_ModuleCodeList = NULL; |
405 | return_VOID; |
406 | } |
407 | |
408 | |
409 | /******************************************************************************* |
410 | * |
411 | * FUNCTION: AcpiNsExecModuleCode |
412 | * |
413 | * PARAMETERS: MethodObj - Object container for the module-level code |
414 | * Info - Info block for method evaluation |
415 | * |
416 | * RETURN: None. Exceptions during method execution are ignored, since |
417 | * we cannot abort a table load. |
418 | * |
419 | * DESCRIPTION: Execute a control method containing a block of module-level |
420 | * executable AML code. The control method is temporarily |
421 | * installed to the root node, then evaluated. |
422 | * |
423 | ******************************************************************************/ |
424 | |
425 | static void |
426 | AcpiNsExecModuleCode ( |
427 | ACPI_OPERAND_OBJECT *MethodObj, |
428 | ACPI_EVALUATE_INFO *Info) |
429 | { |
430 | ACPI_OPERAND_OBJECT *ParentObj; |
431 | ACPI_NAMESPACE_NODE *ParentNode; |
432 | ACPI_OBJECT_TYPE Type; |
433 | ACPI_STATUS Status; |
434 | |
435 | |
436 | ACPI_FUNCTION_TRACE (NsExecModuleCode); |
437 | |
438 | |
439 | /* |
440 | * Get the parent node. We cheat by using the NextObject field |
441 | * of the method object descriptor. |
442 | */ |
443 | ParentNode = ACPI_CAST_PTR ( |
444 | ACPI_NAMESPACE_NODE, MethodObj->Method.NextObject); |
445 | Type = AcpiNsGetType (ParentNode); |
446 | |
447 | /* |
448 | * Get the region handler and save it in the method object. We may need |
449 | * this if an operation region declaration causes a _REG method to be run. |
450 | * |
451 | * We can't do this in AcpiPsLinkModuleCode because |
452 | * AcpiGbl_RootNode->Object is NULL at PASS1. |
453 | */ |
454 | if ((Type == ACPI_TYPE_DEVICE) && ParentNode->Object) |
455 | { |
456 | MethodObj->Method.Dispatch.Handler = |
457 | ParentNode->Object->Device.Handler; |
458 | } |
459 | |
460 | /* Must clear NextObject (AcpiNsAttachObject needs the field) */ |
461 | |
462 | MethodObj->Method.NextObject = NULL; |
463 | |
464 | /* Initialize the evaluation information block */ |
465 | |
466 | memset (Info, 0, sizeof (ACPI_EVALUATE_INFO)); |
467 | Info->PrefixNode = ParentNode; |
468 | |
469 | /* |
470 | * Get the currently attached parent object. Add a reference, |
471 | * because the ref count will be decreased when the method object |
472 | * is installed to the parent node. |
473 | */ |
474 | ParentObj = AcpiNsGetAttachedObject (ParentNode); |
475 | if (ParentObj) |
476 | { |
477 | AcpiUtAddReference (ParentObj); |
478 | } |
479 | |
480 | /* Install the method (module-level code) in the parent node */ |
481 | |
482 | Status = AcpiNsAttachObject (ParentNode, MethodObj, ACPI_TYPE_METHOD); |
483 | if (ACPI_FAILURE (Status)) |
484 | { |
485 | goto Exit; |
486 | } |
487 | |
488 | /* Execute the parent node as a control method */ |
489 | |
490 | Status = AcpiNsEvaluate (Info); |
491 | |
492 | ACPI_DEBUG_PRINT ((ACPI_DB_INIT_NAMES, |
493 | "Executed module-level code at %p\n" , |
494 | MethodObj->Method.AmlStart)); |
495 | |
496 | /* Delete a possible implicit return value (in slack mode) */ |
497 | |
498 | if (Info->ReturnObject) |
499 | { |
500 | AcpiUtRemoveReference (Info->ReturnObject); |
501 | } |
502 | |
503 | /* Detach the temporary method object */ |
504 | |
505 | AcpiNsDetachObject (ParentNode); |
506 | |
507 | /* Restore the original parent object */ |
508 | |
509 | if (ParentObj) |
510 | { |
511 | Status = AcpiNsAttachObject (ParentNode, ParentObj, Type); |
512 | } |
513 | else |
514 | { |
515 | ParentNode->Type = (UINT8) Type; |
516 | } |
517 | |
518 | Exit: |
519 | if (ParentObj) |
520 | { |
521 | AcpiUtRemoveReference (ParentObj); |
522 | } |
523 | return_VOID; |
524 | } |
525 | |