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