1 /****************************************************************************** 2 * 3 * Module Name: aslanalyze.c - Support functions for parse tree walks 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, 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 "aslcompiler.h" 46 #include "aslcompiler.y.h" 47 #include <string.h> 48 49 50 #define _COMPONENT ACPI_COMPILER 51 ACPI_MODULE_NAME ("aslanalyze") 52 53 54 /******************************************************************************* 55 * 56 * FUNCTION: AnIsInternalMethod 57 * 58 * PARAMETERS: Op - Current op 59 * 60 * RETURN: Boolean 61 * 62 * DESCRIPTION: Check for an internal control method. 63 * 64 ******************************************************************************/ 65 66 BOOLEAN 67 AnIsInternalMethod ( 68 ACPI_PARSE_OBJECT *Op) 69 { 70 71 if ((!ACPI_STRCMP (Op->Asl.ExternalName, "\\_OSI")) || 72 (!ACPI_STRCMP (Op->Asl.ExternalName, "_OSI"))) 73 { 74 return (TRUE); 75 } 76 77 return (FALSE); 78 } 79 80 81 /******************************************************************************* 82 * 83 * FUNCTION: AnGetInternalMethodReturnType 84 * 85 * PARAMETERS: Op - Current op 86 * 87 * RETURN: Btype 88 * 89 * DESCRIPTION: Get the return type of an internal method 90 * 91 ******************************************************************************/ 92 93 UINT32 94 AnGetInternalMethodReturnType ( 95 ACPI_PARSE_OBJECT *Op) 96 { 97 98 if ((!ACPI_STRCMP (Op->Asl.ExternalName, "\\_OSI")) || 99 (!ACPI_STRCMP (Op->Asl.ExternalName, "_OSI"))) 100 { 101 return (ACPI_BTYPE_STRING); 102 } 103 104 return (0); 105 } 106 107 108 /******************************************************************************* 109 * 110 * FUNCTION: AnCheckId 111 * 112 * PARAMETERS: Op - Current parse op 113 * Type - HID or CID 114 * 115 * RETURN: None 116 * 117 * DESCRIPTION: Perform various checks on _HID and _CID strings. Only limited 118 * checks can be performed on _CID strings. 119 * 120 ******************************************************************************/ 121 122 void 123 AnCheckId ( 124 ACPI_PARSE_OBJECT *Op, 125 ACPI_NAME Type) 126 { 127 UINT32 i; 128 ACPI_SIZE Length; 129 130 131 /* Only care about string versions of _HID/_CID (integers are legal) */ 132 133 if (Op->Asl.ParseOpcode != PARSEOP_STRING_LITERAL) 134 { 135 return; 136 } 137 138 /* For both _HID and _CID, the string must be non-null */ 139 140 Length = strlen (Op->Asl.Value.String); 141 if (!Length) 142 { 143 AslError (ASL_ERROR, ASL_MSG_NULL_STRING, 144 Op, NULL); 145 return; 146 } 147 148 /* 149 * One of the things we want to catch here is the use of a leading 150 * asterisk in the string -- an odd construct that certain platform 151 * manufacturers are fond of. Technically, a leading asterisk is OK 152 * for _CID, but a valid use of this has not been seen. 153 */ 154 if (*Op->Asl.Value.String == '*') 155 { 156 AslError (ASL_ERROR, ASL_MSG_LEADING_ASTERISK, 157 Op, Op->Asl.Value.String); 158 return; 159 } 160 161 /* _CID strings are bus-specific, no more checks can be performed */ 162 163 if (Type == ASL_TYPE_CID) 164 { 165 return; 166 } 167 168 /* For _HID, all characters must be alphanumeric */ 169 170 for (i = 0; Op->Asl.Value.String[i]; i++) 171 { 172 if (!isalnum ((int) Op->Asl.Value.String[i])) 173 { 174 AslError (ASL_ERROR, ASL_MSG_ALPHANUMERIC_STRING, 175 Op, Op->Asl.Value.String); 176 return; 177 } 178 } 179 180 /* 181 * _HID String must be one of these forms: 182 * 183 * "AAA####" A is an uppercase letter and # is a hex digit 184 * "ACPI####" # is a hex digit 185 * "NNNN####" N is an uppercase letter or decimal digit (0-9) 186 * # is a hex digit (ACPI 5.0) 187 */ 188 if ((Length < 7) || (Length > 8)) 189 { 190 AslError (ASL_ERROR, ASL_MSG_HID_LENGTH, 191 Op, Op->Asl.Value.String); 192 return; 193 } 194 195 /* _HID Length is valid (7 or 8), now check the prefix (first 3 or 4 chars) */ 196 197 if (Length == 7) 198 { 199 /* AAA####: Ensure the alphabetic prefix is all uppercase */ 200 201 for (i = 0; i < 3; i++) 202 { 203 if (!isupper ((int) Op->Asl.Value.String[i])) 204 { 205 AslError (ASL_ERROR, ASL_MSG_UPPER_CASE, 206 Op, &Op->Asl.Value.String[i]); 207 return; 208 } 209 } 210 } 211 else /* Length == 8 */ 212 { 213 /* 214 * ACPI#### or NNNN####: 215 * Ensure the prefix contains only uppercase alpha or decimal digits 216 */ 217 for (i = 0; i < 4; i++) 218 { 219 if (!isupper ((int) Op->Asl.Value.String[i]) && 220 !isdigit ((int) Op->Asl.Value.String[i])) 221 { 222 AslError (ASL_ERROR, ASL_MSG_HID_PREFIX, 223 Op, &Op->Asl.Value.String[i]); 224 return; 225 } 226 } 227 } 228 229 /* Remaining characters (suffix) must be hex digits */ 230 231 for (; i < Length; i++) 232 { 233 if (!isxdigit ((int) Op->Asl.Value.String[i])) 234 { 235 AslError (ASL_ERROR, ASL_MSG_HID_SUFFIX, 236 Op, &Op->Asl.Value.String[i]); 237 break; 238 } 239 } 240 } 241 242 243 /******************************************************************************* 244 * 245 * FUNCTION: AnLastStatementIsReturn 246 * 247 * PARAMETERS: Op - A method parse node 248 * 249 * RETURN: TRUE if last statement is an ASL RETURN. False otherwise 250 * 251 * DESCRIPTION: Walk down the list of top level statements within a method 252 * to find the last one. Check if that last statement is in 253 * fact a RETURN statement. 254 * 255 ******************************************************************************/ 256 257 BOOLEAN 258 AnLastStatementIsReturn ( 259 ACPI_PARSE_OBJECT *Op) 260 { 261 ACPI_PARSE_OBJECT *Next; 262 263 264 /* Check if last statement is a return */ 265 266 Next = ASL_GET_CHILD_NODE (Op); 267 while (Next) 268 { 269 if ((!Next->Asl.Next) && 270 (Next->Asl.ParseOpcode == PARSEOP_RETURN)) 271 { 272 return (TRUE); 273 } 274 275 Next = ASL_GET_PEER_NODE (Next); 276 } 277 278 return (FALSE); 279 } 280 281 282 /******************************************************************************* 283 * 284 * FUNCTION: AnCheckMethodReturnValue 285 * 286 * PARAMETERS: Op - Parent 287 * OpInfo - Parent info 288 * ArgOp - Method invocation op 289 * RequiredBtypes - What caller requires 290 * ThisNodeBtype - What this node returns (if anything) 291 * 292 * RETURN: None 293 * 294 * DESCRIPTION: Check a method invocation for 1) A return value and if it does 295 * in fact return a value, 2) check the type of the return value. 296 * 297 ******************************************************************************/ 298 299 void 300 AnCheckMethodReturnValue ( 301 ACPI_PARSE_OBJECT *Op, 302 const ACPI_OPCODE_INFO *OpInfo, 303 ACPI_PARSE_OBJECT *ArgOp, 304 UINT32 RequiredBtypes, 305 UINT32 ThisNodeBtype) 306 { 307 ACPI_PARSE_OBJECT *OwningOp; 308 ACPI_NAMESPACE_NODE *Node; 309 310 311 Node = ArgOp->Asl.Node; 312 313 314 /* Examine the parent op of this method */ 315 316 OwningOp = Node->Op; 317 if (OwningOp->Asl.CompileFlags & NODE_METHOD_NO_RETVAL) 318 { 319 /* Method NEVER returns a value */ 320 321 AslError (ASL_ERROR, ASL_MSG_NO_RETVAL, Op, Op->Asl.ExternalName); 322 } 323 else if (OwningOp->Asl.CompileFlags & NODE_METHOD_SOME_NO_RETVAL) 324 { 325 /* Method SOMETIMES returns a value, SOMETIMES not */ 326 327 AslError (ASL_WARNING, ASL_MSG_SOME_NO_RETVAL, Op, Op->Asl.ExternalName); 328 } 329 else if (!(ThisNodeBtype & RequiredBtypes)) 330 { 331 /* Method returns a value, but the type is wrong */ 332 333 AnFormatBtype (StringBuffer, ThisNodeBtype); 334 AnFormatBtype (StringBuffer2, RequiredBtypes); 335 336 /* 337 * The case where the method does not return any value at all 338 * was already handled in the namespace cross reference 339 * -- Only issue an error if the method in fact returns a value, 340 * but it is of the wrong type 341 */ 342 if (ThisNodeBtype != 0) 343 { 344 sprintf (MsgBuffer, 345 "Method returns [%s], %s operator requires [%s]", 346 StringBuffer, OpInfo->Name, StringBuffer2); 347 348 AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer); 349 } 350 } 351 } 352 353 354 /******************************************************************************* 355 * 356 * FUNCTION: AnIsResultUsed 357 * 358 * PARAMETERS: Op - Parent op for the operator 359 * 360 * RETURN: TRUE if result from this operation is actually consumed 361 * 362 * DESCRIPTION: Determine if the function result value from an operator is 363 * used. 364 * 365 ******************************************************************************/ 366 367 BOOLEAN 368 AnIsResultUsed ( 369 ACPI_PARSE_OBJECT *Op) 370 { 371 ACPI_PARSE_OBJECT *Parent; 372 373 374 switch (Op->Asl.ParseOpcode) 375 { 376 case PARSEOP_INCREMENT: 377 case PARSEOP_DECREMENT: 378 379 /* These are standalone operators, no return value */ 380 381 return (TRUE); 382 383 default: 384 385 break; 386 } 387 388 /* Examine parent to determine if the return value is used */ 389 390 Parent = Op->Asl.Parent; 391 switch (Parent->Asl.ParseOpcode) 392 { 393 /* If/While - check if the operator is the predicate */ 394 395 case PARSEOP_IF: 396 case PARSEOP_WHILE: 397 398 /* First child is the predicate */ 399 400 if (Parent->Asl.Child == Op) 401 { 402 return (TRUE); 403 } 404 return (FALSE); 405 406 /* Not used if one of these is the parent */ 407 408 case PARSEOP_METHOD: 409 case PARSEOP_DEFINITIONBLOCK: 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 = ACPI_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 }