1 /****************************************************************************** 2 * 3 * Module Name: psloop - Main AML parse loop 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, 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 * Parse the AML and build an operation tree as most interpreters, (such as 46 * Perl) do. Parsing is done by hand rather than with a YACC generated parser 47 * to tightly constrain stack and dynamic memory usage. Parsing is kept 48 * flexible and the code fairly compact by parsing based on a list of AML 49 * opcode templates in AmlOpInfo[]. 50 */ 51 52 #include <contrib/dev/acpica/include/acpi.h> 53 #include <contrib/dev/acpica/include/accommon.h> 54 #include <contrib/dev/acpica/include/acinterp.h> 55 #include <contrib/dev/acpica/include/acparser.h> 56 #include <contrib/dev/acpica/include/acdispat.h> 57 #include <contrib/dev/acpica/include/amlcode.h> 58 59 #define _COMPONENT ACPI_PARSER 60 ACPI_MODULE_NAME ("psloop") 61 62 63 /* Local prototypes */ 64 65 static ACPI_STATUS 66 AcpiPsGetArguments ( 67 ACPI_WALK_STATE *WalkState, 68 UINT8 *AmlOpStart, 69 ACPI_PARSE_OBJECT *Op); 70 71 static void 72 AcpiPsLinkModuleCode ( 73 ACPI_PARSE_OBJECT *ParentOp, 74 UINT8 *AmlStart, 75 UINT32 AmlLength, 76 ACPI_OWNER_ID OwnerId); 77 78 79 /******************************************************************************* 80 * 81 * FUNCTION: AcpiPsGetArguments 82 * 83 * PARAMETERS: WalkState - Current state 84 * AmlOpStart - Op start in AML 85 * Op - Current Op 86 * 87 * RETURN: Status 88 * 89 * DESCRIPTION: Get arguments for passed Op. 90 * 91 ******************************************************************************/ 92 93 static ACPI_STATUS 94 AcpiPsGetArguments ( 95 ACPI_WALK_STATE *WalkState, 96 UINT8 *AmlOpStart, 97 ACPI_PARSE_OBJECT *Op) 98 { 99 ACPI_STATUS Status = AE_OK; 100 ACPI_PARSE_OBJECT *Arg = NULL; 101 const ACPI_OPCODE_INFO *OpInfo; 102 103 104 ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState); 105 106 107 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 108 "Get arguments for opcode [%s]\n", Op->Common.AmlOpName)); 109 110 switch (Op->Common.AmlOpcode) 111 { 112 case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ 113 case AML_WORD_OP: /* AML_WORDDATA_ARG */ 114 case AML_DWORD_OP: /* AML_DWORDATA_ARG */ 115 case AML_QWORD_OP: /* AML_QWORDATA_ARG */ 116 case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ 117 118 /* Fill in constant or string argument directly */ 119 120 AcpiPsGetNextSimpleArg (&(WalkState->ParserState), 121 GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op); 122 break; 123 124 case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ 125 126 Status = AcpiPsGetNextNamepath (WalkState, 127 &(WalkState->ParserState), Op, ACPI_POSSIBLE_METHOD_CALL); 128 if (ACPI_FAILURE (Status)) 129 { 130 return_ACPI_STATUS (Status); 131 } 132 133 WalkState->ArgTypes = 0; 134 break; 135 136 default: 137 /* 138 * Op is not a constant or string, append each argument to the Op 139 */ 140 while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) && 141 !WalkState->ArgCount) 142 { 143 WalkState->Aml = WalkState->ParserState.Aml; 144 145 Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState), 146 GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg); 147 if (ACPI_FAILURE (Status)) 148 { 149 return_ACPI_STATUS (Status); 150 } 151 152 if (Arg) 153 { 154 AcpiPsAppendArg (Op, Arg); 155 } 156 157 INCREMENT_ARG_LIST (WalkState->ArgTypes); 158 } 159 160 161 /* 162 * Handle executable code at "module-level". This refers to 163 * executable opcodes that appear outside of any control method. 164 */ 165 if ((WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) && 166 ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0)) 167 { 168 /* 169 * We want to skip If/Else/While constructs during Pass1 because we 170 * want to actually conditionally execute the code during Pass2. 171 * 172 * Except for disassembly, where we always want to walk the 173 * If/Else/While packages 174 */ 175 switch (Op->Common.AmlOpcode) 176 { 177 case AML_IF_OP: 178 case AML_ELSE_OP: 179 case AML_WHILE_OP: 180 /* 181 * Currently supported module-level opcodes are: 182 * IF/ELSE/WHILE. These appear to be the most common, 183 * and easiest to support since they open an AML 184 * package. 185 */ 186 if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) 187 { 188 AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart, 189 (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart), 190 WalkState->OwnerId); 191 } 192 193 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 194 "Pass1: Skipping an If/Else/While body\n")); 195 196 /* Skip body of if/else/while in pass 1 */ 197 198 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; 199 WalkState->ArgCount = 0; 200 break; 201 202 default: 203 /* 204 * Check for an unsupported executable opcode at module 205 * level. We must be in PASS1, the parent must be a SCOPE, 206 * The opcode class must be EXECUTE, and the opcode must 207 * not be an argument to another opcode. 208 */ 209 if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) && 210 (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP)) 211 { 212 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 213 if ((OpInfo->Class == AML_CLASS_EXECUTE) && 214 (!Arg)) 215 { 216 ACPI_WARNING ((AE_INFO, 217 "Unsupported module-level executable opcode " 218 "0x%.2X at table offset 0x%.4X", 219 Op->Common.AmlOpcode, 220 (UINT32) (ACPI_PTR_DIFF (AmlOpStart, 221 WalkState->ParserState.AmlStart) + 222 sizeof (ACPI_TABLE_HEADER)))); 223 } 224 } 225 break; 226 } 227 } 228 229 /* Special processing for certain opcodes */ 230 231 switch (Op->Common.AmlOpcode) 232 { 233 case AML_METHOD_OP: 234 /* 235 * Skip parsing of control method because we don't have enough 236 * info in the first pass to parse it correctly. 237 * 238 * Save the length and address of the body 239 */ 240 Op->Named.Data = WalkState->ParserState.Aml; 241 Op->Named.Length = (UINT32) 242 (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml); 243 244 /* Skip body of method */ 245 246 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; 247 WalkState->ArgCount = 0; 248 break; 249 250 case AML_BUFFER_OP: 251 case AML_PACKAGE_OP: 252 case AML_VAR_PACKAGE_OP: 253 254 if ((Op->Common.Parent) && 255 (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && 256 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) 257 { 258 /* 259 * Skip parsing of Buffers and Packages because we don't have 260 * enough info in the first pass to parse them correctly. 261 */ 262 Op->Named.Data = AmlOpStart; 263 Op->Named.Length = (UINT32) 264 (WalkState->ParserState.PkgEnd - AmlOpStart); 265 266 /* Skip body */ 267 268 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; 269 WalkState->ArgCount = 0; 270 } 271 break; 272 273 case AML_WHILE_OP: 274 275 if (WalkState->ControlState) 276 { 277 WalkState->ControlState->Control.PackageEnd = 278 WalkState->ParserState.PkgEnd; 279 } 280 break; 281 282 default: 283 284 /* No action for all other opcodes */ 285 286 break; 287 } 288 289 break; 290 } 291 292 return_ACPI_STATUS (AE_OK); 293 } 294 295 296 /******************************************************************************* 297 * 298 * FUNCTION: AcpiPsLinkModuleCode 299 * 300 * PARAMETERS: ParentOp - Parent parser op 301 * AmlStart - Pointer to the AML 302 * AmlLength - Length of executable AML 303 * OwnerId - OwnerId of module level code 304 * 305 * RETURN: None. 306 * 307 * DESCRIPTION: Wrap the module-level code with a method object and link the 308 * object to the global list. Note, the mutex field of the method 309 * object is used to link multiple module-level code objects. 310 * 311 ******************************************************************************/ 312 313 static void 314 AcpiPsLinkModuleCode ( 315 ACPI_PARSE_OBJECT *ParentOp, 316 UINT8 *AmlStart, 317 UINT32 AmlLength, 318 ACPI_OWNER_ID OwnerId) 319 { 320 ACPI_OPERAND_OBJECT *Prev; 321 ACPI_OPERAND_OBJECT *Next; 322 ACPI_OPERAND_OBJECT *MethodObj; 323 ACPI_NAMESPACE_NODE *ParentNode; 324 325 326 ACPI_FUNCTION_TRACE (PsLinkModuleCode); 327 328 329 /* Get the tail of the list */ 330 331 Prev = Next = AcpiGbl_ModuleCodeList; 332 while (Next) 333 { 334 Prev = Next; 335 Next = Next->Method.Mutex; 336 } 337 338 /* 339 * Insert the module level code into the list. Merge it if it is 340 * adjacent to the previous element. 341 */ 342 if (!Prev || 343 ((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart)) 344 { 345 /* Create, initialize, and link a new temporary method object */ 346 347 MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); 348 if (!MethodObj) 349 { 350 return_VOID; 351 } 352 353 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 354 "Create/Link new code block: %p\n", MethodObj)); 355 356 if (ParentOp->Common.Node) 357 { 358 ParentNode = ParentOp->Common.Node; 359 } 360 else 361 { 362 ParentNode = AcpiGbl_RootNode; 363 } 364 365 MethodObj->Method.AmlStart = AmlStart; 366 MethodObj->Method.AmlLength = AmlLength; 367 MethodObj->Method.OwnerId = OwnerId; 368 MethodObj->Method.InfoFlags |= ACPI_METHOD_MODULE_LEVEL; 369 370 /* 371 * Save the parent node in NextObject. This is cheating, but we 372 * don't want to expand the method object. 373 */ 374 MethodObj->Method.NextObject = 375 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParentNode); 376 377 if (!Prev) 378 { 379 AcpiGbl_ModuleCodeList = MethodObj; 380 } 381 else 382 { 383 Prev->Method.Mutex = MethodObj; 384 } 385 } 386 else 387 { 388 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 389 "Appending to existing code block: %p\n", Prev)); 390 391 Prev->Method.AmlLength += AmlLength; 392 } 393 394 return_VOID; 395 } 396 397 /******************************************************************************* 398 * 399 * FUNCTION: AcpiPsParseLoop 400 * 401 * PARAMETERS: WalkState - Current state 402 * 403 * RETURN: Status 404 * 405 * DESCRIPTION: Parse AML (pointed to by the current parser state) and return 406 * a tree of ops. 407 * 408 ******************************************************************************/ 409 410 ACPI_STATUS 411 AcpiPsParseLoop ( 412 ACPI_WALK_STATE *WalkState) 413 { 414 ACPI_STATUS Status = AE_OK; 415 ACPI_PARSE_OBJECT *Op = NULL; /* current op */ 416 ACPI_PARSE_STATE *ParserState; 417 UINT8 *AmlOpStart = NULL; 418 419 420 ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState); 421 422 423 if (WalkState->DescendingCallback == NULL) 424 { 425 return_ACPI_STATUS (AE_BAD_PARAMETER); 426 } 427 428 ParserState = &WalkState->ParserState; 429 WalkState->ArgTypes = 0; 430 431 #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) 432 433 if (WalkState->WalkType & ACPI_WALK_METHOD_RESTART) 434 { 435 /* We are restarting a preempted control method */ 436 437 if (AcpiPsHasCompletedScope (ParserState)) 438 { 439 /* 440 * We must check if a predicate to an IF or WHILE statement 441 * was just completed 442 */ 443 if ((ParserState->Scope->ParseScope.Op) && 444 ((ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_IF_OP) || 445 (ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) && 446 (WalkState->ControlState) && 447 (WalkState->ControlState->Common.State == 448 ACPI_CONTROL_PREDICATE_EXECUTING)) 449 { 450 /* 451 * A predicate was just completed, get the value of the 452 * predicate and branch based on that value 453 */ 454 WalkState->Op = NULL; 455 Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE)); 456 if (ACPI_FAILURE (Status) && 457 ((Status & AE_CODE_MASK) != AE_CODE_CONTROL)) 458 { 459 if (Status == AE_AML_NO_RETURN_VALUE) 460 { 461 ACPI_EXCEPTION ((AE_INFO, Status, 462 "Invoked method did not return a value")); 463 } 464 465 ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed")); 466 return_ACPI_STATUS (Status); 467 } 468 469 Status = AcpiPsNextParseState (WalkState, Op, Status); 470 } 471 472 AcpiPsPopScope (ParserState, &Op, 473 &WalkState->ArgTypes, &WalkState->ArgCount); 474 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op)); 475 } 476 else if (WalkState->PrevOp) 477 { 478 /* We were in the middle of an op */ 479 480 Op = WalkState->PrevOp; 481 WalkState->ArgTypes = WalkState->PrevArgTypes; 482 } 483 } 484 #endif 485 486 /* Iterative parsing loop, while there is more AML to process: */ 487 488 while ((ParserState->Aml < ParserState->AmlEnd) || (Op)) 489 { 490 AmlOpStart = ParserState->Aml; 491 if (!Op) 492 { 493 Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op); 494 if (ACPI_FAILURE (Status)) 495 { 496 if (Status == AE_CTRL_PARSE_CONTINUE) 497 { 498 continue; 499 } 500 501 if (Status == AE_CTRL_PARSE_PENDING) 502 { 503 Status = AE_OK; 504 } 505 506 if (Status == AE_CTRL_TERMINATE) 507 { 508 return_ACPI_STATUS (Status); 509 } 510 511 Status = AcpiPsCompleteOp (WalkState, &Op, Status); 512 if (ACPI_FAILURE (Status)) 513 { 514 return_ACPI_STATUS (Status); 515 } 516 517 continue; 518 } 519 520 AcpiExStartTraceOpcode (Op, WalkState); 521 } 522 523 524 /* 525 * Start ArgCount at zero because we don't know if there are 526 * any args yet 527 */ 528 WalkState->ArgCount = 0; 529 530 /* Are there any arguments that must be processed? */ 531 532 if (WalkState->ArgTypes) 533 { 534 /* Get arguments */ 535 536 Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op); 537 if (ACPI_FAILURE (Status)) 538 { 539 Status = AcpiPsCompleteOp (WalkState, &Op, Status); 540 if (ACPI_FAILURE (Status)) 541 { 542 return_ACPI_STATUS (Status); 543 } 544 545 continue; 546 } 547 } 548 549 /* Check for arguments that need to be processed */ 550 551 if (WalkState->ArgCount) 552 { 553 /* 554 * There are arguments (complex ones), push Op and 555 * prepare for argument 556 */ 557 Status = AcpiPsPushScope (ParserState, Op, 558 WalkState->ArgTypes, WalkState->ArgCount); 559 if (ACPI_FAILURE (Status)) 560 { 561 Status = AcpiPsCompleteOp (WalkState, &Op, Status); 562 if (ACPI_FAILURE (Status)) 563 { 564 return_ACPI_STATUS (Status); 565 } 566 567 continue; 568 } 569 570 Op = NULL; 571 continue; 572 } 573 574 /* 575 * All arguments have been processed -- Op is complete, 576 * prepare for next 577 */ 578 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 579 if (WalkState->OpInfo->Flags & AML_NAMED) 580 { 581 if (Op->Common.AmlOpcode == AML_REGION_OP || 582 Op->Common.AmlOpcode == AML_DATA_REGION_OP) 583 { 584 /* 585 * Skip parsing of control method or opregion body, 586 * because we don't have enough info in the first pass 587 * to parse them correctly. 588 * 589 * Completed parsing an OpRegion declaration, we now 590 * know the length. 591 */ 592 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); 593 } 594 } 595 596 if (WalkState->OpInfo->Flags & AML_CREATE) 597 { 598 /* 599 * Backup to beginning of CreateXXXfield declaration (1 for 600 * Opcode) 601 * 602 * BodyLength is unknown until we parse the body 603 */ 604 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); 605 } 606 607 if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP) 608 { 609 /* 610 * Backup to beginning of BankField declaration 611 * 612 * BodyLength is unknown until we parse the body 613 */ 614 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); 615 } 616 617 /* This op complete, notify the dispatcher */ 618 619 if (WalkState->AscendingCallback != NULL) 620 { 621 WalkState->Op = Op; 622 WalkState->Opcode = Op->Common.AmlOpcode; 623 624 Status = WalkState->AscendingCallback (WalkState); 625 Status = AcpiPsNextParseState (WalkState, Op, Status); 626 if (Status == AE_CTRL_PENDING) 627 { 628 Status = AE_OK; 629 } 630 } 631 632 Status = AcpiPsCompleteOp (WalkState, &Op, Status); 633 if (ACPI_FAILURE (Status)) 634 { 635 return_ACPI_STATUS (Status); 636 } 637 638 } /* while ParserState->Aml */ 639 640 Status = AcpiPsCompleteFinalOp (WalkState, Op, Status); 641 return_ACPI_STATUS (Status); 642 } 643