1 2 /****************************************************************************** 3 * 4 * Module Name: aslfold - Constant folding 5 * 6 *****************************************************************************/ 7 8 /* 9 * Copyright (C) 2000 - 2012, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45 46 #include <contrib/dev/acpica/compiler/aslcompiler.h> 47 #include "aslcompiler.y.h" 48 #include <contrib/dev/acpica/include/amlcode.h> 49 50 #include <contrib/dev/acpica/include/acdispat.h> 51 #include <contrib/dev/acpica/include/acparser.h> 52 53 #define _COMPONENT ACPI_COMPILER 54 ACPI_MODULE_NAME ("aslfold") 55 56 /* Local prototypes */ 57 58 static ACPI_STATUS 59 OpcAmlEvaluationWalk1 ( 60 ACPI_PARSE_OBJECT *Op, 61 UINT32 Level, 62 void *Context); 63 64 static ACPI_STATUS 65 OpcAmlEvaluationWalk2 ( 66 ACPI_PARSE_OBJECT *Op, 67 UINT32 Level, 68 void *Context); 69 70 static ACPI_STATUS 71 OpcAmlCheckForConstant ( 72 ACPI_PARSE_OBJECT *Op, 73 UINT32 Level, 74 void *Context); 75 76 static void 77 OpcUpdateIntegerNode ( 78 ACPI_PARSE_OBJECT *Op, 79 UINT64 Value); 80 81 82 /******************************************************************************* 83 * 84 * FUNCTION: OpcAmlEvaluationWalk1 85 * 86 * PARAMETERS: ASL_WALK_CALLBACK 87 * 88 * RETURN: Status 89 * 90 * DESCRIPTION: Descending callback for AML execution of constant subtrees 91 * 92 ******************************************************************************/ 93 94 static ACPI_STATUS 95 OpcAmlEvaluationWalk1 ( 96 ACPI_PARSE_OBJECT *Op, 97 UINT32 Level, 98 void *Context) 99 { 100 ACPI_WALK_STATE *WalkState = Context; 101 ACPI_STATUS Status; 102 ACPI_PARSE_OBJECT *OutOp; 103 104 105 WalkState->Op = Op; 106 WalkState->Opcode = Op->Common.AmlOpcode; 107 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 108 109 /* Copy child pointer to Arg for compatibility with Interpreter */ 110 111 if (Op->Asl.Child) 112 { 113 Op->Common.Value.Arg = Op->Asl.Child; 114 } 115 116 /* Call AML dispatcher */ 117 118 Status = AcpiDsExecBeginOp (WalkState, &OutOp); 119 if (ACPI_FAILURE (Status)) 120 { 121 AcpiOsPrintf ("Constant interpretation failed - %s\n", 122 AcpiFormatException (Status)); 123 } 124 125 return (Status); 126 } 127 128 129 /******************************************************************************* 130 * 131 * FUNCTION: OpcAmlEvaluationWalk2 132 * 133 * PARAMETERS: ASL_WALK_CALLBACK 134 * 135 * RETURN: Status 136 * 137 * DESCRIPTION: Ascending callback for AML execution of constant subtrees 138 * 139 ******************************************************************************/ 140 141 static ACPI_STATUS 142 OpcAmlEvaluationWalk2 ( 143 ACPI_PARSE_OBJECT *Op, 144 UINT32 Level, 145 void *Context) 146 { 147 ACPI_WALK_STATE *WalkState = Context; 148 ACPI_STATUS Status; 149 150 151 WalkState->Op = Op; 152 WalkState->Opcode = Op->Common.AmlOpcode; 153 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 154 155 /* Copy child pointer to Arg for compatibility with Interpreter */ 156 157 if (Op->Asl.Child) 158 { 159 Op->Common.Value.Arg = Op->Asl.Child; 160 } 161 162 /* Call AML dispatcher */ 163 164 Status = AcpiDsExecEndOp (WalkState); 165 if (ACPI_FAILURE (Status)) 166 { 167 AcpiOsPrintf ("Constant interpretation failed - %s\n", 168 AcpiFormatException (Status)); 169 } 170 171 return (Status); 172 } 173 174 175 /******************************************************************************* 176 * 177 * FUNCTION: OpcAmlCheckForConstant 178 * 179 * PARAMETERS: ASL_WALK_CALLBACK 180 * 181 * RETURN: Status 182 * 183 * DESCRIPTION: Check one Op for a type 3/4/5 AML opcode 184 * 185 ******************************************************************************/ 186 187 static ACPI_STATUS 188 OpcAmlCheckForConstant ( 189 ACPI_PARSE_OBJECT *Op, 190 UINT32 Level, 191 void *Context) 192 { 193 ACPI_WALK_STATE *WalkState = Context; 194 195 196 WalkState->Op = Op; 197 WalkState->Opcode = Op->Common.AmlOpcode; 198 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 199 200 DbgPrint (ASL_PARSE_OUTPUT, "[%.4d] Opcode: %12.12s ", 201 Op->Asl.LogicalLineNumber, Op->Asl.ParseOpName); 202 203 /* 204 * These opcodes do not appear in the OpcodeInfo table, but 205 * they represent constants, so abort the constant walk now. 206 */ 207 if ((WalkState->Opcode == AML_RAW_DATA_BYTE) || 208 (WalkState->Opcode == AML_RAW_DATA_WORD) || 209 (WalkState->Opcode == AML_RAW_DATA_DWORD) || 210 (WalkState->Opcode == AML_RAW_DATA_QWORD)) 211 { 212 WalkState->WalkType = ACPI_WALK_CONST_OPTIONAL; 213 return (AE_TYPE); 214 } 215 216 if (!(WalkState->OpInfo->Flags & AML_CONSTANT)) 217 { 218 /* The opcode is not a Type 3/4/5 opcode */ 219 220 if (Op->Asl.CompileFlags & NODE_IS_TARGET) 221 { 222 DbgPrint (ASL_PARSE_OUTPUT, 223 "**** Valid Target, cannot reduce ****\n"); 224 } 225 else 226 { 227 DbgPrint (ASL_PARSE_OUTPUT, 228 "**** Not a Type 3/4/5 opcode ****\n"); 229 } 230 231 if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL) 232 { 233 /* 234 * We are looking at at normal expression to see if it can be 235 * reduced. It can't. No error 236 */ 237 return (AE_TYPE); 238 } 239 240 /* 241 * This is an expression that MUST reduce to a constant, and it 242 * can't be reduced. This is an error 243 */ 244 if (Op->Asl.CompileFlags & NODE_IS_TARGET) 245 { 246 AslError (ASL_ERROR, ASL_MSG_INVALID_TARGET, Op, 247 Op->Asl.ParseOpName); 248 } 249 else 250 { 251 AslError (ASL_ERROR, ASL_MSG_INVALID_CONSTANT_OP, Op, 252 Op->Asl.ParseOpName); 253 } 254 255 return (AE_TYPE); 256 } 257 258 /* Debug output */ 259 260 DbgPrint (ASL_PARSE_OUTPUT, "TYPE_345"); 261 262 if (Op->Asl.CompileFlags & NODE_IS_TARGET) 263 { 264 DbgPrint (ASL_PARSE_OUTPUT, " TARGET"); 265 } 266 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG) 267 { 268 DbgPrint (ASL_PARSE_OUTPUT, " TERMARG"); 269 } 270 271 DbgPrint (ASL_PARSE_OUTPUT, "\n"); 272 return (AE_OK); 273 } 274 275 276 /******************************************************************************* 277 * 278 * FUNCTION: OpcAmlConstantWalk 279 * 280 * PARAMETERS: ASL_WALK_CALLBACK 281 * 282 * RETURN: Status 283 * 284 * DESCRIPTION: Reduce an Op and its subtree to a constant if possible 285 * 286 ******************************************************************************/ 287 288 ACPI_STATUS 289 OpcAmlConstantWalk ( 290 ACPI_PARSE_OBJECT *Op, 291 UINT32 Level, 292 void *Context) 293 { 294 ACPI_WALK_STATE *WalkState; 295 ACPI_STATUS Status = AE_OK; 296 ACPI_OPERAND_OBJECT *ObjDesc; 297 ACPI_PARSE_OBJECT *RootOp; 298 ACPI_PARSE_OBJECT *OriginalParentOp; 299 UINT8 WalkType; 300 301 302 /* 303 * Only interested in subtrees that could possibly contain 304 * expressions that can be evaluated at this time 305 */ 306 if ((!(Op->Asl.CompileFlags & NODE_COMPILE_TIME_CONST)) || 307 (Op->Asl.CompileFlags & NODE_IS_TARGET)) 308 { 309 return (AE_OK); 310 } 311 312 /* Set the walk type based on the reduction used for this op */ 313 314 if (Op->Asl.CompileFlags & NODE_IS_TERM_ARG) 315 { 316 /* Op is a TermArg, constant folding is merely optional */ 317 318 if (!Gbl_FoldConstants) 319 { 320 return (AE_CTRL_DEPTH); 321 } 322 323 WalkType = ACPI_WALK_CONST_OPTIONAL; 324 } 325 else 326 { 327 /* Op is a DataObject, the expression MUST reduced to a constant */ 328 329 WalkType = ACPI_WALK_CONST_REQUIRED; 330 } 331 332 /* Create a new walk state */ 333 334 WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); 335 if (!WalkState) 336 { 337 return AE_NO_MEMORY; 338 } 339 340 WalkState->NextOp = NULL; 341 WalkState->Params = NULL; 342 WalkState->WalkType = WalkType; 343 WalkState->CallerReturnDesc = &ObjDesc; 344 345 /* 346 * Examine the entire subtree -- all nodes must be constants 347 * or type 3/4/5 opcodes 348 */ 349 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_DOWNWARD, 350 OpcAmlCheckForConstant, NULL, WalkState); 351 352 /* 353 * Did we find an entire subtree that contains all constants and type 3/4/5 354 * opcodes? (Only AE_OK or AE_TYPE returned from above) 355 */ 356 if (Status == AE_TYPE) 357 { 358 /* Subtree cannot be reduced to a constant */ 359 360 if (WalkState->WalkType == ACPI_WALK_CONST_OPTIONAL) 361 { 362 AcpiDsDeleteWalkState (WalkState); 363 return (AE_OK); 364 } 365 366 /* Don't descend any further, and use a default "constant" value */ 367 368 Status = AE_CTRL_DEPTH; 369 } 370 else 371 { 372 /* Subtree can be reduced */ 373 374 /* Allocate a new temporary root for this subtree */ 375 376 RootOp = TrAllocateNode (PARSEOP_INTEGER); 377 if (!RootOp) 378 { 379 return (AE_NO_MEMORY); 380 } 381 382 RootOp->Common.AmlOpcode = AML_INT_EVAL_SUBTREE_OP; 383 384 OriginalParentOp = Op->Common.Parent; 385 Op->Common.Parent = RootOp; 386 387 /* Hand off the subtree to the AML interpreter */ 388 389 Status = TrWalkParseTree (Op, ASL_WALK_VISIT_TWICE, 390 OpcAmlEvaluationWalk1, OpcAmlEvaluationWalk2, WalkState); 391 Op->Common.Parent = OriginalParentOp; 392 393 /* TBD: we really *should* release the RootOp node */ 394 395 if (ACPI_SUCCESS (Status)) 396 { 397 TotalFolds++; 398 399 /* Get the final result */ 400 401 Status = AcpiDsResultPop (&ObjDesc, WalkState); 402 } 403 404 /* Check for error from the ACPICA core */ 405 406 if (ACPI_FAILURE (Status)) 407 { 408 AslCoreSubsystemError (Op, Status, 409 "Failure during constant evaluation", FALSE); 410 } 411 } 412 413 if (ACPI_FAILURE (Status)) 414 { 415 /* We could not resolve the subtree for some reason */ 416 417 AslError (ASL_ERROR, ASL_MSG_CONSTANT_EVALUATION, Op, 418 Op->Asl.ParseOpName); 419 420 /* Set the subtree value to ZERO anyway. Eliminates further errors */ 421 422 OpcUpdateIntegerNode (Op, 0); 423 } 424 else 425 { 426 AslError (ASL_OPTIMIZATION, ASL_MSG_CONSTANT_FOLDED, Op, 427 Op->Asl.ParseOpName); 428 429 /* 430 * Because we know we executed type 3/4/5 opcodes above, we know that 431 * the result must be either an Integer, String, or Buffer. 432 */ 433 switch (ObjDesc->Common.Type) 434 { 435 case ACPI_TYPE_INTEGER: 436 437 OpcUpdateIntegerNode (Op, ObjDesc->Integer.Value); 438 439 DbgPrint (ASL_PARSE_OUTPUT, 440 "Constant expression reduced to (%s) %8.8X%8.8X\n", 441 Op->Asl.ParseOpName, 442 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer)); 443 break; 444 445 446 case ACPI_TYPE_STRING: 447 448 Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; 449 Op->Common.AmlOpcode = AML_STRING_OP; 450 Op->Asl.AmlLength = ACPI_STRLEN (ObjDesc->String.Pointer) + 1; 451 Op->Common.Value.String = ObjDesc->String.Pointer; 452 453 DbgPrint (ASL_PARSE_OUTPUT, 454 "Constant expression reduced to (STRING) %s\n", 455 Op->Common.Value.String); 456 457 break; 458 459 460 case ACPI_TYPE_BUFFER: 461 462 Op->Asl.ParseOpcode = PARSEOP_BUFFER; 463 Op->Common.AmlOpcode = AML_BUFFER_OP; 464 Op->Asl.CompileFlags = NODE_AML_PACKAGE; 465 UtSetParseOpName (Op); 466 467 /* Child node is the buffer length */ 468 469 RootOp = TrAllocateNode (PARSEOP_INTEGER); 470 471 RootOp->Asl.AmlOpcode = AML_DWORD_OP; 472 RootOp->Asl.Value.Integer = ObjDesc->Buffer.Length; 473 RootOp->Asl.Parent = Op; 474 475 (void) OpcSetOptimalIntegerSize (RootOp); 476 477 Op->Asl.Child = RootOp; 478 Op = RootOp; 479 UtSetParseOpName (Op); 480 481 /* Peer to the child is the raw buffer data */ 482 483 RootOp = TrAllocateNode (PARSEOP_RAW_DATA); 484 RootOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER; 485 RootOp->Asl.AmlLength = ObjDesc->Buffer.Length; 486 RootOp->Asl.Value.String = (char *) ObjDesc->Buffer.Pointer; 487 RootOp->Asl.Parent = Op->Asl.Parent; 488 489 Op->Asl.Next = RootOp; 490 Op = RootOp; 491 492 DbgPrint (ASL_PARSE_OUTPUT, 493 "Constant expression reduced to (BUFFER) length %X\n", 494 ObjDesc->Buffer.Length); 495 break; 496 497 498 default: 499 printf ("Unsupported return type: %s\n", 500 AcpiUtGetObjectTypeName (ObjDesc)); 501 break; 502 } 503 } 504 505 UtSetParseOpName (Op); 506 Op->Asl.Child = NULL; 507 508 AcpiDsDeleteWalkState (WalkState); 509 return (AE_CTRL_DEPTH); 510 } 511 512 513 /******************************************************************************* 514 * 515 * FUNCTION: OpcUpdateIntegerNode 516 * 517 * PARAMETERS: Op - Current parse object 518 * 519 * RETURN: None 520 * 521 * DESCRIPTION: Update node to the correct integer type. 522 * 523 ******************************************************************************/ 524 525 static void 526 OpcUpdateIntegerNode ( 527 ACPI_PARSE_OBJECT *Op, 528 UINT64 Value) 529 { 530 531 Op->Common.Value.Integer = Value; 532 533 /* 534 * The AmlLength is used by the parser to indicate a constant, 535 * (if non-zero). Length is either (1/2/4/8) 536 */ 537 switch (Op->Asl.AmlLength) 538 { 539 case 1: 540 TrUpdateNode (PARSEOP_BYTECONST, Op); 541 Op->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 542 break; 543 544 case 2: 545 TrUpdateNode (PARSEOP_WORDCONST, Op); 546 Op->Asl.AmlOpcode = AML_RAW_DATA_WORD; 547 break; 548 549 case 4: 550 TrUpdateNode (PARSEOP_DWORDCONST, Op); 551 Op->Asl.AmlOpcode = AML_RAW_DATA_DWORD; 552 break; 553 554 case 8: 555 TrUpdateNode (PARSEOP_QWORDCONST, Op); 556 Op->Asl.AmlOpcode = AML_RAW_DATA_QWORD; 557 break; 558 559 case 0: 560 default: 561 OpcSetOptimalIntegerSize (Op); 562 TrUpdateNode (PARSEOP_INTEGER, Op); 563 break; 564 } 565 566 Op->Asl.AmlLength = 0; 567 } 568