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