1 /****************************************************************************** 2 * 3 * Module Name: aslanalyze.c - Support functions for 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 <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, 143 Op, NULL); 144 return; 145 } 146 147 /* 148 * One of the things we want to catch here is the use of a leading 149 * asterisk in the string -- an odd construct that certain platform 150 * manufacturers are fond of. Technically, a leading asterisk is OK 151 * for _CID, but a valid use of this has not been seen. 152 */ 153 if (*Op->Asl.Value.String == '*') 154 { 155 AslError (ASL_ERROR, ASL_MSG_LEADING_ASTERISK, 156 Op, Op->Asl.Value.String); 157 return; 158 } 159 160 /* _CID strings are bus-specific, no more checks can be performed */ 161 162 if (Type == ASL_TYPE_CID) 163 { 164 return; 165 } 166 167 /* For _HID, all characters must be alphanumeric */ 168 169 for (i = 0; Op->Asl.Value.String[i]; i++) 170 { 171 if (!isalnum ((int) Op->Asl.Value.String[i])) 172 { 173 AslError (ASL_ERROR, ASL_MSG_ALPHANUMERIC_STRING, 174 Op, Op->Asl.Value.String); 175 return; 176 } 177 } 178 179 /* 180 * _HID String must be one of these forms: 181 * 182 * "AAA####" A is an uppercase letter and # is a hex digit 183 * "ACPI####" # is a hex digit 184 * "NNNN####" N is an uppercase letter or decimal digit (0-9) 185 * # is a hex digit (ACPI 5.0) 186 */ 187 if ((Length < 7) || (Length > 8)) 188 { 189 AslError (ASL_ERROR, ASL_MSG_HID_LENGTH, 190 Op, Op->Asl.Value.String); 191 return; 192 } 193 194 /* _HID Length is valid (7 or 8), now check the prefix (first 3 or 4 chars) */ 195 196 if (Length == 7) 197 { 198 /* AAA####: Ensure the alphabetic prefix is all uppercase */ 199 200 for (i = 0; i < 3; i++) 201 { 202 if (!isupper ((int) Op->Asl.Value.String[i])) 203 { 204 AslError (ASL_ERROR, ASL_MSG_UPPER_CASE, 205 Op, &Op->Asl.Value.String[i]); 206 return; 207 } 208 } 209 } 210 else /* Length == 8 */ 211 { 212 /* 213 * ACPI#### or NNNN####: 214 * Ensure the prefix contains only uppercase alpha or decimal digits 215 */ 216 for (i = 0; i < 4; i++) 217 { 218 if (!isupper ((int) Op->Asl.Value.String[i]) && 219 !isdigit ((int) Op->Asl.Value.String[i])) 220 { 221 AslError (ASL_ERROR, ASL_MSG_HID_PREFIX, 222 Op, &Op->Asl.Value.String[i]); 223 return; 224 } 225 } 226 } 227 228 /* Remaining characters (suffix) must be hex digits */ 229 230 for (; i < Length; i++) 231 { 232 if (!isxdigit ((int) Op->Asl.Value.String[i])) 233 { 234 AslError (ASL_ERROR, ASL_MSG_HID_SUFFIX, 235 Op, &Op->Asl.Value.String[i]); 236 break; 237 } 238 } 239 } 240 241 242 /******************************************************************************* 243 * 244 * FUNCTION: AnLastStatementIsReturn 245 * 246 * PARAMETERS: Op - A method parse node 247 * 248 * RETURN: TRUE if last statement is an ASL RETURN. False otherwise 249 * 250 * DESCRIPTION: Walk down the list of top level statements within a method 251 * to find the last one. Check if that last statement is in 252 * fact a RETURN statement. 253 * 254 ******************************************************************************/ 255 256 BOOLEAN 257 AnLastStatementIsReturn ( 258 ACPI_PARSE_OBJECT *Op) 259 { 260 ACPI_PARSE_OBJECT *Next; 261 262 263 /* Check if last statement is a return */ 264 265 Next = ASL_GET_CHILD_NODE (Op); 266 while (Next) 267 { 268 if ((!Next->Asl.Next) && 269 (Next->Asl.ParseOpcode == PARSEOP_RETURN)) 270 { 271 return (TRUE); 272 } 273 274 Next = ASL_GET_PEER_NODE (Next); 275 } 276 277 return (FALSE); 278 } 279 280 281 /******************************************************************************* 282 * 283 * FUNCTION: AnCheckMethodReturnValue 284 * 285 * PARAMETERS: Op - Parent 286 * OpInfo - Parent info 287 * ArgOp - Method invocation op 288 * RequiredBtypes - What caller requires 289 * ThisNodeBtype - What this node returns (if anything) 290 * 291 * RETURN: None 292 * 293 * DESCRIPTION: Check a method invocation for 1) A return value and if it does 294 * in fact return a value, 2) check the type of the return value. 295 * 296 ******************************************************************************/ 297 298 void 299 AnCheckMethodReturnValue ( 300 ACPI_PARSE_OBJECT *Op, 301 const ACPI_OPCODE_INFO *OpInfo, 302 ACPI_PARSE_OBJECT *ArgOp, 303 UINT32 RequiredBtypes, 304 UINT32 ThisNodeBtype) 305 { 306 ACPI_PARSE_OBJECT *OwningOp; 307 ACPI_NAMESPACE_NODE *Node; 308 309 310 Node = ArgOp->Asl.Node; 311 312 313 /* Examine the parent op of this method */ 314 315 OwningOp = Node->Op; 316 if (OwningOp->Asl.CompileFlags & NODE_METHOD_NO_RETVAL) 317 { 318 /* Method NEVER returns a value */ 319 320 AslError (ASL_ERROR, ASL_MSG_NO_RETVAL, Op, Op->Asl.ExternalName); 321 } 322 else if (OwningOp->Asl.CompileFlags & NODE_METHOD_SOME_NO_RETVAL) 323 { 324 /* Method SOMETIMES returns a value, SOMETIMES not */ 325 326 AslError (ASL_WARNING, ASL_MSG_SOME_NO_RETVAL, 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 return (FALSE); 404 405 /* Not used if one of these is the parent */ 406 407 case PARSEOP_METHOD: 408 case PARSEOP_DEFINITIONBLOCK: 409 case PARSEOP_ELSE: 410 411 return (FALSE); 412 413 default: 414 415 /* Any other type of parent means that the result is used */ 416 417 return (TRUE); 418 } 419 } 420 421 422 /******************************************************************************* 423 * 424 * FUNCTION: ApCheckForGpeNameConflict 425 * 426 * PARAMETERS: Op - Current parse op 427 * 428 * RETURN: None 429 * 430 * DESCRIPTION: Check for a conflict between GPE names within this scope. 431 * Conflict means two GPE names with the same GPE number, but 432 * different types -- such as _L1C and _E1C. 433 * 434 ******************************************************************************/ 435 436 void 437 ApCheckForGpeNameConflict ( 438 ACPI_PARSE_OBJECT *Op) 439 { 440 ACPI_PARSE_OBJECT *NextOp; 441 UINT32 GpeNumber; 442 char Name[ACPI_NAME_SIZE + 1]; 443 char Target[ACPI_NAME_SIZE]; 444 445 446 /* Need a null-terminated string version of NameSeg */ 447 448 ACPI_MOVE_32_TO_32 (Name, &Op->Asl.NameSeg); 449 Name[ACPI_NAME_SIZE] = 0; 450 451 /* 452 * For a GPE method: 453 * 1st char must be underscore 454 * 2nd char must be L or E 455 * 3rd/4th chars must be a hex number 456 */ 457 if ((Name[0] != '_') || 458 ((Name[1] != 'L') && (Name[1] != 'E'))) 459 { 460 return; 461 } 462 463 /* Verify 3rd/4th chars are a valid hex value */ 464 465 GpeNumber = strtoul (&Name[2], NULL, 16); 466 if (GpeNumber == ACPI_UINT32_MAX) 467 { 468 return; 469 } 470 471 /* 472 * We are now sure we have an _Lxx or _Exx. 473 * Create the target name that would cause collision (Flip E/L) 474 */ 475 ACPI_MOVE_32_TO_32 (Target, Name); 476 477 /* Inject opposite letter ("L" versus "E") */ 478 479 if (Name[1] == 'L') 480 { 481 Target[1] = 'E'; 482 } 483 else /* Name[1] == 'E' */ 484 { 485 Target[1] = 'L'; 486 } 487 488 /* Search all peers (objects within this scope) for target match */ 489 490 NextOp = Op->Asl.Next; 491 while (NextOp) 492 { 493 /* 494 * We mostly care about methods, but check Name() constructs also, 495 * even though they will get another error for not being a method. 496 * All GPE names must be defined as control methods. 497 */ 498 if ((NextOp->Asl.ParseOpcode == PARSEOP_METHOD) || 499 (NextOp->Asl.ParseOpcode == PARSEOP_NAME)) 500 { 501 if (ACPI_COMPARE_NAME (Target, NextOp->Asl.NameSeg)) 502 { 503 /* Found both _Exy and _Lxy in the same scope, error */ 504 505 AslError (ASL_ERROR, ASL_MSG_GPE_NAME_CONFLICT, NextOp, 506 Name); 507 return; 508 } 509 } 510 511 NextOp = NextOp->Asl.Next; 512 } 513 514 /* OK, no conflict found */ 515 516 return; 517 } 518 519 520 /******************************************************************************* 521 * 522 * FUNCTION: ApCheckRegMethod 523 * 524 * PARAMETERS: Op - Current parse op 525 * 526 * RETURN: None 527 * 528 * DESCRIPTION: Ensure that a _REG method has a corresponding Operation 529 * Region declaration within the same scope. Note: _REG is defined 530 * to have two arguments and must therefore be defined as a 531 * control method. 532 * 533 ******************************************************************************/ 534 535 void 536 ApCheckRegMethod ( 537 ACPI_PARSE_OBJECT *Op) 538 { 539 ACPI_PARSE_OBJECT *Next; 540 ACPI_PARSE_OBJECT *Parent; 541 542 543 /* We are only interested in _REG methods */ 544 545 if (!ACPI_COMPARE_NAME (METHOD_NAME__REG, &Op->Asl.NameSeg)) 546 { 547 return; 548 } 549 550 /* Get the start of the current scope */ 551 552 Parent = Op->Asl.Parent; 553 Next = Parent->Asl.Child; 554 555 /* Search entire scope for an operation region declaration */ 556 557 while (Next) 558 { 559 if (Next->Asl.ParseOpcode == PARSEOP_OPERATIONREGION) 560 { 561 return; /* Found region, OK */ 562 } 563 564 Next = Next->Asl.Next; 565 } 566 567 /* No region found, issue warning */ 568 569 AslError (ASL_WARNING, ASL_MSG_NO_REGION, Op, NULL); 570 } 571 572 573 /******************************************************************************* 574 * 575 * FUNCTION: ApFindNameInScope 576 * 577 * PARAMETERS: Name - Name to search for 578 * Op - Current parse op 579 * 580 * RETURN: TRUE if name found in the same scope as Op. 581 * 582 * DESCRIPTION: Determine if a name appears in the same scope as Op, as either 583 * a Method() or a Name(). 584 * 585 ******************************************************************************/ 586 587 BOOLEAN 588 ApFindNameInScope ( 589 char *Name, 590 ACPI_PARSE_OBJECT *Op) 591 { 592 ACPI_PARSE_OBJECT *Next; 593 ACPI_PARSE_OBJECT *Parent; 594 595 596 /* Get the start of the current scope */ 597 598 Parent = Op->Asl.Parent; 599 Next = Parent->Asl.Child; 600 601 /* Search entire scope for a match to the name */ 602 603 while (Next) 604 { 605 if ((Next->Asl.ParseOpcode == PARSEOP_METHOD) || 606 (Next->Asl.ParseOpcode == PARSEOP_NAME)) 607 { 608 if (ACPI_COMPARE_NAME (Name, Next->Asl.NameSeg)) 609 { 610 return (TRUE); 611 } 612 } 613 614 Next = Next->Asl.Next; 615 } 616 617 return (FALSE); 618 } 619