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