1 /****************************************************************************** 2 * 3 * Module Name: aslmethod.c - Control method analysis walk 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2020, 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 "aslcompiler.h" 45 #include "aslcompiler.y.h" 46 #include "acnamesp.h" 47 #include "acparser.h" 48 #include "amlcode.h" 49 50 51 #define _COMPONENT ACPI_COMPILER 52 ACPI_MODULE_NAME ("aslmethod") 53 54 55 /* Local prototypes */ 56 57 static void 58 MtCheckNamedObjectInMethod ( 59 ACPI_PARSE_OBJECT *Op, 60 ASL_METHOD_INFO *MethodInfo); 61 62 static void 63 MtCheckStaticOperationRegionInMethod ( 64 ACPI_PARSE_OBJECT *Op); 65 66 67 /******************************************************************************* 68 * 69 * FUNCTION: MtMethodAnalysisWalkBegin 70 * 71 * PARAMETERS: ASL_WALK_CALLBACK 72 * 73 * RETURN: Status 74 * 75 * DESCRIPTION: Descending callback for the analysis walk. Check methods for: 76 * 1) Initialized local variables 77 * 2) Valid arguments 78 * 3) Return types 79 * 80 ******************************************************************************/ 81 82 ACPI_STATUS 83 MtMethodAnalysisWalkBegin ( 84 ACPI_PARSE_OBJECT *Op, 85 UINT32 Level, 86 void *Context) 87 { 88 ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; 89 ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack; 90 ACPI_PARSE_OBJECT *Next; 91 UINT32 RegisterNumber; 92 UINT32 i; 93 char LocalName[] = "Local0"; 94 char ArgName[] = "Arg0"; 95 ACPI_PARSE_OBJECT *ArgNode; 96 ACPI_PARSE_OBJECT *NextType; 97 UINT8 ActualArgs = 0; 98 BOOLEAN HidExists; 99 BOOLEAN AdrExists; 100 101 102 /* Build cross-reference output file if requested */ 103 104 if (AslGbl_CrossReferenceOutput) 105 { 106 OtXrefWalkPart1 (Op, Level, MethodInfo); 107 } 108 109 switch (Op->Asl.ParseOpcode) 110 { 111 case PARSEOP_METHOD: 112 113 AslGbl_TotalMethods++; 114 115 /* Create and init method info */ 116 117 MethodInfo = UtLocalCalloc (sizeof (ASL_METHOD_INFO)); 118 MethodInfo->Next = WalkInfo->MethodStack; 119 MethodInfo->Op = Op; 120 121 WalkInfo->MethodStack = MethodInfo; 122 123 /* 124 * Special handling for _PSx methods. Dependency rules (same scope): 125 * 126 * 1) _PS0 - One of these must exist: _PS1, _PS2, _PS3 127 * 2) _PS1/_PS2/_PS3: A _PS0 must exist 128 */ 129 if (ACPI_COMPARE_NAMESEG (METHOD_NAME__PS0, Op->Asl.NameSeg)) 130 { 131 /* For _PS0, one of _PS1/_PS2/_PS3 must exist */ 132 133 if ((!ApFindNameInScope (METHOD_NAME__PS1, Op)) && 134 (!ApFindNameInScope (METHOD_NAME__PS2, Op)) && 135 (!ApFindNameInScope (METHOD_NAME__PS3, Op))) 136 { 137 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op, 138 "_PS0 requires one of _PS1/_PS2/_PS3 in same scope"); 139 } 140 } 141 else if ( 142 ACPI_COMPARE_NAMESEG (METHOD_NAME__PS1, Op->Asl.NameSeg) || 143 ACPI_COMPARE_NAMESEG (METHOD_NAME__PS2, Op->Asl.NameSeg) || 144 ACPI_COMPARE_NAMESEG (METHOD_NAME__PS3, Op->Asl.NameSeg)) 145 { 146 /* For _PS1/_PS2/_PS3, a _PS0 must exist */ 147 148 if (!ApFindNameInScope (METHOD_NAME__PS0, Op)) 149 { 150 sprintf (AslGbl_MsgBuffer, 151 "%4.4s requires _PS0 in same scope", Op->Asl.NameSeg); 152 153 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op, 154 AslGbl_MsgBuffer); 155 } 156 } 157 158 /* Get the name node */ 159 160 Next = Op->Asl.Child; 161 162 /* Get the NumArguments node */ 163 164 Next = Next->Asl.Next; 165 MethodInfo->NumArguments = (UINT8) 166 (((UINT8) Next->Asl.Value.Integer) & 0x07); 167 168 /* Get the SerializeRule and SyncLevel nodes, ignored here */ 169 170 Next = Next->Asl.Next; 171 MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer; 172 173 Next = Next->Asl.Next; 174 ArgNode = Next; 175 176 /* Get the ReturnType node */ 177 178 Next = Next->Asl.Next; 179 180 NextType = Next->Asl.Child; 181 182 MethodInfo->ValidReturnTypes = MtProcessTypeOp (NextType); 183 184 /* Get the ParameterType node */ 185 186 Next = Next->Asl.Next; 187 188 NextType = Next->Asl.Child; 189 if (!NextType) 190 { 191 /* 192 * The optional parameter types list was omitted at the source 193 * level. Use the Argument count parameter instead. 194 */ 195 ActualArgs = MethodInfo->NumArguments; 196 } 197 else 198 { 199 ActualArgs = MtProcessParameterTypeList (NextType, 200 MethodInfo->ValidArgTypes); 201 } 202 203 if ((MethodInfo->NumArguments) && 204 (MethodInfo->NumArguments != ActualArgs)) 205 { 206 sprintf (AslGbl_MsgBuffer, 207 "Length = %u", ActualArgs); 208 AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_MISMATCH, 209 Op->Asl.Child->Asl.Next, AslGbl_MsgBuffer); 210 } 211 212 /* Allow numarguments == 0 for Function() */ 213 214 if ((!MethodInfo->NumArguments) && (ActualArgs)) 215 { 216 MethodInfo->NumArguments = ActualArgs; 217 ArgNode->Asl.Value.Integer |= ActualArgs; 218 } 219 220 /* 221 * Actual arguments are initialized at method entry. 222 * All other ArgX "registers" can be used as locals, so we 223 * track their initialization. 224 */ 225 for (i = 0; i < MethodInfo->NumArguments; i++) 226 { 227 MethodInfo->ArgInitialized[i] = TRUE; 228 } 229 break; 230 231 case PARSEOP_METHODCALL: 232 233 /* Check for a recursive method call */ 234 235 if (MethodInfo && 236 (Op->Asl.Node == MethodInfo->Op->Asl.Node)) 237 { 238 if (MethodInfo->CreatesNamedObjects) 239 { 240 /* 241 * This is an error, as it will fail at runtime on all ACPI 242 * implementations. Any named object declarations will be 243 * executed twice, causing failure the second time. Note, 244 * this is independent of whether the method is declared 245 * Serialized, because the same thread is attempting to 246 * reenter the method, and this will always succeed. 247 */ 248 AslDualParseOpError (ASL_ERROR, ASL_MSG_ILLEGAL_RECURSION, Op, 249 Op->Asl.Value.String, ASL_MSG_FOUND_HERE, MethodInfo->Op, 250 MethodInfo->Op->Asl.ExternalName); 251 } 252 else 253 { 254 /* Method does not create objects, issue a remark */ 255 256 AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName); 257 } 258 } 259 break; 260 261 case PARSEOP_LOCAL0: 262 case PARSEOP_LOCAL1: 263 case PARSEOP_LOCAL2: 264 case PARSEOP_LOCAL3: 265 case PARSEOP_LOCAL4: 266 case PARSEOP_LOCAL5: 267 case PARSEOP_LOCAL6: 268 case PARSEOP_LOCAL7: 269 270 if (!MethodInfo) 271 { 272 /* 273 * Local was used outside a control method, or there was an error 274 * in the method declaration. 275 */ 276 AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, 277 Op, Op->Asl.ExternalName); 278 return (AE_ERROR); 279 } 280 281 RegisterNumber = (Op->Asl.AmlOpcode & 0x0007); 282 283 /* 284 * If the local is being used as a target, mark the local 285 * initialized 286 */ 287 if (Op->Asl.CompileFlags & OP_IS_TARGET) 288 { 289 MethodInfo->LocalInitialized[RegisterNumber] = TRUE; 290 } 291 292 /* 293 * Otherwise, this is a reference, check if the local 294 * has been previously initialized. 295 * 296 * The only operator that accepts an uninitialized value is ObjectType() 297 */ 298 else if ((!MethodInfo->LocalInitialized[RegisterNumber]) && 299 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) 300 { 301 LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30); 302 AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName); 303 } 304 break; 305 306 case PARSEOP_ARG0: 307 case PARSEOP_ARG1: 308 case PARSEOP_ARG2: 309 case PARSEOP_ARG3: 310 case PARSEOP_ARG4: 311 case PARSEOP_ARG5: 312 case PARSEOP_ARG6: 313 314 if (!MethodInfo) 315 { 316 /* 317 * Arg was used outside a control method, or there was an error 318 * in the method declaration. 319 */ 320 AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, 321 Op, Op->Asl.ExternalName); 322 return (AE_ERROR); 323 } 324 325 RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8; 326 ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30); 327 328 /* 329 * If the Arg is being used as a target, mark the local 330 * initialized 331 */ 332 if (Op->Asl.CompileFlags & OP_IS_TARGET) 333 { 334 MethodInfo->ArgInitialized[RegisterNumber] = TRUE; 335 } 336 337 /* 338 * Otherwise, this is a reference, check if the Arg 339 * has been previously initialized. 340 * 341 * The only operator that accepts an uninitialized value is ObjectType() 342 */ 343 else if ((!MethodInfo->ArgInitialized[RegisterNumber]) && 344 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) 345 { 346 AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName); 347 } 348 349 /* Flag this arg if it is not a "real" argument to the method */ 350 351 if (RegisterNumber >= MethodInfo->NumArguments) 352 { 353 AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName); 354 } 355 break; 356 357 case PARSEOP_RETURN: 358 359 if (!MethodInfo) 360 { 361 /* 362 * Probably was an error in the method declaration, 363 * no additional error here 364 */ 365 ACPI_WARNING ((AE_INFO, "%p, No parent method", Op)); 366 return (AE_ERROR); 367 } 368 369 /* 370 * A child indicates a possible return value. A simple Return or 371 * Return() is marked with OP_IS_NULL_RETURN by the parser so 372 * that it is not counted as a "real" return-with-value, although 373 * the AML code that is actually emitted is Return(0). The AML 374 * definition of Return has a required parameter, so we are 375 * forced to convert a null return to Return(0). 376 */ 377 if ((Op->Asl.Child) && 378 (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && 379 (!(Op->Asl.Child->Asl.CompileFlags & OP_IS_NULL_RETURN))) 380 { 381 MethodInfo->NumReturnWithValue++; 382 } 383 else 384 { 385 MethodInfo->NumReturnNoValue++; 386 } 387 break; 388 389 case PARSEOP_BREAK: 390 case PARSEOP_CONTINUE: 391 392 Next = Op->Asl.Parent; 393 while (Next) 394 { 395 if (Next->Asl.ParseOpcode == PARSEOP_WHILE) 396 { 397 break; 398 } 399 Next = Next->Asl.Parent; 400 } 401 402 if (!Next) 403 { 404 AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL); 405 } 406 break; 407 408 case PARSEOP_STALL: 409 410 /* We can range check if the argument is an integer */ 411 412 if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) && 413 (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX)) 414 { 415 AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL); 416 } 417 break; 418 419 case PARSEOP_DEVICE: 420 421 /* Check usage of _HID and _ADR objects */ 422 423 HidExists = ApFindNameInDeviceTree (METHOD_NAME__HID, Op); 424 AdrExists = ApFindNameInDeviceTree (METHOD_NAME__ADR, Op); 425 426 if (!HidExists && !AdrExists) 427 { 428 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op, 429 "Device object requires a _HID or _ADR in same scope"); 430 } 431 else if (HidExists && AdrExists) 432 { 433 /* 434 * According to the ACPI spec, "A device object must contain 435 * either an _HID object or an _ADR object, but should not contain 436 * both". 437 */ 438 AslError (ASL_WARNING, ASL_MSG_MULTIPLE_TYPES, Op, 439 "Device object requires either a _HID or _ADR, but not both"); 440 } 441 break; 442 443 case PARSEOP_EVENT: 444 case PARSEOP_MUTEX: 445 case PARSEOP_OPERATIONREGION: 446 case PARSEOP_POWERRESOURCE: 447 case PARSEOP_PROCESSOR: 448 case PARSEOP_THERMALZONE: 449 450 /* 451 * The first operand is a name to be created in the namespace. 452 * Check against the reserved list. 453 */ 454 i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg); 455 if (i < ACPI_VALID_RESERVED_NAME_MAX) 456 { 457 AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, 458 Op, Op->Asl.ExternalName); 459 } 460 461 MtCheckStaticOperationRegionInMethod (Op); 462 break; 463 464 case PARSEOP_NAME: 465 466 /* Typecheck any predefined names statically defined with Name() */ 467 468 ApCheckForPredefinedObject (Op, Op->Asl.NameSeg); 469 470 /* Special typechecking for _HID */ 471 472 if (ACPI_COMPARE_NAMESEG (METHOD_NAME__HID, Op->Asl.NameSeg)) 473 { 474 Next = Op->Asl.Child->Asl.Next; 475 AnCheckId (Next, ASL_TYPE_HID); 476 } 477 478 /* Special typechecking for _CID */ 479 480 else if (ACPI_COMPARE_NAMESEG (METHOD_NAME__CID, Op->Asl.NameSeg)) 481 { 482 Next = Op->Asl.Child->Asl.Next; 483 484 if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) || 485 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) 486 { 487 Next = Next->Asl.Child; 488 while (Next) 489 { 490 AnCheckId (Next, ASL_TYPE_CID); 491 Next = Next->Asl.Next; 492 } 493 } 494 else 495 { 496 AnCheckId (Next, ASL_TYPE_CID); 497 } 498 } 499 500 break; 501 502 default: 503 504 break; 505 } 506 507 /* Check for named object creation within a non-serialized method */ 508 509 MtCheckNamedObjectInMethod (Op, MethodInfo); 510 return (AE_OK); 511 } 512 513 514 /******************************************************************************* 515 * 516 * FUNCTION: MtProcessTypeOp 517 * 518 * PARAMETERS: Op - Op representing a btype 519 * 520 * RETURN: Btype represented by Op 521 * 522 * DESCRIPTION: Process a parse object that represents single parameter type or 523 * a return type in method, function, and external declarations. 524 * 525 ******************************************************************************/ 526 527 UINT32 528 MtProcessTypeOp ( 529 ACPI_PARSE_OBJECT *TypeOp) 530 { 531 UINT32 Btype = ACPI_BTYPE_ANY; 532 533 534 while (TypeOp) 535 { 536 Btype |= AnMapObjTypeToBtype (TypeOp); 537 TypeOp->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 538 TypeOp = TypeOp->Asl.Next; 539 } 540 541 return (Btype); 542 } 543 544 545 /******************************************************************************* 546 * 547 * FUNCTION: MtProcessParameterTypeList 548 * 549 * PARAMETERS: Op - Op representing a btype 550 * 551 * RETURN: Btype represented by Op 552 * 553 * DESCRIPTION: Process a parse object that represents a parameter type list in 554 * method, function, and external declarations. 555 * 556 ******************************************************************************/ 557 558 UINT8 559 MtProcessParameterTypeList ( 560 ACPI_PARSE_OBJECT *ParamTypeOp, 561 UINT32 *TypeList) 562 { 563 UINT8 ParameterCount = 0; 564 565 566 while (ParamTypeOp) 567 { 568 TypeList[ParameterCount] = 569 MtProcessTypeOp (ParamTypeOp->Asl.Child); 570 571 ParameterCount++; 572 ParamTypeOp = ParamTypeOp->Asl.Next; 573 } 574 575 return (ParameterCount); 576 } 577 578 579 /******************************************************************************* 580 * 581 * FUNCTION: MtCheckNamedObjectInMethod 582 * 583 * PARAMETERS: Op - Current parser op 584 * MethodInfo - Info for method being parsed 585 * 586 * RETURN: None 587 * 588 * DESCRIPTION: Detect if a non-serialized method is creating a named object, 589 * which could possibly cause problems if two threads execute 590 * the method concurrently. Emit a remark in this case. 591 * 592 ******************************************************************************/ 593 594 static void 595 MtCheckNamedObjectInMethod ( 596 ACPI_PARSE_OBJECT *Op, 597 ASL_METHOD_INFO *MethodInfo) 598 { 599 const ACPI_OPCODE_INFO *OpInfo; 600 char *ExternalPath; 601 602 603 /* We don't care about actual method declarations or scopes */ 604 605 if ((Op->Asl.AmlOpcode == AML_METHOD_OP) || 606 (Op->Asl.AmlOpcode == AML_SCOPE_OP)) 607 { 608 return; 609 } 610 611 /* Determine if we are creating a named object within a method */ 612 613 if (!MethodInfo) 614 { 615 return; 616 } 617 618 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); 619 if (OpInfo->Class == AML_CLASS_NAMED_OBJECT) 620 { 621 /* 622 * 1) Mark the method as a method that creates named objects. 623 * 624 * 2) Issue a remark indicating the inefficiency of creating named 625 * objects within a method (Except for compiler-emitted temporary 626 * variables). 627 * 628 * 3) If the method is non-serialized, emit a remark that the method 629 * should be serialized. 630 * 631 * Reason: If a thread blocks within the method for any reason, and 632 * another thread enters the method, the method will fail because 633 * an attempt will be made to create the same object twice. 634 */ 635 ExternalPath = AcpiNsGetNormalizedPathname (MethodInfo->Op->Asl.Node, TRUE); 636 637 /* No error for compiler temp variables (name starts with "_T_") */ 638 639 if ((Op->Asl.NameSeg[0] != '_') && 640 (Op->Asl.NameSeg[1] != 'T') && 641 (Op->Asl.NameSeg[2] != '_')) 642 { 643 AslError (ASL_REMARK, ASL_MSG_NAMED_OBJECT_CREATION, Op, 644 ExternalPath); 645 } 646 647 MethodInfo->CreatesNamedObjects = TRUE; 648 if (!MethodInfo->ShouldBeSerialized) 649 { 650 AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op, 651 ExternalPath); 652 653 /* Emit message only ONCE per method */ 654 655 MethodInfo->ShouldBeSerialized = TRUE; 656 } 657 658 if (ExternalPath) 659 { 660 ACPI_FREE (ExternalPath); 661 } 662 } 663 } 664 665 666 /******************************************************************************* 667 * 668 * FUNCTION: MtCheckStaticOperationRegionInMethod 669 * 670 * PARAMETERS: Op - Current parser op 671 * 672 * RETURN: None 673 * 674 * DESCRIPTION: Warns if an Operation Region with static address or length 675 * is declared inside a control method 676 * 677 ******************************************************************************/ 678 679 static void 680 MtCheckStaticOperationRegionInMethod( 681 ACPI_PARSE_OBJECT* Op) 682 { 683 ACPI_PARSE_OBJECT* AddressOp; 684 ACPI_PARSE_OBJECT* LengthOp; 685 686 687 if (Op->Asl.ParseOpcode != PARSEOP_OPERATIONREGION) 688 { 689 return; 690 } 691 692 /* 693 * OperationRegion should have 4 arguments defined. At this point, we 694 * assume that the parse tree is well-formed. 695 */ 696 AddressOp = Op->Asl.Child->Asl.Next->Asl.Next; 697 LengthOp = Op->Asl.Child->Asl.Next->Asl.Next->Asl.Next; 698 699 if (UtGetParentMethodOp (Op) && 700 AddressOp->Asl.ParseOpcode == PARSEOP_INTEGER && 701 LengthOp->Asl.ParseOpcode == PARSEOP_INTEGER) 702 { 703 /* 704 * At this point, a static operation region declared inside of a 705 * control method has been found. Throw a warning because this is 706 * highly inefficient. 707 */ 708 AslError(ASL_WARNING, ASL_MSG_STATIC_OPREGION_IN_METHOD, Op, NULL); 709 } 710 711 return; 712 } 713 714 715 /******************************************************************************* 716 * 717 * FUNCTION: MtMethodAnalysisWalkEnd 718 * 719 * PARAMETERS: ASL_WALK_CALLBACK 720 * 721 * RETURN: Status 722 * 723 * DESCRIPTION: Ascending callback for analysis walk. Complete method 724 * return analysis. 725 * 726 ******************************************************************************/ 727 728 ACPI_STATUS 729 MtMethodAnalysisWalkEnd ( 730 ACPI_PARSE_OBJECT *Op, 731 UINT32 Level, 732 void *Context) 733 { 734 ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; 735 ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack; 736 char *ExternalPath; 737 738 739 switch (Op->Asl.ParseOpcode) 740 { 741 case PARSEOP_METHOD: 742 case PARSEOP_RETURN: 743 744 if (!MethodInfo) 745 { 746 printf ("No method info for method! [%s]\n", Op->Asl.Namepath); 747 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op, 748 "No method info for this method"); 749 750 CmCleanupAndExit (); 751 return (AE_AML_INTERNAL); 752 } 753 break; 754 755 default: 756 757 break; 758 } 759 760 switch (Op->Asl.ParseOpcode) 761 { 762 case PARSEOP_METHOD: 763 764 WalkInfo->MethodStack = MethodInfo->Next; 765 766 /* 767 * Check if there is no return statement at the end of the 768 * method AND we can actually get there -- i.e., the execution 769 * of the method can possibly terminate without a return statement. 770 */ 771 if ((!AnLastStatementIsReturn (Op)) && 772 (!(Op->Asl.CompileFlags & OP_HAS_NO_EXIT))) 773 { 774 /* 775 * No return statement, and execution can possibly exit 776 * via this path. This is equivalent to Return () 777 */ 778 MethodInfo->NumReturnNoValue++; 779 } 780 781 /* 782 * Check for case where some return statements have a return value 783 * and some do not. Exit without a return statement is a return with 784 * no value 785 */ 786 if (MethodInfo->NumReturnNoValue && 787 MethodInfo->NumReturnWithValue) 788 { 789 ExternalPath = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE); 790 791 AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op, 792 ExternalPath); 793 794 if (ExternalPath) 795 { 796 ACPI_FREE (ExternalPath); 797 } 798 } 799 800 /* 801 * If there are any RETURN() statements with no value, or there is a 802 * control path that allows the method to exit without a return value, 803 * we mark the method as a method that does not return a value. This 804 * knowledge can be used to check method invocations that expect a 805 * returned value. 806 */ 807 if (MethodInfo->NumReturnNoValue) 808 { 809 if (MethodInfo->NumReturnWithValue) 810 { 811 Op->Asl.CompileFlags |= OP_METHOD_SOME_NO_RETVAL; 812 } 813 else 814 { 815 Op->Asl.CompileFlags |= OP_METHOD_NO_RETVAL; 816 } 817 } 818 819 /* 820 * Check predefined method names for correct return behavior 821 * and correct number of arguments. Also, some special checks 822 * For GPE and _REG methods. 823 */ 824 if (ApCheckForPredefinedMethod (Op, MethodInfo)) 825 { 826 /* Special check for two names like _L01 and _E01 in same scope */ 827 828 ApCheckForGpeNameConflict (Op); 829 830 /* 831 * Special check for _REG: Must have an operation region definition 832 * within the same scope! 833 */ 834 ApCheckRegMethod (Op); 835 } 836 837 ACPI_FREE (MethodInfo); 838 break; 839 840 case PARSEOP_NAME: 841 842 /* Special check for two names like _L01 and _E01 in same scope */ 843 844 ApCheckForGpeNameConflict (Op); 845 break; 846 847 case PARSEOP_RETURN: 848 849 /* 850 * If the parent is a predefined method name, attempt to typecheck 851 * the return value. Only static types can be validated. 852 */ 853 ApCheckPredefinedReturnValue (Op, MethodInfo); 854 855 /* 856 * The parent block does not "exit" and continue execution -- the 857 * method is terminated here with the Return() statement. 858 */ 859 Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT; 860 861 /* Used in the "typing" pass later */ 862 863 Op->Asl.ParentMethod = MethodInfo->Op; 864 865 /* 866 * If there is a peer node after the return statement, then this 867 * node is unreachable code -- i.e., it won't be executed because of 868 * the preceding Return() statement. 869 */ 870 if (Op->Asl.Next) 871 { 872 AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE, 873 Op->Asl.Next, NULL); 874 } 875 break; 876 877 case PARSEOP_IF: 878 879 if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) && 880 (Op->Asl.Next) && 881 (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE)) 882 { 883 /* 884 * This IF has a corresponding ELSE. The IF block has no exit, 885 * (it contains an unconditional Return) 886 * mark the ELSE block to remember this fact. 887 */ 888 Op->Asl.Next->Asl.CompileFlags |= OP_IF_HAS_NO_EXIT; 889 } 890 break; 891 892 case PARSEOP_ELSE: 893 894 if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) && 895 (Op->Asl.CompileFlags & OP_IF_HAS_NO_EXIT)) 896 { 897 /* 898 * This ELSE block has no exit and the corresponding IF block 899 * has no exit either. Therefore, the parent node has no exit. 900 */ 901 Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT; 902 } 903 break; 904 905 906 default: 907 908 if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) && 909 (Op->Asl.Parent)) 910 { 911 /* If this node has no exit, then the parent has no exit either */ 912 913 Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT; 914 } 915 break; 916 } 917 918 return (AE_OK); 919 } 920