1 /******************************************************************************* 2 * 3 * Module Name: nseval - Object evaluation, includes control method execution 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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 <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/acparser.h> 47 #include <contrib/dev/acpica/include/acinterp.h> 48 #include <contrib/dev/acpica/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: 67 * PrefixNode - Prefix or Method/Object Node to execute 68 * RelativePath - Name of method to execute, If NULL, the 69 * Node is the object to execute 70 * Parameters - List of parameters to pass to the method, 71 * terminated by NULL. Params itself may be 72 * NULL if no parameters are being passed. 73 * ReturnObject - Where to put method's return value (if 74 * any). If NULL, no value is returned. 75 * ParameterType - Type of Parameter list 76 * ReturnObject - Where to put method's return value (if 77 * any). If NULL, no value is returned. 78 * Flags - ACPI_IGNORE_RETURN_VALUE to delete return 79 * 80 * RETURN: Status 81 * 82 * DESCRIPTION: Execute a control method or return the current value of an 83 * ACPI namespace object. 84 * 85 * MUTEX: Locks interpreter 86 * 87 ******************************************************************************/ 88 89 ACPI_STATUS 90 AcpiNsEvaluate ( 91 ACPI_EVALUATE_INFO *Info) 92 { 93 ACPI_STATUS Status; 94 95 96 ACPI_FUNCTION_TRACE (NsEvaluate); 97 98 99 if (!Info) 100 { 101 return_ACPI_STATUS (AE_BAD_PARAMETER); 102 } 103 104 if (!Info->Node) 105 { 106 /* 107 * Get the actual namespace node for the target object if we 108 * need to. Handles these cases: 109 * 110 * 1) Null node, valid pathname from root (absolute path) 111 * 2) Node and valid pathname (path relative to Node) 112 * 3) Node, Null pathname 113 */ 114 Status = AcpiNsGetNode (Info->PrefixNode, Info->RelativePathname, 115 ACPI_NS_NO_UPSEARCH, &Info->Node); 116 if (ACPI_FAILURE (Status)) 117 { 118 return_ACPI_STATUS (Status); 119 } 120 } 121 122 /* 123 * For a method alias, we must grab the actual method node so that 124 * proper scoping context will be established before execution. 125 */ 126 if (AcpiNsGetType (Info->Node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) 127 { 128 Info->Node = ACPI_CAST_PTR ( 129 ACPI_NAMESPACE_NODE, Info->Node->Object); 130 } 131 132 /* Complete the info block initialization */ 133 134 Info->ReturnObject = NULL; 135 Info->NodeFlags = Info->Node->Flags; 136 Info->ObjDesc = AcpiNsGetAttachedObject (Info->Node); 137 138 ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", 139 Info->RelativePathname, Info->Node, 140 AcpiNsGetAttachedObject (Info->Node))); 141 142 /* Get info if we have a predefined name (_HID, etc.) */ 143 144 Info->Predefined = AcpiUtMatchPredefinedMethod (Info->Node->Name.Ascii); 145 146 /* Get the full pathname to the object, for use in warning messages */ 147 148 Info->FullPathname = AcpiNsGetExternalPathname (Info->Node); 149 if (!Info->FullPathname) 150 { 151 return_ACPI_STATUS (AE_NO_MEMORY); 152 } 153 154 /* Count the number of arguments being passed in */ 155 156 Info->ParamCount = 0; 157 if (Info->Parameters) 158 { 159 while (Info->Parameters[Info->ParamCount]) 160 { 161 Info->ParamCount++; 162 } 163 164 /* Warn on impossible argument count */ 165 166 if (Info->ParamCount > ACPI_METHOD_NUM_ARGS) 167 { 168 ACPI_WARN_PREDEFINED ((AE_INFO, Info->FullPathname, ACPI_WARN_ALWAYS, 169 "Excess arguments (%u) - using only %u", 170 Info->ParamCount, ACPI_METHOD_NUM_ARGS)); 171 172 Info->ParamCount = ACPI_METHOD_NUM_ARGS; 173 } 174 } 175 176 /* 177 * For predefined names: Check that the declared argument count 178 * matches the ACPI spec -- otherwise this is a BIOS error. 179 */ 180 AcpiNsCheckAcpiCompliance (Info->FullPathname, Info->Node, 181 Info->Predefined); 182 183 /* 184 * For all names: Check that the incoming argument count for 185 * this method/object matches the actual ASL/AML definition. 186 */ 187 AcpiNsCheckArgumentCount (Info->FullPathname, Info->Node, 188 Info->ParamCount, Info->Predefined); 189 190 /* For predefined names: Typecheck all incoming arguments */ 191 192 AcpiNsCheckArgumentTypes (Info); 193 194 /* 195 * Three major evaluation cases: 196 * 197 * 1) Object types that cannot be evaluated by definition 198 * 2) The object is a control method -- execute it 199 * 3) The object is not a method -- just return it's current value 200 */ 201 switch (AcpiNsGetType (Info->Node)) 202 { 203 case ACPI_TYPE_DEVICE: 204 case ACPI_TYPE_EVENT: 205 case ACPI_TYPE_MUTEX: 206 case ACPI_TYPE_REGION: 207 case ACPI_TYPE_THERMAL: 208 case ACPI_TYPE_LOCAL_SCOPE: 209 /* 210 * 1) Disallow evaluation of certain object types. For these, 211 * object evaluation is undefined and not supported. 212 */ 213 ACPI_ERROR ((AE_INFO, 214 "%s: Evaluation of object type [%s] is not supported", 215 Info->FullPathname, 216 AcpiUtGetTypeName (Info->Node->Type))); 217 218 Status = AE_TYPE; 219 goto Cleanup; 220 221 case ACPI_TYPE_METHOD: 222 /* 223 * 2) Object is a control method - execute it 224 */ 225 226 /* Verify that there is a method object associated with this node */ 227 228 if (!Info->ObjDesc) 229 { 230 ACPI_ERROR ((AE_INFO, "%s: Method has no attached sub-object", 231 Info->FullPathname)); 232 Status = AE_NULL_OBJECT; 233 goto Cleanup; 234 } 235 236 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 237 "**** Execute method [%s] at AML address %p length %X\n", 238 Info->FullPathname, 239 Info->ObjDesc->Method.AmlStart + 1, 240 Info->ObjDesc->Method.AmlLength - 1)); 241 242 /* 243 * Any namespace deletion must acquire both the namespace and 244 * interpreter locks to ensure that no thread is using the portion of 245 * the namespace that is being deleted. 246 * 247 * Execute the method via the interpreter. The interpreter is locked 248 * here before calling into the AML parser 249 */ 250 AcpiExEnterInterpreter (); 251 Status = AcpiPsExecuteMethod (Info); 252 AcpiExExitInterpreter (); 253 break; 254 255 default: 256 /* 257 * 3) All other non-method objects -- get the current object value 258 */ 259 260 /* 261 * Some objects require additional resolution steps (e.g., the Node 262 * may be a field that must be read, etc.) -- we can't just grab 263 * the object out of the node. 264 * 265 * Use ResolveNodeToValue() to get the associated value. 266 * 267 * NOTE: we can get away with passing in NULL for a walk state because 268 * the Node is guaranteed to not be a reference to either a method 269 * local or a method argument (because this interface is never called 270 * from a running method.) 271 * 272 * Even though we do not directly invoke the interpreter for object 273 * resolution, we must lock it because we could access an OpRegion. 274 * The OpRegion access code assumes that the interpreter is locked. 275 */ 276 AcpiExEnterInterpreter (); 277 278 /* TBD: ResolveNodeToValue has a strange interface, fix */ 279 280 Info->ReturnObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, Info->Node); 281 282 Status = AcpiExResolveNodeToValue (ACPI_CAST_INDIRECT_PTR ( 283 ACPI_NAMESPACE_NODE, &Info->ReturnObject), NULL); 284 AcpiExExitInterpreter (); 285 286 if (ACPI_FAILURE (Status)) 287 { 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 ((AE_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 (ACPI_NAMESPACE_NODE, 444 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 ACPI_MEMSET (Info, 0, sizeof (ACPI_EVALUATE_INFO)); 467 Info->PrefixNode = ParentNode; 468 469 /* 470 * Get the currently attached parent object. Add a reference, because the 471 * ref count will be decreased when the method object is installed to 472 * 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, 483 ACPI_TYPE_METHOD); 484 if (ACPI_FAILURE (Status)) 485 { 486 goto Exit; 487 } 488 489 /* Execute the parent node as a control method */ 490 491 Status = AcpiNsEvaluate (Info); 492 493 ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "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