1 /****************************************************************************** 2 * 3 * Module Name: asltree - Parse tree management 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2021, 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 MERCHANTABILITY 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 "aslcompiler.h" 45 #include "aslcompiler.y.h" 46 #include "acapps.h" 47 48 #define _COMPONENT ACPI_COMPILER 49 ACPI_MODULE_NAME ("asltree") 50 51 52 /******************************************************************************* 53 * 54 * FUNCTION: TrSetOpIntegerValue 55 * 56 * PARAMETERS: ParseOpcode - New opcode to be assigned to the op 57 * Op - An existing parse op 58 * 59 * RETURN: The updated op 60 * 61 * DESCRIPTION: Used to set the integer value of a op, 62 * usually to a specific size (8, 16, 32, or 64 bits) 63 * 64 ******************************************************************************/ 65 66 ACPI_PARSE_OBJECT * 67 TrSetOpIntegerValue ( 68 UINT32 ParseOpcode, 69 ACPI_PARSE_OBJECT *Op) 70 { 71 72 if (!Op) 73 { 74 return (NULL); 75 } 76 77 DbgPrint (ASL_PARSE_OUTPUT, 78 "\nUpdateOp: Old - %s, New - %s\n", 79 UtGetOpName (Op->Asl.ParseOpcode), 80 UtGetOpName (ParseOpcode)); 81 82 /* Assign new opcode and name */ 83 84 if (Op->Asl.ParseOpcode == PARSEOP_ONES) 85 { 86 switch (ParseOpcode) 87 { 88 case PARSEOP_BYTECONST: 89 90 Op->Asl.Value.Integer = ACPI_UINT8_MAX; 91 break; 92 93 case PARSEOP_WORDCONST: 94 95 Op->Asl.Value.Integer = ACPI_UINT16_MAX; 96 break; 97 98 case PARSEOP_DWORDCONST: 99 100 Op->Asl.Value.Integer = ACPI_UINT32_MAX; 101 break; 102 103 /* Don't need to do the QWORD case */ 104 105 default: 106 107 /* Don't care about others */ 108 break; 109 } 110 } 111 112 Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 113 UtSetParseOpName (Op); 114 115 /* 116 * For the BYTE, WORD, and DWORD constants, make sure that the integer 117 * that was passed in will actually fit into the data type 118 */ 119 switch (ParseOpcode) 120 { 121 case PARSEOP_BYTECONST: 122 123 UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX); 124 Op->Asl.Value.Integer &= ACPI_UINT8_MAX; 125 break; 126 127 case PARSEOP_WORDCONST: 128 129 UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX); 130 Op->Asl.Value.Integer &= ACPI_UINT16_MAX; 131 break; 132 133 case PARSEOP_DWORDCONST: 134 135 UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX); 136 Op->Asl.Value.Integer &= ACPI_UINT32_MAX; 137 break; 138 139 default: 140 141 /* Don't care about others, don't need to check QWORD */ 142 143 break; 144 } 145 146 /* Converter: if this is a method invocation, turn off capture comments */ 147 148 if (AcpiGbl_CaptureComments && 149 (ParseOpcode == PARSEOP_METHODCALL)) 150 { 151 AslGbl_CommentState.CaptureComments = FALSE; 152 } 153 154 return (Op); 155 } 156 157 158 /******************************************************************************* 159 * 160 * FUNCTION: TrSetOpFlags 161 * 162 * PARAMETERS: Op - An existing parse op 163 * Flags - New flags word 164 * 165 * RETURN: The updated parser op 166 * 167 * DESCRIPTION: Set bits in the op flags word. Will not clear bits, only set 168 * 169 ******************************************************************************/ 170 171 ACPI_PARSE_OBJECT * 172 TrSetOpFlags ( 173 ACPI_PARSE_OBJECT *Op, 174 UINT32 Flags) 175 { 176 177 if (!Op) 178 { 179 return (NULL); 180 } 181 182 DbgPrint (ASL_PARSE_OUTPUT, 183 "\nSetOpFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags); 184 185 TrPrintOpFlags (Flags, ASL_PARSE_OUTPUT); 186 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 187 188 Op->Asl.CompileFlags |= Flags; 189 return (Op); 190 } 191 192 193 /******************************************************************************* 194 * 195 * FUNCTION: TrSetOpAmlLength 196 * 197 * PARAMETERS: Op - An existing parse op 198 * Length - AML Length 199 * 200 * RETURN: The updated parser op 201 * 202 * DESCRIPTION: Set the AML Length in a op. Used by the parser to indicate 203 * the presence of a op that must be reduced to a fixed length 204 * constant. 205 * 206 ******************************************************************************/ 207 208 ACPI_PARSE_OBJECT * 209 TrSetOpAmlLength ( 210 ACPI_PARSE_OBJECT *Op, 211 UINT32 Length) 212 { 213 214 DbgPrint (ASL_PARSE_OUTPUT, 215 "\nSetOpAmlLength: Op %p, %8.8X\n", Op, Length); 216 217 if (!Op) 218 { 219 return (NULL); 220 } 221 222 Op->Asl.AmlLength = Length; 223 return (Op); 224 } 225 226 227 /******************************************************************************* 228 * 229 * FUNCTION: TrSetOpParent 230 * 231 * PARAMETERS: Op - To be set to new parent 232 * ParentOp - The parent 233 * 234 * RETURN: None, sets Op parent directly 235 * 236 * DESCRIPTION: Change the parent of a parse op. 237 * 238 ******************************************************************************/ 239 240 void 241 TrSetOpParent ( 242 ACPI_PARSE_OBJECT *Op, 243 ACPI_PARSE_OBJECT *ParentOp) 244 { 245 246 Op->Asl.Parent = ParentOp; 247 } 248 249 250 /******************************************************************************* 251 * 252 * FUNCTION: TrSetOpCurrentFilename 253 * 254 * PARAMETERS: Op - An existing parse op 255 * 256 * RETURN: None 257 * 258 * DESCRIPTION: Save the include file filename. Used for debug output only. 259 * 260 ******************************************************************************/ 261 262 void 263 TrSetOpCurrentFilename ( 264 ACPI_PARSE_OBJECT *Op) 265 { 266 267 Op->Asl.Filename = AslGbl_PreviousIncludeFilename; 268 } 269 270 271 /******************************************************************************* 272 * 273 * FUNCTION: TrSetOpIntegerWidth 274 * 275 * PARAMETERS: Op - An existing parse op 276 * 277 * RETURN: None 278 * 279 * DESCRIPTION: 280 * 281 ******************************************************************************/ 282 283 void 284 TrSetOpIntegerWidth ( 285 ACPI_PARSE_OBJECT *TableSignatureOp, 286 ACPI_PARSE_OBJECT *RevisionOp) 287 { 288 289 /* TBD: Check table sig? (DSDT vs. SSDT) */ 290 291 /* Handle command-line version override */ 292 293 if (AslGbl_RevisionOverride) 294 { 295 AcpiUtSetIntegerWidth (AslGbl_RevisionOverride); 296 } 297 else 298 { 299 AcpiUtSetIntegerWidth ((UINT8) RevisionOp->Asl.Value.Integer); 300 } 301 } 302 303 304 /******************************************************************************* 305 * 306 * FUNCTION: TrSetOpEndLineNumber 307 * 308 * PARAMETERS: Op - An existing parse op 309 * 310 * RETURN: None. 311 * 312 * DESCRIPTION: Set the ending line numbers (file line and logical line) of a 313 * parse op to the current line numbers. 314 * 315 ******************************************************************************/ 316 317 void 318 TrSetOpEndLineNumber ( 319 ACPI_PARSE_OBJECT *Op) 320 { 321 322 /* If the end line # is already set, just return */ 323 324 if (Op->Asl.EndLine) 325 { 326 return; 327 } 328 329 Op->Asl.EndLine = AslGbl_CurrentLineNumber; 330 Op->Asl.EndLogicalLine = AslGbl_LogicalLineNumber; 331 } 332 333 334 /******************************************************************************* 335 * 336 * FUNCTION: TrLinkOpChildren 337 * 338 * PARAMETERS: Op - An existing parse op 339 * NumChildren - Number of children to follow 340 * ... - A list of child ops to link to the new 341 * op. NumChildren long. 342 * 343 * RETURN: The updated (linked) op 344 * 345 * DESCRIPTION: Link a group of ops to an existing parse op 346 * 347 ******************************************************************************/ 348 349 ACPI_PARSE_OBJECT * 350 TrLinkOpChildren ( 351 ACPI_PARSE_OBJECT *Op, 352 UINT32 NumChildren, 353 ...) 354 { 355 ACPI_PARSE_OBJECT *Child; 356 ACPI_PARSE_OBJECT *PrevChild; 357 ACPI_PARSE_OBJECT *LastSibling; 358 va_list ap; 359 UINT32 i; 360 BOOLEAN FirstChild; 361 362 363 va_start (ap, NumChildren); 364 365 TrSetOpEndLineNumber (Op); 366 367 DbgPrint (ASL_PARSE_OUTPUT, 368 "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ", 369 Op->Asl.LineNumber, Op->Asl.EndLine, 370 Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode)); 371 372 switch (Op->Asl.ParseOpcode) 373 { 374 case PARSEOP_ASL_CODE: 375 376 if (!AslGbl_ParseTreeRoot) 377 { 378 DbgPrint (ASL_PARSE_OUTPUT, "Creating first Definition Block\n"); 379 AslGbl_ParseTreeRoot = Op; 380 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 381 } 382 else 383 { 384 DbgPrint (ASL_PARSE_OUTPUT, "Creating subsequent Definition Block\n"); 385 Op = AslGbl_ParseTreeRoot; 386 } 387 388 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); 389 break; 390 391 case PARSEOP_DEFINITION_BLOCK: 392 393 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 394 break; 395 396 case PARSEOP_OPERATIONREGION: 397 398 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 399 break; 400 401 case PARSEOP_OR: 402 403 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 404 break; 405 406 default: 407 408 /* Nothing to do for other opcodes */ 409 410 break; 411 } 412 413 /* The following is for capturing comments */ 414 415 if (AcpiGbl_CaptureComments) 416 { 417 /* 418 * If there are "regular comments" detected at this point, 419 * then is an endBlk comment. Categorize it as so and distribute 420 * all regular comments to this parse op. 421 */ 422 if (AslGbl_CommentListHead) 423 { 424 Op->Asl.EndBlkComment = AslGbl_CommentListHead; 425 CvDbgPrint ("EndBlk Comment for %s: %s", 426 Op->Asl.ParseOpName, AslGbl_CommentListHead->Comment); 427 AslGbl_CommentListHead = NULL; 428 AslGbl_CommentListTail = NULL; 429 } 430 } 431 432 /* Link the new op to it's children */ 433 434 PrevChild = NULL; 435 FirstChild = TRUE; 436 for (i = 0; i < NumChildren; i++) 437 { 438 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 439 440 if ((Child == PrevChild) && (Child != NULL)) 441 { 442 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child, 443 "Child op list invalid"); 444 va_end(ap); 445 return (Op); 446 } 447 448 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 449 450 /* 451 * If child is NULL, this means that an optional argument 452 * was omitted. We must create a placeholder with a special 453 * opcode (DEFAULT_ARG) so that the code generator will know 454 * that it must emit the correct default for this argument 455 */ 456 if (!Child) 457 { 458 Child = TrAllocateOp (PARSEOP_DEFAULT_ARG); 459 } 460 461 /* Link first child to parent */ 462 463 if (FirstChild) 464 { 465 FirstChild = FALSE; 466 467 /* 468 * In the case that multiple definition blocks are being compiled, 469 * append the definition block to the end of the child list as the 470 * last sibling. This is done to facilitate namespace cross- 471 * reference between multiple definition blocks. 472 */ 473 if (Op->Asl.Child && 474 (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)) 475 { 476 LastSibling = Op->Asl.Child; 477 while (LastSibling->Asl.Next) 478 { 479 LastSibling = LastSibling->Asl.Next; 480 } 481 LastSibling->Asl.Next = Child; 482 } 483 else 484 { 485 Op->Asl.Child = Child; 486 } 487 } 488 489 /* Point all children to parent */ 490 491 Child->Asl.Parent = Op; 492 493 /* Link children in a peer list */ 494 495 if (PrevChild) 496 { 497 PrevChild->Asl.Next = Child; 498 } 499 500 /* 501 * This child might be a list, point all ops in the list 502 * to the same parent 503 */ 504 while (Child->Asl.Next) 505 { 506 Child = Child->Asl.Next; 507 Child->Asl.Parent = Op; 508 } 509 510 PrevChild = Child; 511 } 512 513 va_end(ap); 514 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 515 516 if (AcpiGbl_CaptureComments) 517 { 518 AslGbl_CommentState.LatestParseOp = Op; 519 CvDbgPrint ("TrLinkOpChildren=====Set latest parse op to this op.\n"); 520 } 521 522 return (Op); 523 } 524 525 526 /******************************************************************************* 527 * 528 * FUNCTION: TrLinkPeerOp 529 * 530 * PARAMETERS: Op1 - First peer 531 * Op2 - Second peer 532 * 533 * RETURN: Op1 or the non-null op. 534 * 535 * DESCRIPTION: Link two ops as peers. Handles cases where one peer is null. 536 * 537 ******************************************************************************/ 538 539 ACPI_PARSE_OBJECT * 540 TrLinkPeerOp ( 541 ACPI_PARSE_OBJECT *Op1, 542 ACPI_PARSE_OBJECT *Op2) 543 { 544 ACPI_PARSE_OBJECT *Next; 545 546 547 DbgPrint (ASL_PARSE_OUTPUT, 548 "\nLinkPeerOp: 1=%p (%s), 2=%p (%s)\n", 549 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL, 550 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL); 551 552 553 if ((!Op1) && (!Op2)) 554 { 555 DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null ops!\n"); 556 return (Op1); 557 } 558 559 /* If one of the ops is null, just return the non-null op */ 560 561 if (!Op2) 562 { 563 return (Op1); 564 } 565 566 if (!Op1) 567 { 568 return (Op2); 569 } 570 571 if (Op1 == Op2) 572 { 573 DbgPrint (ASL_DEBUG_OUTPUT, 574 "\n************* Internal error, linking op to itself %p\n", 575 Op1); 576 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1, 577 "Linking op to itself"); 578 return (Op1); 579 } 580 581 Op1->Asl.Parent = Op2->Asl.Parent; 582 583 /* 584 * Op 1 may already have a peer list (such as an IF/ELSE pair), 585 * so we must walk to the end of the list and attach the new 586 * peer at the end 587 */ 588 Next = Op1; 589 while (Next->Asl.Next) 590 { 591 Next = Next->Asl.Next; 592 } 593 594 Next->Asl.Next = Op2; 595 return (Op1); 596 } 597 598 599 /******************************************************************************* 600 * 601 * FUNCTION: TrLinkPeerOps 602 * 603 * PARAMETERS: NumPeers - The number of ops in the list to follow 604 * ... - A list of ops to link together as peers 605 * 606 * RETURN: The first op in the list (head of the peer list) 607 * 608 * DESCRIPTION: Link together an arbitrary number of peer ops. 609 * 610 ******************************************************************************/ 611 612 ACPI_PARSE_OBJECT * 613 TrLinkPeerOps ( 614 UINT32 NumPeers, 615 ...) 616 { 617 ACPI_PARSE_OBJECT *This; 618 ACPI_PARSE_OBJECT *Next; 619 va_list ap; 620 UINT32 i; 621 ACPI_PARSE_OBJECT *Start; 622 623 624 DbgPrint (ASL_PARSE_OUTPUT, 625 "\nLinkPeerOps: (%u) ", NumPeers); 626 627 va_start (ap, NumPeers); 628 This = va_arg (ap, ACPI_PARSE_OBJECT *); 629 Start = This; 630 631 /* 632 * Link all peers 633 */ 634 for (i = 0; i < (NumPeers -1); i++) 635 { 636 DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This); 637 638 while (This->Asl.Next) 639 { 640 This = This->Asl.Next; 641 } 642 643 /* Get another peer op */ 644 645 Next = va_arg (ap, ACPI_PARSE_OBJECT *); 646 if (!Next) 647 { 648 Next = TrAllocateOp (PARSEOP_DEFAULT_ARG); 649 } 650 651 /* link new op to the current op */ 652 653 This->Asl.Next = Next; 654 This = Next; 655 } 656 657 va_end (ap); 658 DbgPrint (ASL_PARSE_OUTPUT,"\n"); 659 return (Start); 660 } 661 662 663 /******************************************************************************* 664 * 665 * FUNCTION: TrLinkChildOp 666 * 667 * PARAMETERS: Op1 - Parent op 668 * Op2 - Op to become a child 669 * 670 * RETURN: The parent op 671 * 672 * DESCRIPTION: Link two ops together as a parent and child 673 * 674 ******************************************************************************/ 675 676 ACPI_PARSE_OBJECT * 677 TrLinkChildOp ( 678 ACPI_PARSE_OBJECT *Op1, 679 ACPI_PARSE_OBJECT *Op2) 680 { 681 ACPI_PARSE_OBJECT *Next; 682 683 684 DbgPrint (ASL_PARSE_OUTPUT, 685 "\nLinkChildOp: Parent=%p (%s), Child=%p (%s)\n", 686 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL, 687 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL); 688 689 /* 690 * Converter: if TrLinkChildOp is called to link a method call, 691 * turn on capture comments as it signifies that we are done parsing 692 * a method call. 693 */ 694 if (AcpiGbl_CaptureComments && Op1) 695 { 696 if (Op1->Asl.ParseOpcode == PARSEOP_METHODCALL) 697 { 698 AslGbl_CommentState.CaptureComments = TRUE; 699 } 700 AslGbl_CommentState.LatestParseOp = Op1; 701 } 702 703 if (!Op1 || !Op2) 704 { 705 return (Op1); 706 } 707 708 Op1->Asl.Child = Op2; 709 710 /* Set the child and all peers of the child to point to the parent */ 711 712 Next = Op2; 713 while (Next) 714 { 715 Next->Asl.Parent = Op1; 716 Next = Next->Asl.Next; 717 } 718 719 return (Op1); 720 } 721 722 723 /******************************************************************************* 724 * 725 * FUNCTION: TrWalkParseTree 726 * 727 * PARAMETERS: Op - Walk starting point 728 * Visitation - Type of walk 729 * DescendingCallback - Called during tree descent 730 * AscendingCallback - Called during tree ascent 731 * Context - To be passed to the callbacks 732 * 733 * RETURN: Status from callback(s) 734 * 735 * DESCRIPTION: Walk the entire parse tree. 736 * 737 ******************************************************************************/ 738 739 ACPI_STATUS 740 TrWalkParseTree ( 741 ACPI_PARSE_OBJECT *Op, 742 UINT32 Visitation, 743 ASL_WALK_CALLBACK DescendingCallback, 744 ASL_WALK_CALLBACK AscendingCallback, 745 void *Context) 746 { 747 UINT32 Level; 748 BOOLEAN OpPreviouslyVisited; 749 ACPI_PARSE_OBJECT *StartOp = Op; 750 ACPI_STATUS Status; 751 ACPI_PARSE_OBJECT *Restore = NULL; 752 BOOLEAN WalkOneDefinitionBlock = Visitation & ASL_WALK_VISIT_DB_SEPARATELY; 753 754 755 if (!AslGbl_ParseTreeRoot) 756 { 757 return (AE_OK); 758 } 759 760 Level = 0; 761 OpPreviouslyVisited = FALSE; 762 763 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK && 764 WalkOneDefinitionBlock) 765 { 766 Restore = Op->Asl.Next; 767 Op->Asl.Next = NULL; 768 } 769 switch (Visitation & ~ASL_WALK_VISIT_DB_SEPARATELY) 770 { 771 case ASL_WALK_VISIT_DOWNWARD: 772 773 while (Op) 774 { 775 if (!OpPreviouslyVisited) 776 { 777 /* Let the callback process the op. */ 778 779 Status = DescendingCallback (Op, Level, Context); 780 if (ACPI_SUCCESS (Status)) 781 { 782 /* Visit children first, once */ 783 784 if (Op->Asl.Child) 785 { 786 Level++; 787 Op = Op->Asl.Child; 788 continue; 789 } 790 } 791 else if (Status != AE_CTRL_DEPTH) 792 { 793 /* Exit immediately on any error */ 794 795 goto ErrorExit; 796 } 797 } 798 799 /* Terminate walk at start op */ 800 801 if (Op == StartOp) 802 { 803 break; 804 } 805 806 /* No more children, visit peers */ 807 808 if (Op->Asl.Next) 809 { 810 Op = Op->Asl.Next; 811 OpPreviouslyVisited = FALSE; 812 } 813 else 814 { 815 /* No children or peers, re-visit parent */ 816 817 if (Level != 0 ) 818 { 819 Level--; 820 } 821 Op = Op->Asl.Parent; 822 OpPreviouslyVisited = TRUE; 823 } 824 } 825 break; 826 827 case ASL_WALK_VISIT_UPWARD: 828 829 while (Op) 830 { 831 /* Visit leaf op (no children) or parent op on return trip */ 832 833 if ((!Op->Asl.Child) || 834 (OpPreviouslyVisited)) 835 { 836 /* Let the callback process the op. */ 837 838 Status = AscendingCallback (Op, Level, Context); 839 if (ACPI_FAILURE (Status)) 840 { 841 goto ErrorExit; 842 } 843 } 844 else 845 { 846 /* Visit children first, once */ 847 848 Level++; 849 Op = Op->Asl.Child; 850 continue; 851 } 852 853 /* Terminate walk at start op */ 854 855 if (Op == StartOp) 856 { 857 break; 858 } 859 860 /* No more children, visit peers */ 861 862 if (Op->Asl.Next) 863 { 864 Op = Op->Asl.Next; 865 OpPreviouslyVisited = FALSE; 866 } 867 else 868 { 869 /* No children or peers, re-visit parent */ 870 871 if (Level != 0 ) 872 { 873 Level--; 874 } 875 Op = Op->Asl.Parent; 876 OpPreviouslyVisited = TRUE; 877 } 878 } 879 break; 880 881 case ASL_WALK_VISIT_TWICE: 882 883 while (Op) 884 { 885 if (OpPreviouslyVisited) 886 { 887 Status = AscendingCallback (Op, Level, Context); 888 if (ACPI_FAILURE (Status)) 889 { 890 goto ErrorExit; 891 } 892 } 893 else 894 { 895 /* Let the callback process the op. */ 896 897 Status = DescendingCallback (Op, Level, Context); 898 if (ACPI_SUCCESS (Status)) 899 { 900 /* Visit children first, once */ 901 902 if (Op->Asl.Child) 903 { 904 Level++; 905 Op = Op->Asl.Child; 906 continue; 907 } 908 } 909 else if (Status != AE_CTRL_DEPTH) 910 { 911 /* Exit immediately on any error */ 912 913 goto ErrorExit; 914 } 915 } 916 917 /* Terminate walk at start op */ 918 919 if (Op == StartOp) 920 { 921 break; 922 } 923 924 /* No more children, visit peers */ 925 926 if (Op->Asl.Next) 927 { 928 Op = Op->Asl.Next; 929 OpPreviouslyVisited = FALSE; 930 } 931 else 932 { 933 /* No children or peers, re-visit parent */ 934 935 if (Level != 0 ) 936 { 937 Level--; 938 } 939 Op = Op->Asl.Parent; 940 OpPreviouslyVisited = TRUE; 941 } 942 } 943 break; 944 945 default: 946 /* No other types supported */ 947 break; 948 } 949 950 /* If we get here, the walk completed with no errors */ 951 952 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK && 953 WalkOneDefinitionBlock) 954 { 955 Op->Asl.Next = Restore; 956 } 957 958 return (AE_OK); 959 960 ErrorExit: 961 962 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK && 963 WalkOneDefinitionBlock) 964 { 965 Op->Asl.Next = Restore; 966 } 967 return (Status); 968 } 969