1 /****************************************************************************** 2 * 3 * Module Name: aslanalyze.c - Support functions for parse tree walks 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2011, 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 <contrib/dev/acpica/compiler/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 UINT32 AlphaPrefixLength; 130 131 132 /* Only care about string versions of _HID/_CID (integers are legal) */ 133 134 if (Op->Asl.ParseOpcode != PARSEOP_STRING_LITERAL) 135 { 136 return; 137 } 138 139 /* For both _HID and _CID, the string must be non-null */ 140 141 Length = strlen (Op->Asl.Value.String); 142 if (!Length) 143 { 144 AslError (ASL_ERROR, ASL_MSG_NULL_STRING, 145 Op, NULL); 146 return; 147 } 148 149 /* 150 * One of the things we want to catch here is the use of a leading 151 * asterisk in the string -- an odd construct that certain platform 152 * manufacturers are fond of. Technically, a leading asterisk is OK 153 * for _CID, but a valid use of this has not been seen. 154 */ 155 if (*Op->Asl.Value.String == '*') 156 { 157 AslError (ASL_ERROR, ASL_MSG_LEADING_ASTERISK, 158 Op, Op->Asl.Value.String); 159 return; 160 } 161 162 /* _CID strings are bus-specific, no more checks can be performed */ 163 164 if (Type == ASL_TYPE_CID) 165 { 166 return; 167 } 168 169 /* For _HID, all characters must be alphanumeric */ 170 171 for (i = 0; Op->Asl.Value.String[i]; i++) 172 { 173 if (!isalnum ((int) Op->Asl.Value.String[i])) 174 { 175 AslError (ASL_ERROR, ASL_MSG_ALPHANUMERIC_STRING, 176 Op, Op->Asl.Value.String); 177 break; 178 } 179 } 180 181 /* _HID String must be of the form "XXX####" or "ACPI####" */ 182 183 if ((Length < 7) || (Length > 8)) 184 { 185 AslError (ASL_ERROR, ASL_MSG_HID_LENGTH, 186 Op, Op->Asl.Value.String); 187 return; 188 } 189 190 /* _HID Length is valid, now check for uppercase (first 3 or 4 chars) */ 191 192 AlphaPrefixLength = 3; 193 if (Length >= 8) 194 { 195 AlphaPrefixLength = 4; 196 } 197 198 /* Ensure the alphabetic prefix is all uppercase */ 199 200 for (i = 0; (i < AlphaPrefixLength) && Op->Asl.Value.String[i]; 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 break; 207 } 208 } 209 } 210 211 212 /******************************************************************************* 213 * 214 * FUNCTION: AnLastStatementIsReturn 215 * 216 * PARAMETERS: Op - A method parse node 217 * 218 * RETURN: TRUE if last statement is an ASL RETURN. False otherwise 219 * 220 * DESCRIPTION: Walk down the list of top level statements within a method 221 * to find the last one. Check if that last statement is in 222 * fact a RETURN statement. 223 * 224 ******************************************************************************/ 225 226 BOOLEAN 227 AnLastStatementIsReturn ( 228 ACPI_PARSE_OBJECT *Op) 229 { 230 ACPI_PARSE_OBJECT *Next; 231 232 233 /* Check if last statement is a return */ 234 235 Next = ASL_GET_CHILD_NODE (Op); 236 while (Next) 237 { 238 if ((!Next->Asl.Next) && 239 (Next->Asl.ParseOpcode == PARSEOP_RETURN)) 240 { 241 return (TRUE); 242 } 243 244 Next = ASL_GET_PEER_NODE (Next); 245 } 246 247 return (FALSE); 248 } 249 250 251 /******************************************************************************* 252 * 253 * FUNCTION: AnCheckMethodReturnValue 254 * 255 * PARAMETERS: Op - Parent 256 * OpInfo - Parent info 257 * ArgOp - Method invocation op 258 * RequiredBtypes - What caller requires 259 * ThisNodeBtype - What this node returns (if anything) 260 * 261 * RETURN: None 262 * 263 * DESCRIPTION: Check a method invocation for 1) A return value and if it does 264 * in fact return a value, 2) check the type of the return value. 265 * 266 ******************************************************************************/ 267 268 void 269 AnCheckMethodReturnValue ( 270 ACPI_PARSE_OBJECT *Op, 271 const ACPI_OPCODE_INFO *OpInfo, 272 ACPI_PARSE_OBJECT *ArgOp, 273 UINT32 RequiredBtypes, 274 UINT32 ThisNodeBtype) 275 { 276 ACPI_PARSE_OBJECT *OwningOp; 277 ACPI_NAMESPACE_NODE *Node; 278 279 280 Node = ArgOp->Asl.Node; 281 282 283 /* Examine the parent op of this method */ 284 285 OwningOp = Node->Op; 286 if (OwningOp->Asl.CompileFlags & NODE_METHOD_NO_RETVAL) 287 { 288 /* Method NEVER returns a value */ 289 290 AslError (ASL_ERROR, ASL_MSG_NO_RETVAL, Op, Op->Asl.ExternalName); 291 } 292 else if (OwningOp->Asl.CompileFlags & NODE_METHOD_SOME_NO_RETVAL) 293 { 294 /* Method SOMETIMES returns a value, SOMETIMES not */ 295 296 AslError (ASL_WARNING, ASL_MSG_SOME_NO_RETVAL, Op, Op->Asl.ExternalName); 297 } 298 else if (!(ThisNodeBtype & RequiredBtypes)) 299 { 300 /* Method returns a value, but the type is wrong */ 301 302 AnFormatBtype (StringBuffer, ThisNodeBtype); 303 AnFormatBtype (StringBuffer2, RequiredBtypes); 304 305 /* 306 * The case where the method does not return any value at all 307 * was already handled in the namespace cross reference 308 * -- Only issue an error if the method in fact returns a value, 309 * but it is of the wrong type 310 */ 311 if (ThisNodeBtype != 0) 312 { 313 sprintf (MsgBuffer, 314 "Method returns [%s], %s operator requires [%s]", 315 StringBuffer, OpInfo->Name, StringBuffer2); 316 317 AslError (ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgOp, MsgBuffer); 318 } 319 } 320 } 321 322 323 /******************************************************************************* 324 * 325 * FUNCTION: AnIsResultUsed 326 * 327 * PARAMETERS: Op - Parent op for the operator 328 * 329 * RETURN: TRUE if result from this operation is actually consumed 330 * 331 * DESCRIPTION: Determine if the function result value from an operator is 332 * used. 333 * 334 ******************************************************************************/ 335 336 BOOLEAN 337 AnIsResultUsed ( 338 ACPI_PARSE_OBJECT *Op) 339 { 340 ACPI_PARSE_OBJECT *Parent; 341 342 343 switch (Op->Asl.ParseOpcode) 344 { 345 case PARSEOP_INCREMENT: 346 case PARSEOP_DECREMENT: 347 348 /* These are standalone operators, no return value */ 349 350 return (TRUE); 351 352 default: 353 break; 354 } 355 356 /* Examine parent to determine if the return value is used */ 357 358 Parent = Op->Asl.Parent; 359 switch (Parent->Asl.ParseOpcode) 360 { 361 /* If/While - check if the operator is the predicate */ 362 363 case PARSEOP_IF: 364 case PARSEOP_WHILE: 365 366 /* First child is the predicate */ 367 368 if (Parent->Asl.Child == Op) 369 { 370 return (TRUE); 371 } 372 return (FALSE); 373 374 /* Not used if one of these is the parent */ 375 376 case PARSEOP_METHOD: 377 case PARSEOP_DEFINITIONBLOCK: 378 case PARSEOP_ELSE: 379 380 return (FALSE); 381 382 default: 383 /* Any other type of parent means that the result is used */ 384 385 return (TRUE); 386 } 387 } 388 389 390 /******************************************************************************* 391 * 392 * FUNCTION: ApCheckForGpeNameConflict 393 * 394 * PARAMETERS: Op - Current parse op 395 * 396 * RETURN: None 397 * 398 * DESCRIPTION: Check for a conflict between GPE names within this scope. 399 * Conflict means two GPE names with the same GPE number, but 400 * different types -- such as _L1C and _E1C. 401 * 402 ******************************************************************************/ 403 404 void 405 ApCheckForGpeNameConflict ( 406 ACPI_PARSE_OBJECT *Op) 407 { 408 ACPI_PARSE_OBJECT *NextOp; 409 UINT32 GpeNumber; 410 char Name[ACPI_NAME_SIZE + 1]; 411 char Target[ACPI_NAME_SIZE]; 412 413 414 /* Need a null-terminated string version of NameSeg */ 415 416 ACPI_MOVE_32_TO_32 (Name, &Op->Asl.NameSeg); 417 Name[ACPI_NAME_SIZE] = 0; 418 419 /* 420 * For a GPE method: 421 * 1st char must be underscore 422 * 2nd char must be L or E 423 * 3rd/4th chars must be a hex number 424 */ 425 if ((Name[0] != '_') || 426 ((Name[1] != 'L') && (Name[1] != 'E'))) 427 { 428 return; 429 } 430 431 /* Verify 3rd/4th chars are a valid hex value */ 432 433 GpeNumber = ACPI_STRTOUL (&Name[2], NULL, 16); 434 if (GpeNumber == ACPI_UINT32_MAX) 435 { 436 return; 437 } 438 439 /* 440 * We are now sure we have an _Lxx or _Exx. 441 * Create the target name that would cause collision (Flip E/L) 442 */ 443 ACPI_MOVE_32_TO_32 (Target, Name); 444 445 /* Inject opposite letter ("L" versus "E") */ 446 447 if (Name[1] == 'L') 448 { 449 Target[1] = 'E'; 450 } 451 else /* Name[1] == 'E' */ 452 { 453 Target[1] = 'L'; 454 } 455 456 /* Search all peers (objects within this scope) for target match */ 457 458 NextOp = Op->Asl.Next; 459 while (NextOp) 460 { 461 /* 462 * We mostly care about methods, but check Name() constructs also, 463 * even though they will get another error for not being a method. 464 * All GPE names must be defined as control methods. 465 */ 466 if ((NextOp->Asl.ParseOpcode == PARSEOP_METHOD) || 467 (NextOp->Asl.ParseOpcode == PARSEOP_NAME)) 468 { 469 if (ACPI_COMPARE_NAME (Target, NextOp->Asl.NameSeg)) 470 { 471 /* Found both _Exy and _Lxy in the same scope, error */ 472 473 AslError (ASL_ERROR, ASL_MSG_GPE_NAME_CONFLICT, NextOp, 474 Name); 475 return; 476 } 477 } 478 479 NextOp = NextOp->Asl.Next; 480 } 481 482 /* OK, no conflict found */ 483 484 return; 485 } 486 487 488 /******************************************************************************* 489 * 490 * FUNCTION: ApCheckRegMethod 491 * 492 * PARAMETERS: Op - Current parse op 493 * 494 * RETURN: None 495 * 496 * DESCRIPTION: Ensure that a _REG method has a corresponding Operation 497 * Region declaration within the same scope. Note: _REG is defined 498 * to have two arguments and must therefore be defined as a 499 * control method. 500 * 501 ******************************************************************************/ 502 503 void 504 ApCheckRegMethod ( 505 ACPI_PARSE_OBJECT *Op) 506 { 507 ACPI_PARSE_OBJECT *Next; 508 ACPI_PARSE_OBJECT *Parent; 509 510 511 /* We are only interested in _REG methods */ 512 513 if (!ACPI_COMPARE_NAME (METHOD_NAME__REG, &Op->Asl.NameSeg)) 514 { 515 return; 516 } 517 518 /* Get the start of the current scope */ 519 520 Parent = Op->Asl.Parent; 521 Next = Parent->Asl.Child; 522 523 /* Search entire scope for an operation region declaration */ 524 525 while (Next) 526 { 527 if (Next->Asl.ParseOpcode == PARSEOP_OPERATIONREGION) 528 { 529 return; /* Found region, OK */ 530 } 531 532 Next = Next->Asl.Next; 533 } 534 535 /* No region found, issue warning */ 536 537 AslError (ASL_WARNING, ASL_MSG_NO_REGION, Op, NULL); 538 } 539