1 /****************************************************************************** 2 * 3 * Module Name: aslanalyze.c - Support functions for parse tree walks 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, 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 <string.h> 47 48 49 #define _COMPONENT ACPI_COMPILER 50 ACPI_MODULE_NAME ("aslanalyze") 51 52 53 /* Local Prototypes */ 54 55 static ACPI_STATUS 56 ApDeviceSubtreeWalk ( 57 ACPI_PARSE_OBJECT *Op, 58 UINT32 Level, 59 void *Context); 60 61 62 /******************************************************************************* 63 * 64 * FUNCTION: AnIsInternalMethod 65 * 66 * PARAMETERS: Op - Current op 67 * 68 * RETURN: Boolean 69 * 70 * DESCRIPTION: Check for an internal control method. 71 * 72 ******************************************************************************/ 73 74 BOOLEAN 75 AnIsInternalMethod ( 76 ACPI_PARSE_OBJECT *Op) 77 { 78 79 if ((!strcmp (Op->Asl.ExternalName, "\\_OSI")) || 80 (!strcmp (Op->Asl.ExternalName, "_OSI"))) 81 { 82 return (TRUE); 83 } 84 85 return (FALSE); 86 } 87 88 89 /******************************************************************************* 90 * 91 * FUNCTION: AnGetInternalMethodReturnType 92 * 93 * PARAMETERS: Op - Current op 94 * 95 * RETURN: Btype 96 * 97 * DESCRIPTION: Get the return type of an internal method 98 * 99 ******************************************************************************/ 100 101 UINT32 102 AnGetInternalMethodReturnType ( 103 ACPI_PARSE_OBJECT *Op) 104 { 105 106 if ((!strcmp (Op->Asl.ExternalName, "\\_OSI")) || 107 (!strcmp (Op->Asl.ExternalName, "_OSI"))) 108 { 109 return (ACPI_BTYPE_STRING); 110 } 111 112 return (0); 113 } 114 115 116 /******************************************************************************* 117 * 118 * FUNCTION: AnCheckId 119 * 120 * PARAMETERS: Op - Current parse op 121 * Type - HID or CID 122 * 123 * RETURN: None 124 * 125 * DESCRIPTION: Perform various checks on _HID and _CID strings. Only limited 126 * checks can be performed on _CID strings. 127 * 128 ******************************************************************************/ 129 130 void 131 AnCheckId ( 132 ACPI_PARSE_OBJECT *Op, 133 ACPI_NAME Type) 134 { 135 UINT32 i; 136 ACPI_SIZE Length; 137 138 139 /* Only care about string versions of _HID/_CID (integers are legal) */ 140 141 if (Op->Asl.ParseOpcode != PARSEOP_STRING_LITERAL) 142 { 143 return; 144 } 145 146 /* For both _HID and _CID, the string must be non-null */ 147 148 Length = strlen (Op->Asl.Value.String); 149 if (!Length) 150 { 151 AslError (ASL_ERROR, ASL_MSG_NULL_STRING, Op, NULL); 152 return; 153 } 154 155 /* 156 * One of the things we want to catch here is the use of a leading 157 * asterisk in the string -- an odd construct that certain platform 158 * manufacturers are fond of. Technically, a leading asterisk is OK 159 * for _CID, but a valid use of this has not been seen. 160 */ 161 if (*Op->Asl.Value.String == '*') 162 { 163 AslError (ASL_ERROR, ASL_MSG_LEADING_ASTERISK, 164 Op, Op->Asl.Value.String); 165 return; 166 } 167 168 /* _CID strings are bus-specific, no more checks can be performed */ 169 170 if (Type == ASL_TYPE_CID) 171 { 172 return; 173 } 174 175 /* For _HID, all characters must be alphanumeric */ 176 177 for (i = 0; Op->Asl.Value.String[i]; i++) 178 { 179 if (!isalnum ((int) Op->Asl.Value.String[i])) 180 { 181 AslError (ASL_ERROR, ASL_MSG_ALPHANUMERIC_STRING, 182 Op, Op->Asl.Value.String); 183 return; 184 } 185 } 186 187 /* 188 * _HID String must be one of these forms: 189 * 190 * "AAA####" A is an uppercase letter and # is a hex digit 191 * "ACPI####" # is a hex digit 192 * "NNNN####" N is an uppercase letter or decimal digit (0-9) 193 * # is a hex digit (ACPI 5.0) 194 */ 195 if ((Length < 7) || (Length > 8)) 196 { 197 AslError (ASL_ERROR, ASL_MSG_HID_LENGTH, 198 Op, Op->Asl.Value.String); 199 return; 200 } 201 202 /* _HID Length is valid (7 or 8), now check prefix (first 3 or 4 chars) */ 203 204 if (Length == 7) 205 { 206 /* AAA####: Ensure the alphabetic prefix is all uppercase */ 207 208 for (i = 0; i < 3; i++) 209 { 210 if (!isupper ((int) Op->Asl.Value.String[i])) 211 { 212 AslError (ASL_ERROR, ASL_MSG_UPPER_CASE, 213 Op, &Op->Asl.Value.String[i]); 214 return; 215 } 216 } 217 } 218 else /* Length == 8 */ 219 { 220 /* 221 * ACPI#### or NNNN####: 222 * Ensure the prefix contains only uppercase alpha or decimal digits 223 */ 224 for (i = 0; i < 4; i++) 225 { 226 if (!isupper ((int) Op->Asl.Value.String[i]) && 227 !isdigit ((int) Op->Asl.Value.String[i])) 228 { 229 AslError (ASL_ERROR, ASL_MSG_HID_PREFIX, 230 Op, &Op->Asl.Value.String[i]); 231 return; 232 } 233 } 234 } 235 236 /* Remaining characters (suffix) must be hex digits */ 237 238 for (; i < Length; i++) 239 { 240 if (!isxdigit ((int) Op->Asl.Value.String[i])) 241 { 242 AslError (ASL_ERROR, ASL_MSG_HID_SUFFIX, 243 Op, &Op->Asl.Value.String[i]); 244 break; 245 } 246 } 247 } 248 249 250 /******************************************************************************* 251 * 252 * FUNCTION: AnLastStatementIsReturn 253 * 254 * PARAMETERS: Op - A method parse node 255 * 256 * RETURN: TRUE if last statement is an ASL RETURN. False otherwise 257 * 258 * DESCRIPTION: Walk down the list of top level statements within a method 259 * to find the last one. Check if that last statement is in 260 * fact a RETURN statement. 261 * 262 ******************************************************************************/ 263 264 BOOLEAN 265 AnLastStatementIsReturn ( 266 ACPI_PARSE_OBJECT *Op) 267 { 268 ACPI_PARSE_OBJECT *Next; 269 270 271 /* Check if last statement is a return */ 272 273 Next = ASL_GET_CHILD_NODE (Op); 274 while (Next) 275 { 276 if ((!Next->Asl.Next) && 277 (Next->Asl.ParseOpcode == PARSEOP_RETURN)) 278 { 279 return (TRUE); 280 } 281 282 Next = ASL_GET_PEER_NODE (Next); 283 } 284 285 return (FALSE); 286 } 287 288 289 /******************************************************************************* 290 * 291 * FUNCTION: AnCheckMethodReturnValue 292 * 293 * PARAMETERS: Op - Parent 294 * OpInfo - Parent info 295 * ArgOp - Method invocation op 296 * RequiredBtypes - What caller requires 297 * ThisNodeBtype - What this node returns (if anything) 298 * 299 * RETURN: None 300 * 301 * DESCRIPTION: Check a method invocation for 1) A return value and if it does 302 * in fact return a value, 2) check the type of the return value. 303 * 304 ******************************************************************************/ 305 306 void 307 AnCheckMethodReturnValue ( 308 ACPI_PARSE_OBJECT *Op, 309 const ACPI_OPCODE_INFO *OpInfo, 310 ACPI_PARSE_OBJECT *ArgOp, 311 UINT32 RequiredBtypes, 312 UINT32 ThisNodeBtype) 313 { 314 ACPI_PARSE_OBJECT *OwningOp; 315 ACPI_NAMESPACE_NODE *Node; 316 317 318 Node = ArgOp->Asl.Node; 319 320 if (!Node) 321 { 322 /* No error message, this can happen and is OK */ 323 324 return; 325 } 326 327 /* Examine the parent op of this method */ 328 329 OwningOp = Node->Op; 330 if (OwningOp->Asl.CompileFlags & NODE_METHOD_NO_RETVAL) 331 { 332 /* Method NEVER returns a value */ 333 334 AslError (ASL_ERROR, ASL_MSG_NO_RETVAL, Op, Op->Asl.ExternalName); 335 } 336 else if (OwningOp->Asl.CompileFlags & NODE_METHOD_SOME_NO_RETVAL) 337 { 338 /* Method SOMETIMES returns a value, SOMETIMES not */ 339 340 AslError (ASL_WARNING, ASL_MSG_SOME_NO_RETVAL, 341 Op, Op->Asl.ExternalName); 342 } 343 else if (!(ThisNodeBtype & RequiredBtypes)) 344 { 345 /* Method returns a value, but the type is wrong */ 346 347 AnFormatBtype (StringBuffer, ThisNodeBtype); 348 AnFormatBtype (StringBuffer2, RequiredBtypes); 349 350 /* 351 * The case where the method does not return any value at all 352 * was already handled in the namespace cross reference 353 * -- Only issue an error if the method in fact returns a value, 354 * but it is of the wrong type 355 */ 356 if (ThisNodeBtype != 0) 357 { 358 sprintf (MsgBuffer, 359 "Method returns [%s], %s operator requires [%s]", 360 StringBuffer, OpInfo->Name, StringBuffer2); 361 362 AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer); 363 } 364 } 365 } 366 367 368 /******************************************************************************* 369 * 370 * FUNCTION: AnIsResultUsed 371 * 372 * PARAMETERS: Op - Parent op for the operator 373 * 374 * RETURN: TRUE if result from this operation is actually consumed 375 * 376 * DESCRIPTION: Determine if the function result value from an operator is 377 * used. 378 * 379 ******************************************************************************/ 380 381 BOOLEAN 382 AnIsResultUsed ( 383 ACPI_PARSE_OBJECT *Op) 384 { 385 ACPI_PARSE_OBJECT *Parent; 386 387 388 switch (Op->Asl.ParseOpcode) 389 { 390 case PARSEOP_INCREMENT: 391 case PARSEOP_DECREMENT: 392 393 /* These are standalone operators, no return value */ 394 395 return (TRUE); 396 397 default: 398 399 break; 400 } 401 402 /* Examine parent to determine if the return value is used */ 403 404 Parent = Op->Asl.Parent; 405 switch (Parent->Asl.ParseOpcode) 406 { 407 /* If/While - check if the operator is the predicate */ 408 409 case PARSEOP_IF: 410 case PARSEOP_WHILE: 411 412 /* First child is the predicate */ 413 414 if (Parent->Asl.Child == Op) 415 { 416 return (TRUE); 417 } 418 419 return (FALSE); 420 421 /* Not used if one of these is the parent */ 422 423 case PARSEOP_METHOD: 424 case PARSEOP_DEFINITION_BLOCK: 425 case PARSEOP_ELSE: 426 427 return (FALSE); 428 429 default: 430 431 /* Any other type of parent means that the result is used */ 432 433 return (TRUE); 434 } 435 } 436 437 438 /******************************************************************************* 439 * 440 * FUNCTION: ApCheckForGpeNameConflict 441 * 442 * PARAMETERS: Op - Current parse op 443 * 444 * RETURN: None 445 * 446 * DESCRIPTION: Check for a conflict between GPE names within this scope. 447 * Conflict means two GPE names with the same GPE number, but 448 * different types -- such as _L1C and _E1C. 449 * 450 ******************************************************************************/ 451 452 void 453 ApCheckForGpeNameConflict ( 454 ACPI_PARSE_OBJECT *Op) 455 { 456 ACPI_PARSE_OBJECT *NextOp; 457 UINT32 GpeNumber; 458 char Name[ACPI_NAME_SIZE + 1]; 459 char Target[ACPI_NAME_SIZE]; 460 461 462 /* Need a null-terminated string version of NameSeg */ 463 464 ACPI_MOVE_32_TO_32 (Name, &Op->Asl.NameSeg); 465 Name[ACPI_NAME_SIZE] = 0; 466 467 /* 468 * For a GPE method: 469 * 1st char must be underscore 470 * 2nd char must be L or E 471 * 3rd/4th chars must be a hex number 472 */ 473 if ((Name[0] != '_') || 474 ((Name[1] != 'L') && (Name[1] != 'E'))) 475 { 476 return; 477 } 478 479 /* Verify 3rd/4th chars are a valid hex value */ 480 481 GpeNumber = strtoul (&Name[2], NULL, 16); 482 if (GpeNumber == ACPI_UINT32_MAX) 483 { 484 return; 485 } 486 487 /* 488 * We are now sure we have an _Lxx or _Exx. 489 * Create the target name that would cause collision (Flip E/L) 490 */ 491 ACPI_MOVE_32_TO_32 (Target, Name); 492 493 /* Inject opposite letter ("L" versus "E") */ 494 495 if (Name[1] == 'L') 496 { 497 Target[1] = 'E'; 498 } 499 else /* Name[1] == 'E' */ 500 { 501 Target[1] = 'L'; 502 } 503 504 /* Search all peers (objects within this scope) for target match */ 505 506 NextOp = Op->Asl.Next; 507 while (NextOp) 508 { 509 /* 510 * We mostly care about methods, but check Name() constructs also, 511 * even though they will get another error for not being a method. 512 * All GPE names must be defined as control methods. 513 */ 514 if ((NextOp->Asl.ParseOpcode == PARSEOP_METHOD) || 515 (NextOp->Asl.ParseOpcode == PARSEOP_NAME)) 516 { 517 if (ACPI_COMPARE_NAME (Target, NextOp->Asl.NameSeg)) 518 { 519 /* Found both _Exy and _Lxy in the same scope, error */ 520 521 AslError (ASL_ERROR, ASL_MSG_GPE_NAME_CONFLICT, NextOp, 522 Name); 523 return; 524 } 525 } 526 527 NextOp = NextOp->Asl.Next; 528 } 529 530 /* OK, no conflict found */ 531 532 return; 533 } 534 535 536 /******************************************************************************* 537 * 538 * FUNCTION: ApCheckRegMethod 539 * 540 * PARAMETERS: Op - Current parse op 541 * 542 * RETURN: None 543 * 544 * DESCRIPTION: Ensure that a _REG method has a corresponding Operation 545 * Region declaration within the same scope. Note: _REG is defined 546 * to have two arguments and must therefore be defined as a 547 * control method. 548 * 549 ******************************************************************************/ 550 551 void 552 ApCheckRegMethod ( 553 ACPI_PARSE_OBJECT *Op) 554 { 555 ACPI_PARSE_OBJECT *Next; 556 ACPI_PARSE_OBJECT *Parent; 557 558 559 /* We are only interested in _REG methods */ 560 561 if (!ACPI_COMPARE_NAME (METHOD_NAME__REG, &Op->Asl.NameSeg)) 562 { 563 return; 564 } 565 566 /* Get the start of the current scope */ 567 568 Parent = Op->Asl.Parent; 569 Next = Parent->Asl.Child; 570 571 /* Search entire scope for an operation region declaration */ 572 573 while (Next) 574 { 575 if (Next->Asl.ParseOpcode == PARSEOP_OPERATIONREGION) 576 { 577 return; /* Found region, OK */ 578 } 579 580 Next = Next->Asl.Next; 581 } 582 583 /* No region found, issue warning */ 584 585 AslError (ASL_WARNING, ASL_MSG_NO_REGION, Op, NULL); 586 } 587 588 589 /******************************************************************************* 590 * 591 * FUNCTION: ApFindNameInDeviceTree 592 * 593 * PARAMETERS: Name - Name to search for 594 * Op - Current parse op 595 * 596 * RETURN: TRUE if name found in the same scope as Op. 597 * 598 * DESCRIPTION: Determine if a name appears in the same scope as Op, as either 599 * a Method() or a Name(). "Same scope" can mean under an If or 600 * Else statement. 601 * 602 * NOTE: Detects _HID/_ADR in this type of construct (legal in ACPI 6.1+) 603 * 604 * Scope (\_SB.PCI0) 605 * { 606 * Device (I2C0) 607 * { 608 * If (SMD0 != 4) { 609 * Name (_HID, "INT3442") 610 * } Else { 611 * Name (_ADR, 0x400) 612 * } 613 * } 614 * } 615 ******************************************************************************/ 616 617 BOOLEAN 618 ApFindNameInDeviceTree ( 619 char *Name, 620 ACPI_PARSE_OBJECT *Op) 621 { 622 ACPI_STATUS Status; 623 624 625 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD, 626 ApDeviceSubtreeWalk, NULL, Name); 627 628 if (Status == AE_CTRL_TRUE) 629 { 630 return (TRUE); /* Found a match */ 631 } 632 633 return (FALSE); 634 } 635 636 637 /* Callback function for interface above */ 638 639 static ACPI_STATUS 640 ApDeviceSubtreeWalk ( 641 ACPI_PARSE_OBJECT *Op, 642 UINT32 Level, 643 void *Context) 644 { 645 char *Name = ACPI_CAST_PTR (char, Context); 646 647 648 switch (Op->Asl.ParseOpcode) 649 { 650 case PARSEOP_DEVICE: 651 652 /* Level 0 is the starting device, ignore it */ 653 654 if (Level > 0) 655 { 656 /* Ignore sub-devices */ 657 658 return (AE_CTRL_DEPTH); 659 } 660 break; 661 662 case PARSEOP_NAME: 663 case PARSEOP_METHOD: 664 665 /* These are what we are looking for */ 666 667 if (ACPI_COMPARE_NAME (Name, Op->Asl.NameSeg)) 668 { 669 return (AE_CTRL_TRUE); 670 } 671 return (AE_CTRL_DEPTH); 672 673 case PARSEOP_SCOPE: 674 case PARSEOP_FIELD: 675 case PARSEOP_OPERATIONREGION: 676 677 /* 678 * We want to ignore these, because either they can be large 679 * subtrees or open a scope to somewhere else. 680 */ 681 return (AE_CTRL_DEPTH); 682 683 default: 684 break; 685 } 686 687 return (AE_OK); 688 } 689 690 691 /******************************************************************************* 692 * 693 * FUNCTION: ApFindNameInScope 694 * 695 * PARAMETERS: Name - Name to search for 696 * Op - Current parse op 697 * 698 * RETURN: TRUE if name found in the same scope as Op. 699 * 700 * DESCRIPTION: Determine if a name appears in the same scope as Op, as either 701 * a Method() or a Name(). 702 * 703 ******************************************************************************/ 704 705 BOOLEAN 706 ApFindNameInScope ( 707 char *Name, 708 ACPI_PARSE_OBJECT *Op) 709 { 710 ACPI_PARSE_OBJECT *Next; 711 ACPI_PARSE_OBJECT *Parent; 712 713 714 /* Get the start of the current scope */ 715 716 Parent = Op->Asl.Parent; 717 Next = Parent->Asl.Child; 718 719 /* Search entire scope for a match to the name */ 720 721 while (Next) 722 { 723 if ((Next->Asl.ParseOpcode == PARSEOP_METHOD) || 724 (Next->Asl.ParseOpcode == PARSEOP_NAME)) 725 { 726 if (ACPI_COMPARE_NAME (Name, Next->Asl.NameSeg)) 727 { 728 return (TRUE); 729 } 730 } 731 732 Next = Next->Asl.Next; 733 } 734 735 return (FALSE); 736 } 737