1 /****************************************************************************** 2 * 3 * Module Name: aslmethod.c - Control method analysis walk 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2013, 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 45 #include <contrib/dev/acpica/compiler/aslcompiler.h> 46 #include "aslcompiler.y.h" 47 48 49 #define _COMPONENT ACPI_COMPILER 50 ACPI_MODULE_NAME ("aslmethod") 51 52 53 /******************************************************************************* 54 * 55 * FUNCTION: MtMethodAnalysisWalkBegin 56 * 57 * PARAMETERS: ASL_WALK_CALLBACK 58 * 59 * RETURN: Status 60 * 61 * DESCRIPTION: Descending callback for the analysis walk. Check methods for: 62 * 1) Initialized local variables 63 * 2) Valid arguments 64 * 3) Return types 65 * 66 ******************************************************************************/ 67 68 ACPI_STATUS 69 MtMethodAnalysisWalkBegin ( 70 ACPI_PARSE_OBJECT *Op, 71 UINT32 Level, 72 void *Context) 73 { 74 ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; 75 ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack; 76 ACPI_PARSE_OBJECT *Next; 77 UINT32 RegisterNumber; 78 UINT32 i; 79 char LocalName[] = "Local0"; 80 char ArgName[] = "Arg0"; 81 ACPI_PARSE_OBJECT *ArgNode; 82 ACPI_PARSE_OBJECT *NextType; 83 ACPI_PARSE_OBJECT *NextParamType; 84 UINT8 ActualArgs = 0; 85 86 87 switch (Op->Asl.ParseOpcode) 88 { 89 case PARSEOP_METHOD: 90 91 TotalMethods++; 92 93 /* Create and init method info */ 94 95 MethodInfo = UtLocalCalloc (sizeof (ASL_METHOD_INFO)); 96 MethodInfo->Next = WalkInfo->MethodStack; 97 MethodInfo->Op = Op; 98 99 WalkInfo->MethodStack = MethodInfo; 100 101 /* Get the name node, ignored here */ 102 103 Next = Op->Asl.Child; 104 105 /* Get the NumArguments node */ 106 107 Next = Next->Asl.Next; 108 MethodInfo->NumArguments = (UINT8) 109 (((UINT8) Next->Asl.Value.Integer) & 0x07); 110 111 /* Get the SerializeRule and SyncLevel nodes, ignored here */ 112 113 Next = Next->Asl.Next; 114 Next = Next->Asl.Next; 115 ArgNode = Next; 116 117 /* Get the ReturnType node */ 118 119 Next = Next->Asl.Next; 120 121 NextType = Next->Asl.Child; 122 while (NextType) 123 { 124 /* Get and map each of the ReturnTypes */ 125 126 MethodInfo->ValidReturnTypes |= AnMapObjTypeToBtype (NextType); 127 NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 128 NextType = NextType->Asl.Next; 129 } 130 131 /* Get the ParameterType node */ 132 133 Next = Next->Asl.Next; 134 135 NextType = Next->Asl.Child; 136 while (NextType) 137 { 138 if (NextType->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 139 { 140 NextParamType = NextType->Asl.Child; 141 while (NextParamType) 142 { 143 MethodInfo->ValidArgTypes[ActualArgs] |= AnMapObjTypeToBtype (NextParamType); 144 NextParamType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 145 NextParamType = NextParamType->Asl.Next; 146 } 147 } 148 else 149 { 150 MethodInfo->ValidArgTypes[ActualArgs] = 151 AnMapObjTypeToBtype (NextType); 152 NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 153 ActualArgs++; 154 } 155 156 NextType = NextType->Asl.Next; 157 } 158 159 if ((MethodInfo->NumArguments) && 160 (MethodInfo->NumArguments != ActualArgs)) 161 { 162 /* error: Param list did not match number of args */ 163 } 164 165 /* Allow numarguments == 0 for Function() */ 166 167 if ((!MethodInfo->NumArguments) && (ActualArgs)) 168 { 169 MethodInfo->NumArguments = ActualArgs; 170 ArgNode->Asl.Value.Integer |= ActualArgs; 171 } 172 173 /* 174 * Actual arguments are initialized at method entry. 175 * All other ArgX "registers" can be used as locals, so we 176 * track their initialization. 177 */ 178 for (i = 0; i < MethodInfo->NumArguments; i++) 179 { 180 MethodInfo->ArgInitialized[i] = TRUE; 181 } 182 break; 183 184 185 case PARSEOP_METHODCALL: 186 187 if (MethodInfo && 188 (Op->Asl.Node == MethodInfo->Op->Asl.Node)) 189 { 190 AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName); 191 } 192 break; 193 194 195 case PARSEOP_LOCAL0: 196 case PARSEOP_LOCAL1: 197 case PARSEOP_LOCAL2: 198 case PARSEOP_LOCAL3: 199 case PARSEOP_LOCAL4: 200 case PARSEOP_LOCAL5: 201 case PARSEOP_LOCAL6: 202 case PARSEOP_LOCAL7: 203 204 if (!MethodInfo) 205 { 206 /* 207 * Local was used outside a control method, or there was an error 208 * in the method declaration. 209 */ 210 AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName); 211 return (AE_ERROR); 212 } 213 214 RegisterNumber = (Op->Asl.AmlOpcode & 0x000F); 215 216 /* 217 * If the local is being used as a target, mark the local 218 * initialized 219 */ 220 if (Op->Asl.CompileFlags & NODE_IS_TARGET) 221 { 222 MethodInfo->LocalInitialized[RegisterNumber] = TRUE; 223 } 224 225 /* 226 * Otherwise, this is a reference, check if the local 227 * has been previously initialized. 228 * 229 * The only operator that accepts an uninitialized value is ObjectType() 230 */ 231 else if ((!MethodInfo->LocalInitialized[RegisterNumber]) && 232 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) 233 { 234 LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30); 235 AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName); 236 } 237 break; 238 239 240 case PARSEOP_ARG0: 241 case PARSEOP_ARG1: 242 case PARSEOP_ARG2: 243 case PARSEOP_ARG3: 244 case PARSEOP_ARG4: 245 case PARSEOP_ARG5: 246 case PARSEOP_ARG6: 247 248 if (!MethodInfo) 249 { 250 /* 251 * Arg was used outside a control method, or there was an error 252 * in the method declaration. 253 */ 254 AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName); 255 return (AE_ERROR); 256 } 257 258 RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8; 259 ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30); 260 261 /* 262 * If the Arg is being used as a target, mark the local 263 * initialized 264 */ 265 if (Op->Asl.CompileFlags & NODE_IS_TARGET) 266 { 267 MethodInfo->ArgInitialized[RegisterNumber] = TRUE; 268 } 269 270 /* 271 * Otherwise, this is a reference, check if the Arg 272 * has been previously initialized. 273 * 274 * The only operator that accepts an uninitialized value is ObjectType() 275 */ 276 else if ((!MethodInfo->ArgInitialized[RegisterNumber]) && 277 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) 278 { 279 AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName); 280 } 281 282 /* Flag this arg if it is not a "real" argument to the method */ 283 284 if (RegisterNumber >= MethodInfo->NumArguments) 285 { 286 AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName); 287 } 288 break; 289 290 291 case PARSEOP_RETURN: 292 293 if (!MethodInfo) 294 { 295 /* 296 * Probably was an error in the method declaration, 297 * no additional error here 298 */ 299 ACPI_WARNING ((AE_INFO, "%p, No parent method", Op)); 300 return (AE_ERROR); 301 } 302 303 /* 304 * A child indicates a possible return value. A simple Return or 305 * Return() is marked with NODE_IS_NULL_RETURN by the parser so 306 * that it is not counted as a "real" return-with-value, although 307 * the AML code that is actually emitted is Return(0). The AML 308 * definition of Return has a required parameter, so we are 309 * forced to convert a null return to Return(0). 310 */ 311 if ((Op->Asl.Child) && 312 (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && 313 (!(Op->Asl.Child->Asl.CompileFlags & NODE_IS_NULL_RETURN))) 314 { 315 MethodInfo->NumReturnWithValue++; 316 } 317 else 318 { 319 MethodInfo->NumReturnNoValue++; 320 } 321 break; 322 323 324 case PARSEOP_BREAK: 325 case PARSEOP_CONTINUE: 326 327 Next = Op->Asl.Parent; 328 while (Next) 329 { 330 if (Next->Asl.ParseOpcode == PARSEOP_WHILE) 331 { 332 break; 333 } 334 Next = Next->Asl.Parent; 335 } 336 337 if (!Next) 338 { 339 AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL); 340 } 341 break; 342 343 344 case PARSEOP_STALL: 345 346 /* We can range check if the argument is an integer */ 347 348 if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) && 349 (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX)) 350 { 351 AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL); 352 } 353 break; 354 355 356 case PARSEOP_DEVICE: 357 case PARSEOP_EVENT: 358 case PARSEOP_MUTEX: 359 case PARSEOP_OPERATIONREGION: 360 case PARSEOP_POWERRESOURCE: 361 case PARSEOP_PROCESSOR: 362 case PARSEOP_THERMALZONE: 363 364 /* 365 * The first operand is a name to be created in the namespace. 366 * Check against the reserved list. 367 */ 368 i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg); 369 if (i < ACPI_VALID_RESERVED_NAME_MAX) 370 { 371 AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, Op, Op->Asl.ExternalName); 372 } 373 break; 374 375 376 case PARSEOP_NAME: 377 378 /* Typecheck any predefined names statically defined with Name() */ 379 380 ApCheckForPredefinedObject (Op, Op->Asl.NameSeg); 381 382 /* Special typechecking for _HID */ 383 384 if (!ACPI_STRCMP (METHOD_NAME__HID, Op->Asl.NameSeg)) 385 { 386 Next = Op->Asl.Child->Asl.Next; 387 AnCheckId (Next, ASL_TYPE_HID); 388 } 389 390 /* Special typechecking for _CID */ 391 392 else if (!ACPI_STRCMP (METHOD_NAME__CID, Op->Asl.NameSeg)) 393 { 394 Next = Op->Asl.Child->Asl.Next; 395 396 if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) || 397 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) 398 { 399 Next = Next->Asl.Child; 400 while (Next) 401 { 402 AnCheckId (Next, ASL_TYPE_CID); 403 Next = Next->Asl.Next; 404 } 405 } 406 else 407 { 408 AnCheckId (Next, ASL_TYPE_CID); 409 } 410 } 411 break; 412 413 414 default: 415 break; 416 } 417 418 return (AE_OK); 419 } 420 421 422 /******************************************************************************* 423 * 424 * FUNCTION: MtMethodAnalysisWalkEnd 425 * 426 * PARAMETERS: ASL_WALK_CALLBACK 427 * 428 * RETURN: Status 429 * 430 * DESCRIPTION: Ascending callback for analysis walk. Complete method 431 * return analysis. 432 * 433 ******************************************************************************/ 434 435 ACPI_STATUS 436 MtMethodAnalysisWalkEnd ( 437 ACPI_PARSE_OBJECT *Op, 438 UINT32 Level, 439 void *Context) 440 { 441 ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; 442 ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack; 443 444 445 switch (Op->Asl.ParseOpcode) 446 { 447 case PARSEOP_METHOD: 448 case PARSEOP_RETURN: 449 if (!MethodInfo) 450 { 451 printf ("No method info for method! [%s]\n", Op->Asl.Namepath); 452 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op, 453 "No method info for this method"); 454 455 CmCleanupAndExit (); 456 return (AE_AML_INTERNAL); 457 } 458 break; 459 460 default: 461 break; 462 } 463 464 switch (Op->Asl.ParseOpcode) 465 { 466 case PARSEOP_METHOD: 467 468 WalkInfo->MethodStack = MethodInfo->Next; 469 470 /* 471 * Check if there is no return statement at the end of the 472 * method AND we can actually get there -- i.e., the execution 473 * of the method can possibly terminate without a return statement. 474 */ 475 if ((!AnLastStatementIsReturn (Op)) && 476 (!(Op->Asl.CompileFlags & NODE_HAS_NO_EXIT))) 477 { 478 /* 479 * No return statement, and execution can possibly exit 480 * via this path. This is equivalent to Return () 481 */ 482 MethodInfo->NumReturnNoValue++; 483 } 484 485 /* 486 * Check for case where some return statements have a return value 487 * and some do not. Exit without a return statement is a return with 488 * no value 489 */ 490 if (MethodInfo->NumReturnNoValue && 491 MethodInfo->NumReturnWithValue) 492 { 493 AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op, 494 Op->Asl.ExternalName); 495 } 496 497 /* 498 * If there are any RETURN() statements with no value, or there is a 499 * control path that allows the method to exit without a return value, 500 * we mark the method as a method that does not return a value. This 501 * knowledge can be used to check method invocations that expect a 502 * returned value. 503 */ 504 if (MethodInfo->NumReturnNoValue) 505 { 506 if (MethodInfo->NumReturnWithValue) 507 { 508 Op->Asl.CompileFlags |= NODE_METHOD_SOME_NO_RETVAL; 509 } 510 else 511 { 512 Op->Asl.CompileFlags |= NODE_METHOD_NO_RETVAL; 513 } 514 } 515 516 /* 517 * Check predefined method names for correct return behavior 518 * and correct number of arguments. Also, some special checks 519 * For GPE and _REG methods. 520 */ 521 if (ApCheckForPredefinedMethod (Op, MethodInfo)) 522 { 523 /* Special check for two names like _L01 and _E01 in same scope */ 524 525 ApCheckForGpeNameConflict (Op); 526 527 /* 528 * Special check for _REG: Must have an operation region definition 529 * within the same scope! 530 */ 531 ApCheckRegMethod (Op); 532 } 533 534 ACPI_FREE (MethodInfo); 535 break; 536 537 538 case PARSEOP_NAME: 539 540 /* Special check for two names like _L01 and _E01 in same scope */ 541 542 ApCheckForGpeNameConflict (Op); 543 break; 544 545 546 case PARSEOP_RETURN: 547 548 /* 549 * If the parent is a predefined method name, attempt to typecheck 550 * the return value. Only static types can be validated. 551 */ 552 ApCheckPredefinedReturnValue (Op, MethodInfo); 553 554 /* 555 * The parent block does not "exit" and continue execution -- the 556 * method is terminated here with the Return() statement. 557 */ 558 Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT; 559 560 /* Used in the "typing" pass later */ 561 562 Op->Asl.ParentMethod = MethodInfo->Op; 563 564 /* 565 * If there is a peer node after the return statement, then this 566 * node is unreachable code -- i.e., it won't be executed because of 567 * the preceding Return() statement. 568 */ 569 if (Op->Asl.Next) 570 { 571 AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE, Op->Asl.Next, NULL); 572 } 573 break; 574 575 576 case PARSEOP_IF: 577 578 if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) && 579 (Op->Asl.Next) && 580 (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE)) 581 { 582 /* 583 * This IF has a corresponding ELSE. The IF block has no exit, 584 * (it contains an unconditional Return) 585 * mark the ELSE block to remember this fact. 586 */ 587 Op->Asl.Next->Asl.CompileFlags |= NODE_IF_HAS_NO_EXIT; 588 } 589 break; 590 591 592 case PARSEOP_ELSE: 593 594 if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) && 595 (Op->Asl.CompileFlags & NODE_IF_HAS_NO_EXIT)) 596 { 597 /* 598 * This ELSE block has no exit and the corresponding IF block 599 * has no exit either. Therefore, the parent node has no exit. 600 */ 601 Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT; 602 } 603 break; 604 605 606 default: 607 608 if ((Op->Asl.CompileFlags & NODE_HAS_NO_EXIT) && 609 (Op->Asl.Parent)) 610 { 611 /* If this node has no exit, then the parent has no exit either */ 612 613 Op->Asl.Parent->Asl.CompileFlags |= NODE_HAS_NO_EXIT; 614 } 615 break; 616 } 617 618 return (AE_OK); 619 } 620