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