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