1 /****************************************************************************** 2 * 3 * Module Name: aslwalks.c - Miscellaneous analytical parse tree walks 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, 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 "aslcompiler.h" 46 #include "aslcompiler.y.h" 47 #include "acparser.h" 48 #include "amlcode.h" 49 50 51 #define _COMPONENT ACPI_COMPILER 52 ACPI_MODULE_NAME ("aslwalks") 53 54 55 /******************************************************************************* 56 * 57 * FUNCTION: AnMethodTypingWalkEnd 58 * 59 * PARAMETERS: ASL_WALK_CALLBACK 60 * 61 * RETURN: Status 62 * 63 * DESCRIPTION: Ascending callback for typing walk. Complete the method 64 * return analysis. Check methods for: 65 * 1) Initialized local variables 66 * 2) Valid arguments 67 * 3) Return types 68 * 69 ******************************************************************************/ 70 71 ACPI_STATUS 72 AnMethodTypingWalkEnd ( 73 ACPI_PARSE_OBJECT *Op, 74 UINT32 Level, 75 void *Context) 76 { 77 UINT32 ThisNodeBtype; 78 79 80 switch (Op->Asl.ParseOpcode) 81 { 82 case PARSEOP_METHOD: 83 84 Op->Asl.CompileFlags |= NODE_METHOD_TYPED; 85 break; 86 87 case PARSEOP_RETURN: 88 89 if ((Op->Asl.Child) && 90 (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)) 91 { 92 ThisNodeBtype = AnGetBtype (Op->Asl.Child); 93 94 if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_METHODCALL) && 95 (ThisNodeBtype == (ACPI_UINT32_MAX -1))) 96 { 97 /* 98 * The called method is untyped at this time (typically a 99 * forward reference). 100 * 101 * Check for a recursive method call first. 102 */ 103 if (Op->Asl.ParentMethod != Op->Asl.Child->Asl.Node->Op) 104 { 105 /* We must type the method here */ 106 107 TrWalkParseTree (Op->Asl.Child->Asl.Node->Op, 108 ASL_WALK_VISIT_UPWARD, NULL, 109 AnMethodTypingWalkEnd, NULL); 110 111 ThisNodeBtype = AnGetBtype (Op->Asl.Child); 112 } 113 } 114 115 /* Returns a value, save the value type */ 116 117 if (Op->Asl.ParentMethod) 118 { 119 Op->Asl.ParentMethod->Asl.AcpiBtype |= ThisNodeBtype; 120 } 121 } 122 break; 123 124 default: 125 126 break; 127 } 128 129 return (AE_OK); 130 } 131 132 133 /******************************************************************************* 134 * 135 * FUNCTION: AnOperandTypecheckWalkEnd 136 * 137 * PARAMETERS: ASL_WALK_CALLBACK 138 * 139 * RETURN: Status 140 * 141 * DESCRIPTION: Ascending callback for analysis walk. Complete method 142 * return analysis. 143 * 144 ******************************************************************************/ 145 146 ACPI_STATUS 147 AnOperandTypecheckWalkEnd ( 148 ACPI_PARSE_OBJECT *Op, 149 UINT32 Level, 150 void *Context) 151 { 152 const ACPI_OPCODE_INFO *OpInfo; 153 UINT32 RuntimeArgTypes; 154 UINT32 RuntimeArgTypes2; 155 UINT32 RequiredBtypes; 156 UINT32 ThisNodeBtype; 157 UINT32 CommonBtypes; 158 UINT32 OpcodeClass; 159 ACPI_PARSE_OBJECT *ArgOp; 160 UINT32 ArgType; 161 162 163 switch (Op->Asl.AmlOpcode) 164 { 165 case AML_RAW_DATA_BYTE: 166 case AML_RAW_DATA_WORD: 167 case AML_RAW_DATA_DWORD: 168 case AML_RAW_DATA_QWORD: 169 case AML_RAW_DATA_BUFFER: 170 case AML_RAW_DATA_CHAIN: 171 case AML_PACKAGE_LENGTH: 172 case AML_UNASSIGNED_OPCODE: 173 case AML_DEFAULT_ARG_OP: 174 175 /* Ignore the internal (compiler-only) AML opcodes */ 176 177 return (AE_OK); 178 179 default: 180 181 break; 182 } 183 184 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); 185 if (!OpInfo) 186 { 187 return (AE_OK); 188 } 189 190 ArgOp = Op->Asl.Child; 191 RuntimeArgTypes = OpInfo->RuntimeArgs; 192 OpcodeClass = OpInfo->Class; 193 194 #ifdef ASL_ERROR_NAMED_OBJECT_IN_WHILE 195 /* 196 * Update 11/2008: In practice, we can't perform this check. A simple 197 * analysis is not sufficient. Also, it can cause errors when compiling 198 * disassembled code because of the way Switch operators are implemented 199 * (a While(One) loop with a named temp variable created within.) 200 */ 201 202 /* 203 * If we are creating a named object, check if we are within a while loop 204 * by checking if the parent is a WHILE op. This is a simple analysis, but 205 * probably sufficient for many cases. 206 * 207 * Allow Scope(), Buffer(), and Package(). 208 */ 209 if (((OpcodeClass == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_SCOPE_OP)) || 210 ((OpcodeClass == AML_CLASS_CREATE) && (OpInfo->Flags & AML_NSNODE))) 211 { 212 if (Op->Asl.Parent->Asl.AmlOpcode == AML_WHILE_OP) 213 { 214 AslError (ASL_ERROR, ASL_MSG_NAMED_OBJECT_IN_WHILE, Op, NULL); 215 } 216 } 217 #endif 218 219 /* 220 * Special case for control opcodes IF/RETURN/WHILE since they 221 * have no runtime arg list (at this time) 222 */ 223 switch (Op->Asl.AmlOpcode) 224 { 225 case AML_IF_OP: 226 case AML_WHILE_OP: 227 case AML_RETURN_OP: 228 229 if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) 230 { 231 /* Check for an internal method */ 232 233 if (AnIsInternalMethod (ArgOp)) 234 { 235 return (AE_OK); 236 } 237 238 /* The lone arg is a method call, check it */ 239 240 RequiredBtypes = AnMapArgTypeToBtype (ARGI_INTEGER); 241 if (Op->Asl.AmlOpcode == AML_RETURN_OP) 242 { 243 RequiredBtypes = 0xFFFFFFFF; 244 } 245 246 ThisNodeBtype = AnGetBtype (ArgOp); 247 if (ThisNodeBtype == ACPI_UINT32_MAX) 248 { 249 return (AE_OK); 250 } 251 AnCheckMethodReturnValue (Op, OpInfo, ArgOp, 252 RequiredBtypes, ThisNodeBtype); 253 } 254 return (AE_OK); 255 256 default: 257 258 break; 259 } 260 261 /* Ignore the non-executable opcodes */ 262 263 if (RuntimeArgTypes == ARGI_INVALID_OPCODE) 264 { 265 return (AE_OK); 266 } 267 268 switch (OpcodeClass) 269 { 270 case AML_CLASS_EXECUTE: 271 case AML_CLASS_CREATE: 272 case AML_CLASS_CONTROL: 273 case AML_CLASS_RETURN_VALUE: 274 275 /* TBD: Change class or fix typechecking for these */ 276 277 if ((Op->Asl.AmlOpcode == AML_BUFFER_OP) || 278 (Op->Asl.AmlOpcode == AML_PACKAGE_OP) || 279 (Op->Asl.AmlOpcode == AML_VAR_PACKAGE_OP)) 280 { 281 break; 282 } 283 284 /* Reverse the runtime argument list */ 285 286 RuntimeArgTypes2 = 0; 287 while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes))) 288 { 289 RuntimeArgTypes2 <<= ARG_TYPE_WIDTH; 290 RuntimeArgTypes2 |= ArgType; 291 INCREMENT_ARG_LIST (RuntimeArgTypes); 292 } 293 294 while ((ArgType = GET_CURRENT_ARG_TYPE (RuntimeArgTypes2))) 295 { 296 RequiredBtypes = AnMapArgTypeToBtype (ArgType); 297 298 ThisNodeBtype = AnGetBtype (ArgOp); 299 if (ThisNodeBtype == ACPI_UINT32_MAX) 300 { 301 goto NextArgument; 302 } 303 304 /* Examine the arg based on the required type of the arg */ 305 306 switch (ArgType) 307 { 308 case ARGI_TARGETREF: 309 310 if (ArgOp->Asl.ParseOpcode == PARSEOP_ZERO) 311 { 312 /* ZERO is the placeholder for "don't store result" */ 313 314 ThisNodeBtype = RequiredBtypes; 315 break; 316 } 317 318 if (ArgOp->Asl.ParseOpcode == PARSEOP_INTEGER) 319 { 320 /* 321 * This is the case where an original reference to a resource 322 * descriptor field has been replaced by an (Integer) offset. 323 * These named fields are supported at compile-time only; 324 * the names are not passed to the interpreter (via the AML). 325 */ 326 if ((ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) || 327 (ArgOp->Asl.Node->Type == ACPI_TYPE_LOCAL_RESOURCE)) 328 { 329 AslError (ASL_ERROR, ASL_MSG_RESOURCE_FIELD, ArgOp, NULL); 330 } 331 else 332 { 333 AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, NULL); 334 } 335 break; 336 } 337 338 if ((ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) || 339 (ArgOp->Asl.ParseOpcode == PARSEOP_DEREFOF)) 340 { 341 break; 342 } 343 344 ThisNodeBtype = RequiredBtypes; 345 break; 346 347 348 case ARGI_REFERENCE: /* References */ 349 case ARGI_INTEGER_REF: 350 case ARGI_OBJECT_REF: 351 case ARGI_DEVICE_REF: 352 353 switch (ArgOp->Asl.ParseOpcode) 354 { 355 case PARSEOP_LOCAL0: 356 case PARSEOP_LOCAL1: 357 case PARSEOP_LOCAL2: 358 case PARSEOP_LOCAL3: 359 case PARSEOP_LOCAL4: 360 case PARSEOP_LOCAL5: 361 case PARSEOP_LOCAL6: 362 case PARSEOP_LOCAL7: 363 364 /* TBD: implement analysis of current value (type) of the local */ 365 /* For now, just treat any local as a typematch */ 366 367 /*ThisNodeBtype = RequiredBtypes;*/ 368 break; 369 370 case PARSEOP_ARG0: 371 case PARSEOP_ARG1: 372 case PARSEOP_ARG2: 373 case PARSEOP_ARG3: 374 case PARSEOP_ARG4: 375 case PARSEOP_ARG5: 376 case PARSEOP_ARG6: 377 378 /* Hard to analyze argument types, sow we won't */ 379 /* For now, just treat any arg as a typematch */ 380 381 /* ThisNodeBtype = RequiredBtypes; */ 382 break; 383 384 case PARSEOP_DEBUG: 385 386 break; 387 388 case PARSEOP_REFOF: 389 case PARSEOP_INDEX: 390 default: 391 392 break; 393 394 } 395 break; 396 397 case ARGI_INTEGER: 398 default: 399 400 break; 401 } 402 403 404 CommonBtypes = ThisNodeBtype & RequiredBtypes; 405 406 if (ArgOp->Asl.ParseOpcode == PARSEOP_METHODCALL) 407 { 408 if (AnIsInternalMethod (ArgOp)) 409 { 410 return (AE_OK); 411 } 412 413 /* Check a method call for a valid return value */ 414 415 AnCheckMethodReturnValue (Op, OpInfo, ArgOp, 416 RequiredBtypes, ThisNodeBtype); 417 } 418 419 /* 420 * Now check if the actual type(s) match at least one 421 * bit to the required type 422 */ 423 else if (!CommonBtypes) 424 { 425 /* No match -- this is a type mismatch error */ 426 427 AnFormatBtype (StringBuffer, ThisNodeBtype); 428 AnFormatBtype (StringBuffer2, RequiredBtypes); 429 430 sprintf (MsgBuffer, "[%s] found, %s operator requires [%s]", 431 StringBuffer, OpInfo->Name, StringBuffer2); 432 433 AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer); 434 } 435 436 NextArgument: 437 ArgOp = ArgOp->Asl.Next; 438 INCREMENT_ARG_LIST (RuntimeArgTypes2); 439 } 440 break; 441 442 default: 443 444 break; 445 } 446 447 return (AE_OK); 448 } 449 450 451 /******************************************************************************* 452 * 453 * FUNCTION: AnOtherSemanticAnalysisWalkBegin 454 * 455 * PARAMETERS: ASL_WALK_CALLBACK 456 * 457 * RETURN: Status 458 * 459 * DESCRIPTION: Descending callback for the analysis walk. Checks for 460 * miscellaneous issues in the code. 461 * 462 ******************************************************************************/ 463 464 ACPI_STATUS 465 AnOtherSemanticAnalysisWalkBegin ( 466 ACPI_PARSE_OBJECT *Op, 467 UINT32 Level, 468 void *Context) 469 { 470 ACPI_PARSE_OBJECT *ArgNode; 471 ACPI_PARSE_OBJECT *PrevArgNode = NULL; 472 const ACPI_OPCODE_INFO *OpInfo; 473 ACPI_NAMESPACE_NODE *Node; 474 475 476 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); 477 478 /* 479 * Determine if an execution class operator actually does something by 480 * checking if it has a target and/or the function return value is used. 481 * (Target is optional, so a standalone statement can actually do nothing.) 482 */ 483 if ((OpInfo->Class == AML_CLASS_EXECUTE) && 484 (OpInfo->Flags & AML_HAS_RETVAL) && 485 (!AnIsResultUsed (Op))) 486 { 487 if (OpInfo->Flags & AML_HAS_TARGET) 488 { 489 /* 490 * Find the target node, it is always the last child. If the traget 491 * is not specified in the ASL, a default node of type Zero was 492 * created by the parser. 493 */ 494 ArgNode = Op->Asl.Child; 495 while (ArgNode->Asl.Next) 496 { 497 PrevArgNode = ArgNode; 498 ArgNode = ArgNode->Asl.Next; 499 } 500 501 /* Divide() is the only weird case, it has two targets */ 502 503 if (Op->Asl.AmlOpcode == AML_DIVIDE_OP) 504 { 505 if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) && 506 (PrevArgNode) && 507 (PrevArgNode->Asl.ParseOpcode == PARSEOP_ZERO)) 508 { 509 AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED, 510 Op, Op->Asl.ExternalName); 511 } 512 } 513 else if (ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) 514 { 515 AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED, 516 Op, Op->Asl.ExternalName); 517 } 518 } 519 else 520 { 521 /* 522 * Has no target and the result is not used. Only a couple opcodes 523 * can have this combination. 524 */ 525 switch (Op->Asl.ParseOpcode) 526 { 527 case PARSEOP_ACQUIRE: 528 case PARSEOP_WAIT: 529 case PARSEOP_LOADTABLE: 530 531 break; 532 533 default: 534 535 AslError (ASL_ERROR, ASL_MSG_RESULT_NOT_USED, 536 Op, Op->Asl.ExternalName); 537 break; 538 } 539 } 540 } 541 542 543 /* 544 * Semantic checks for individual ASL operators 545 */ 546 switch (Op->Asl.ParseOpcode) 547 { 548 case PARSEOP_ACQUIRE: 549 case PARSEOP_WAIT: 550 /* 551 * Emit a warning if the timeout parameter for these operators is not 552 * ACPI_WAIT_FOREVER, and the result value from the operator is not 553 * checked, meaning that a timeout could happen, but the code 554 * would not know about it. 555 */ 556 557 /* First child is the namepath, 2nd child is timeout */ 558 559 ArgNode = Op->Asl.Child; 560 ArgNode = ArgNode->Asl.Next; 561 562 /* 563 * Check for the WAIT_FOREVER case - defined by the ACPI spec to be 564 * 0xFFFF or greater 565 */ 566 if (((ArgNode->Asl.ParseOpcode == PARSEOP_WORDCONST) || 567 (ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER)) && 568 (ArgNode->Asl.Value.Integer >= (UINT64) ACPI_WAIT_FOREVER)) 569 { 570 break; 571 } 572 573 /* 574 * The operation could timeout. If the return value is not used 575 * (indicates timeout occurred), issue a warning 576 */ 577 if (!AnIsResultUsed (Op)) 578 { 579 AslError (ASL_WARNING, ASL_MSG_TIMEOUT, ArgNode, 580 Op->Asl.ExternalName); 581 } 582 break; 583 584 case PARSEOP_CREATEFIELD: 585 /* 586 * Check for a zero Length (NumBits) operand. NumBits is the 3rd operand 587 */ 588 ArgNode = Op->Asl.Child; 589 ArgNode = ArgNode->Asl.Next; 590 ArgNode = ArgNode->Asl.Next; 591 592 if ((ArgNode->Asl.ParseOpcode == PARSEOP_ZERO) || 593 ((ArgNode->Asl.ParseOpcode == PARSEOP_INTEGER) && 594 (ArgNode->Asl.Value.Integer == 0))) 595 { 596 AslError (ASL_ERROR, ASL_MSG_NON_ZERO, ArgNode, NULL); 597 } 598 break; 599 600 case PARSEOP_CONNECTION: 601 /* 602 * Ensure that the referenced operation region has the correct SPACE_ID. 603 * From the grammar/parser, we know the parent is a FIELD definition. 604 */ 605 ArgNode = Op->Asl.Parent; /* Field definition */ 606 ArgNode = ArgNode->Asl.Child; /* First child is the OpRegion Name */ 607 Node = ArgNode->Asl.Node; /* OpRegion namespace node */ 608 if (!Node) 609 { 610 break; 611 } 612 613 ArgNode = Node->Op; /* OpRegion definition */ 614 ArgNode = ArgNode->Asl.Child; /* First child is the OpRegion Name */ 615 ArgNode = ArgNode->Asl.Next; /* Next peer is the SPACE_ID (what we want) */ 616 617 /* 618 * The Connection() operator is only valid for the following operation 619 * region SpaceIds: GeneralPurposeIo and GenericSerialBus. 620 */ 621 if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) && 622 (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS)) 623 { 624 AslError (ASL_ERROR, ASL_MSG_CONNECTION_INVALID, Op, NULL); 625 } 626 break; 627 628 case PARSEOP_FIELD: 629 /* 630 * Ensure that fields for GeneralPurposeIo and GenericSerialBus 631 * contain at least one Connection() operator 632 */ 633 ArgNode = Op->Asl.Child; /* 1st child is the OpRegion Name */ 634 Node = ArgNode->Asl.Node; /* OpRegion namespace node */ 635 if (!Node) 636 { 637 break; 638 } 639 640 ArgNode = Node->Op; /* OpRegion definition */ 641 ArgNode = ArgNode->Asl.Child; /* First child is the OpRegion Name */ 642 ArgNode = ArgNode->Asl.Next; /* Next peer is the SPACE_ID (what we want) */ 643 644 /* We are only interested in GeneralPurposeIo and GenericSerialBus */ 645 646 if ((ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GPIO) && 647 (ArgNode->Asl.Value.Integer != ACPI_ADR_SPACE_GSBUS)) 648 { 649 break; 650 } 651 652 ArgNode = Op->Asl.Child; /* 1st child is the OpRegion Name */ 653 ArgNode = ArgNode->Asl.Next; /* AccessType */ 654 ArgNode = ArgNode->Asl.Next; /* LockRule */ 655 ArgNode = ArgNode->Asl.Next; /* UpdateRule */ 656 ArgNode = ArgNode->Asl.Next; /* Start of FieldUnitList */ 657 658 /* Walk the FieldUnitList */ 659 660 while (ArgNode) 661 { 662 if (ArgNode->Asl.ParseOpcode == PARSEOP_CONNECTION) 663 { 664 break; 665 } 666 else if (ArgNode->Asl.ParseOpcode == PARSEOP_NAMESEG) 667 { 668 AslError (ASL_ERROR, ASL_MSG_CONNECTION_MISSING, ArgNode, NULL); 669 break; 670 } 671 672 ArgNode = ArgNode->Asl.Next; 673 } 674 break; 675 676 default: 677 678 break; 679 } 680 681 return (AE_OK); 682 }