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 312 /* Examine the parent op of this method */ 313 314 OwningOp = Node->Op; 315 if (OwningOp->Asl.CompileFlags & NODE_METHOD_NO_RETVAL) 316 { 317 /* Method NEVER returns a value */ 318 319 AslError (ASL_ERROR, ASL_MSG_NO_RETVAL, Op, Op->Asl.ExternalName); 320 } 321 else if (OwningOp->Asl.CompileFlags & NODE_METHOD_SOME_NO_RETVAL) 322 { 323 /* Method SOMETIMES returns a value, SOMETIMES not */ 324 325 AslError (ASL_WARNING, ASL_MSG_SOME_NO_RETVAL, 326 Op, Op->Asl.ExternalName); 327 } 328 else if (!(ThisNodeBtype & RequiredBtypes)) 329 { 330 /* Method returns a value, but the type is wrong */ 331 332 AnFormatBtype (StringBuffer, ThisNodeBtype); 333 AnFormatBtype (StringBuffer2, RequiredBtypes); 334 335 /* 336 * The case where the method does not return any value at all 337 * was already handled in the namespace cross reference 338 * -- Only issue an error if the method in fact returns a value, 339 * but it is of the wrong type 340 */ 341 if (ThisNodeBtype != 0) 342 { 343 sprintf (MsgBuffer, 344 "Method returns [%s], %s operator requires [%s]", 345 StringBuffer, OpInfo->Name, StringBuffer2); 346 347 AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer); 348 } 349 } 350 } 351 352 353 /******************************************************************************* 354 * 355 * FUNCTION: AnIsResultUsed 356 * 357 * PARAMETERS: Op - Parent op for the operator 358 * 359 * RETURN: TRUE if result from this operation is actually consumed 360 * 361 * DESCRIPTION: Determine if the function result value from an operator is 362 * used. 363 * 364 ******************************************************************************/ 365 366 BOOLEAN 367 AnIsResultUsed ( 368 ACPI_PARSE_OBJECT *Op) 369 { 370 ACPI_PARSE_OBJECT *Parent; 371 372 373 switch (Op->Asl.ParseOpcode) 374 { 375 case PARSEOP_INCREMENT: 376 case PARSEOP_DECREMENT: 377 378 /* These are standalone operators, no return value */ 379 380 return (TRUE); 381 382 default: 383 384 break; 385 } 386 387 /* Examine parent to determine if the return value is used */ 388 389 Parent = Op->Asl.Parent; 390 switch (Parent->Asl.ParseOpcode) 391 { 392 /* If/While - check if the operator is the predicate */ 393 394 case PARSEOP_IF: 395 case PARSEOP_WHILE: 396 397 /* First child is the predicate */ 398 399 if (Parent->Asl.Child == Op) 400 { 401 return (TRUE); 402 } 403 404 return (FALSE); 405 406 /* Not used if one of these is the parent */ 407 408 case PARSEOP_METHOD: 409 case PARSEOP_DEFINITION_BLOCK: 410 case PARSEOP_ELSE: 411 412 return (FALSE); 413 414 default: 415 416 /* Any other type of parent means that the result is used */ 417 418 return (TRUE); 419 } 420 } 421 422 423 /******************************************************************************* 424 * 425 * FUNCTION: ApCheckForGpeNameConflict 426 * 427 * PARAMETERS: Op - Current parse op 428 * 429 * RETURN: None 430 * 431 * DESCRIPTION: Check for a conflict between GPE names within this scope. 432 * Conflict means two GPE names with the same GPE number, but 433 * different types -- such as _L1C and _E1C. 434 * 435 ******************************************************************************/ 436 437 void 438 ApCheckForGpeNameConflict ( 439 ACPI_PARSE_OBJECT *Op) 440 { 441 ACPI_PARSE_OBJECT *NextOp; 442 UINT32 GpeNumber; 443 char Name[ACPI_NAME_SIZE + 1]; 444 char Target[ACPI_NAME_SIZE]; 445 446 447 /* Need a null-terminated string version of NameSeg */ 448 449 ACPI_MOVE_32_TO_32 (Name, &Op->Asl.NameSeg); 450 Name[ACPI_NAME_SIZE] = 0; 451 452 /* 453 * For a GPE method: 454 * 1st char must be underscore 455 * 2nd char must be L or E 456 * 3rd/4th chars must be a hex number 457 */ 458 if ((Name[0] != '_') || 459 ((Name[1] != 'L') && (Name[1] != 'E'))) 460 { 461 return; 462 } 463 464 /* Verify 3rd/4th chars are a valid hex value */ 465 466 GpeNumber = strtoul (&Name[2], NULL, 16); 467 if (GpeNumber == ACPI_UINT32_MAX) 468 { 469 return; 470 } 471 472 /* 473 * We are now sure we have an _Lxx or _Exx. 474 * Create the target name that would cause collision (Flip E/L) 475 */ 476 ACPI_MOVE_32_TO_32 (Target, Name); 477 478 /* Inject opposite letter ("L" versus "E") */ 479 480 if (Name[1] == 'L') 481 { 482 Target[1] = 'E'; 483 } 484 else /* Name[1] == 'E' */ 485 { 486 Target[1] = 'L'; 487 } 488 489 /* Search all peers (objects within this scope) for target match */ 490 491 NextOp = Op->Asl.Next; 492 while (NextOp) 493 { 494 /* 495 * We mostly care about methods, but check Name() constructs also, 496 * even though they will get another error for not being a method. 497 * All GPE names must be defined as control methods. 498 */ 499 if ((NextOp->Asl.ParseOpcode == PARSEOP_METHOD) || 500 (NextOp->Asl.ParseOpcode == PARSEOP_NAME)) 501 { 502 if (ACPI_COMPARE_NAME (Target, NextOp->Asl.NameSeg)) 503 { 504 /* Found both _Exy and _Lxy in the same scope, error */ 505 506 AslError (ASL_ERROR, ASL_MSG_GPE_NAME_CONFLICT, NextOp, 507 Name); 508 return; 509 } 510 } 511 512 NextOp = NextOp->Asl.Next; 513 } 514 515 /* OK, no conflict found */ 516 517 return; 518 } 519 520 521 /******************************************************************************* 522 * 523 * FUNCTION: ApCheckRegMethod 524 * 525 * PARAMETERS: Op - Current parse op 526 * 527 * RETURN: None 528 * 529 * DESCRIPTION: Ensure that a _REG method has a corresponding Operation 530 * Region declaration within the same scope. Note: _REG is defined 531 * to have two arguments and must therefore be defined as a 532 * control method. 533 * 534 ******************************************************************************/ 535 536 void 537 ApCheckRegMethod ( 538 ACPI_PARSE_OBJECT *Op) 539 { 540 ACPI_PARSE_OBJECT *Next; 541 ACPI_PARSE_OBJECT *Parent; 542 543 544 /* We are only interested in _REG methods */ 545 546 if (!ACPI_COMPARE_NAME (METHOD_NAME__REG, &Op->Asl.NameSeg)) 547 { 548 return; 549 } 550 551 /* Get the start of the current scope */ 552 553 Parent = Op->Asl.Parent; 554 Next = Parent->Asl.Child; 555 556 /* Search entire scope for an operation region declaration */ 557 558 while (Next) 559 { 560 if (Next->Asl.ParseOpcode == PARSEOP_OPERATIONREGION) 561 { 562 return; /* Found region, OK */ 563 } 564 565 Next = Next->Asl.Next; 566 } 567 568 /* No region found, issue warning */ 569 570 AslError (ASL_WARNING, ASL_MSG_NO_REGION, Op, NULL); 571 } 572 573 574 /******************************************************************************* 575 * 576 * FUNCTION: ApFindNameInScope 577 * 578 * PARAMETERS: Name - Name to search for 579 * Op - Current parse op 580 * 581 * RETURN: TRUE if name found in the same scope as Op. 582 * 583 * DESCRIPTION: Determine if a name appears in the same scope as Op, as either 584 * a Method() or a Name(). 585 * 586 ******************************************************************************/ 587 588 BOOLEAN 589 ApFindNameInScope ( 590 char *Name, 591 ACPI_PARSE_OBJECT *Op) 592 { 593 ACPI_PARSE_OBJECT *Next; 594 ACPI_PARSE_OBJECT *Parent; 595 596 597 /* Get the start of the current scope */ 598 599 Parent = Op->Asl.Parent; 600 Next = Parent->Asl.Child; 601 602 /* Search entire scope for a match to the name */ 603 604 while (Next) 605 { 606 if ((Next->Asl.ParseOpcode == PARSEOP_METHOD) || 607 (Next->Asl.ParseOpcode == PARSEOP_NAME)) 608 { 609 if (ACPI_COMPARE_NAME (Name, Next->Asl.NameSeg)) 610 { 611 return (TRUE); 612 } 613 } 614 615 Next = Next->Asl.Next; 616 } 617 618 return (FALSE); 619 } 620