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