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