1 /****************************************************************************** 2 * 3 * Module Name: asltree - Parse tree management 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2018, 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 "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 Gbl_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 = Gbl_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 (Gbl_RevisionOverride) 294 { 295 AcpiUtSetIntegerWidth (Gbl_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 = Gbl_CurrentLineNumber; 330 Op->Asl.EndLogicalLine = Gbl_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 va_list ap; 358 UINT32 i; 359 BOOLEAN FirstChild; 360 361 362 va_start (ap, NumChildren); 363 364 TrSetOpEndLineNumber (Op); 365 366 DbgPrint (ASL_PARSE_OUTPUT, 367 "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ", 368 Op->Asl.LineNumber, Op->Asl.EndLine, 369 Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode)); 370 371 switch (Op->Asl.ParseOpcode) 372 { 373 case PARSEOP_ASL_CODE: 374 375 Gbl_ParseTreeRoot = Op; 376 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 377 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); 378 break; 379 380 case PARSEOP_DEFINITION_BLOCK: 381 382 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 383 break; 384 385 case PARSEOP_OPERATIONREGION: 386 387 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 388 break; 389 390 case PARSEOP_OR: 391 392 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 393 break; 394 395 default: 396 397 /* Nothing to do for other opcodes */ 398 399 break; 400 } 401 402 /* The following is for capturing comments */ 403 404 if (AcpiGbl_CaptureComments) 405 { 406 /* 407 * If there are "regular comments" detected at this point, 408 * then is an endBlk comment. Categorize it as so and distribute 409 * all regular comments to this parse op. 410 */ 411 if (Gbl_CommentListHead) 412 { 413 Op->Asl.EndBlkComment = Gbl_CommentListHead; 414 CvDbgPrint ("EndBlk Comment for %s: %s", 415 Op->Asl.ParseOpName, Gbl_CommentListHead->Comment); 416 Gbl_CommentListHead = NULL; 417 Gbl_CommentListTail = NULL; 418 } 419 } 420 421 /* Link the new op to it's children */ 422 423 PrevChild = NULL; 424 FirstChild = TRUE; 425 for (i = 0; i < NumChildren; i++) 426 { 427 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 428 429 if ((Child == PrevChild) && (Child != NULL)) 430 { 431 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child, 432 "Child op list invalid"); 433 va_end(ap); 434 return (Op); 435 } 436 437 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 438 439 /* 440 * If child is NULL, this means that an optional argument 441 * was omitted. We must create a placeholder with a special 442 * opcode (DEFAULT_ARG) so that the code generator will know 443 * that it must emit the correct default for this argument 444 */ 445 if (!Child) 446 { 447 Child = TrAllocateOp (PARSEOP_DEFAULT_ARG); 448 } 449 450 /* Link first child to parent */ 451 452 if (FirstChild) 453 { 454 FirstChild = FALSE; 455 Op->Asl.Child = Child; 456 } 457 458 /* Point all children to parent */ 459 460 Child->Asl.Parent = Op; 461 462 /* Link children in a peer list */ 463 464 if (PrevChild) 465 { 466 PrevChild->Asl.Next = Child; 467 } 468 469 /* 470 * This child might be a list, point all ops in the list 471 * to the same parent 472 */ 473 while (Child->Asl.Next) 474 { 475 Child = Child->Asl.Next; 476 Child->Asl.Parent = Op; 477 } 478 479 PrevChild = Child; 480 } 481 482 va_end(ap); 483 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 484 485 if (AcpiGbl_CaptureComments) 486 { 487 Gbl_CommentState.LatestParseOp = Op; 488 CvDbgPrint ("TrLinkOpChildren=====Set latest parse op to this op.\n"); 489 } 490 491 return (Op); 492 } 493 494 495 /******************************************************************************* 496 * 497 * FUNCTION: TrLinkPeerOp 498 * 499 * PARAMETERS: Op1 - First peer 500 * Op2 - Second peer 501 * 502 * RETURN: Op1 or the non-null op. 503 * 504 * DESCRIPTION: Link two ops as peers. Handles cases where one peer is null. 505 * 506 ******************************************************************************/ 507 508 ACPI_PARSE_OBJECT * 509 TrLinkPeerOp ( 510 ACPI_PARSE_OBJECT *Op1, 511 ACPI_PARSE_OBJECT *Op2) 512 { 513 ACPI_PARSE_OBJECT *Next; 514 515 516 DbgPrint (ASL_PARSE_OUTPUT, 517 "\nLinkPeerOp: 1=%p (%s), 2=%p (%s)\n", 518 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL, 519 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL); 520 521 522 if ((!Op1) && (!Op2)) 523 { 524 DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null ops!\n"); 525 return (Op1); 526 } 527 528 /* If one of the ops is null, just return the non-null op */ 529 530 if (!Op2) 531 { 532 return (Op1); 533 } 534 535 if (!Op1) 536 { 537 return (Op2); 538 } 539 540 if (Op1 == Op2) 541 { 542 DbgPrint (ASL_DEBUG_OUTPUT, 543 "\n************* Internal error, linking op to itself %p\n", 544 Op1); 545 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1, 546 "Linking op to itself"); 547 return (Op1); 548 } 549 550 Op1->Asl.Parent = Op2->Asl.Parent; 551 552 /* 553 * Op 1 may already have a peer list (such as an IF/ELSE pair), 554 * so we must walk to the end of the list and attach the new 555 * peer at the end 556 */ 557 Next = Op1; 558 while (Next->Asl.Next) 559 { 560 Next = Next->Asl.Next; 561 } 562 563 Next->Asl.Next = Op2; 564 return (Op1); 565 } 566 567 568 /******************************************************************************* 569 * 570 * FUNCTION: TrLinkPeerOps 571 * 572 * PARAMETERS: NumPeers - The number of ops in the list to follow 573 * ... - A list of ops to link together as peers 574 * 575 * RETURN: The first op in the list (head of the peer list) 576 * 577 * DESCRIPTION: Link together an arbitrary number of peer ops. 578 * 579 ******************************************************************************/ 580 581 ACPI_PARSE_OBJECT * 582 TrLinkPeerOps ( 583 UINT32 NumPeers, 584 ...) 585 { 586 ACPI_PARSE_OBJECT *This; 587 ACPI_PARSE_OBJECT *Next; 588 va_list ap; 589 UINT32 i; 590 ACPI_PARSE_OBJECT *Start; 591 592 593 DbgPrint (ASL_PARSE_OUTPUT, 594 "\nLinkPeerOps: (%u) ", NumPeers); 595 596 va_start (ap, NumPeers); 597 This = va_arg (ap, ACPI_PARSE_OBJECT *); 598 Start = This; 599 600 /* 601 * Link all peers 602 */ 603 for (i = 0; i < (NumPeers -1); i++) 604 { 605 DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This); 606 607 while (This->Asl.Next) 608 { 609 This = This->Asl.Next; 610 } 611 612 /* Get another peer op */ 613 614 Next = va_arg (ap, ACPI_PARSE_OBJECT *); 615 if (!Next) 616 { 617 Next = TrAllocateOp (PARSEOP_DEFAULT_ARG); 618 } 619 620 /* link new op to the current op */ 621 622 This->Asl.Next = Next; 623 This = Next; 624 } 625 626 va_end (ap); 627 DbgPrint (ASL_PARSE_OUTPUT,"\n"); 628 return (Start); 629 } 630 631 632 /******************************************************************************* 633 * 634 * FUNCTION: TrLinkChildOp 635 * 636 * PARAMETERS: Op1 - Parent op 637 * Op2 - Op to become a child 638 * 639 * RETURN: The parent op 640 * 641 * DESCRIPTION: Link two ops together as a parent and child 642 * 643 ******************************************************************************/ 644 645 ACPI_PARSE_OBJECT * 646 TrLinkChildOp ( 647 ACPI_PARSE_OBJECT *Op1, 648 ACPI_PARSE_OBJECT *Op2) 649 { 650 ACPI_PARSE_OBJECT *Next; 651 652 653 DbgPrint (ASL_PARSE_OUTPUT, 654 "\nLinkChildOp: Parent=%p (%s), Child=%p (%s)\n", 655 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL, 656 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL); 657 658 /* 659 * Converter: if TrLinkChildOp is called to link a method call, 660 * turn on capture comments as it signifies that we are done parsing 661 * a method call. 662 */ 663 if (AcpiGbl_CaptureComments && Op1) 664 { 665 if (Op1->Asl.ParseOpcode == PARSEOP_METHODCALL) 666 { 667 Gbl_CommentState.CaptureComments = TRUE; 668 } 669 Gbl_CommentState.LatestParseOp = Op1; 670 } 671 672 if (!Op1 || !Op2) 673 { 674 return (Op1); 675 } 676 677 Op1->Asl.Child = Op2; 678 679 /* Set the child and all peers of the child to point to the parent */ 680 681 Next = Op2; 682 while (Next) 683 { 684 Next->Asl.Parent = Op1; 685 Next = Next->Asl.Next; 686 } 687 688 return (Op1); 689 } 690 691 692 /******************************************************************************* 693 * 694 * FUNCTION: TrWalkParseTree 695 * 696 * PARAMETERS: Op - Walk starting point 697 * Visitation - Type of walk 698 * DescendingCallback - Called during tree descent 699 * AscendingCallback - Called during tree ascent 700 * Context - To be passed to the callbacks 701 * 702 * RETURN: Status from callback(s) 703 * 704 * DESCRIPTION: Walk the entire parse tree. 705 * 706 ******************************************************************************/ 707 708 ACPI_STATUS 709 TrWalkParseTree ( 710 ACPI_PARSE_OBJECT *Op, 711 UINT32 Visitation, 712 ASL_WALK_CALLBACK DescendingCallback, 713 ASL_WALK_CALLBACK AscendingCallback, 714 void *Context) 715 { 716 UINT32 Level; 717 BOOLEAN OpPreviouslyVisited; 718 ACPI_PARSE_OBJECT *StartOp = Op; 719 ACPI_STATUS Status; 720 721 722 if (!Gbl_ParseTreeRoot) 723 { 724 return (AE_OK); 725 } 726 727 Level = 0; 728 OpPreviouslyVisited = FALSE; 729 730 switch (Visitation) 731 { 732 case ASL_WALK_VISIT_DOWNWARD: 733 734 while (Op) 735 { 736 if (!OpPreviouslyVisited) 737 { 738 /* Let the callback process the op. */ 739 740 Status = DescendingCallback (Op, Level, Context); 741 if (ACPI_SUCCESS (Status)) 742 { 743 /* Visit children first, once */ 744 745 if (Op->Asl.Child) 746 { 747 Level++; 748 Op = Op->Asl.Child; 749 continue; 750 } 751 } 752 else if (Status != AE_CTRL_DEPTH) 753 { 754 /* Exit immediately on any error */ 755 756 return (Status); 757 } 758 } 759 760 /* Terminate walk at start op */ 761 762 if (Op == StartOp) 763 { 764 break; 765 } 766 767 /* No more children, visit peers */ 768 769 if (Op->Asl.Next) 770 { 771 Op = Op->Asl.Next; 772 OpPreviouslyVisited = FALSE; 773 } 774 else 775 { 776 /* No children or peers, re-visit parent */ 777 778 if (Level != 0 ) 779 { 780 Level--; 781 } 782 Op = Op->Asl.Parent; 783 OpPreviouslyVisited = TRUE; 784 } 785 } 786 break; 787 788 case ASL_WALK_VISIT_UPWARD: 789 790 while (Op) 791 { 792 /* Visit leaf op (no children) or parent op on return trip */ 793 794 if ((!Op->Asl.Child) || 795 (OpPreviouslyVisited)) 796 { 797 /* Let the callback process the op. */ 798 799 Status = AscendingCallback (Op, Level, Context); 800 if (ACPI_FAILURE (Status)) 801 { 802 return (Status); 803 } 804 } 805 else 806 { 807 /* Visit children first, once */ 808 809 Level++; 810 Op = Op->Asl.Child; 811 continue; 812 } 813 814 /* Terminate walk at start op */ 815 816 if (Op == StartOp) 817 { 818 break; 819 } 820 821 /* No more children, visit peers */ 822 823 if (Op->Asl.Next) 824 { 825 Op = Op->Asl.Next; 826 OpPreviouslyVisited = FALSE; 827 } 828 else 829 { 830 /* No children or peers, re-visit parent */ 831 832 if (Level != 0 ) 833 { 834 Level--; 835 } 836 Op = Op->Asl.Parent; 837 OpPreviouslyVisited = TRUE; 838 } 839 } 840 break; 841 842 case ASL_WALK_VISIT_TWICE: 843 844 while (Op) 845 { 846 if (OpPreviouslyVisited) 847 { 848 Status = AscendingCallback (Op, Level, Context); 849 if (ACPI_FAILURE (Status)) 850 { 851 return (Status); 852 } 853 } 854 else 855 { 856 /* Let the callback process the op. */ 857 858 Status = DescendingCallback (Op, Level, Context); 859 if (ACPI_SUCCESS (Status)) 860 { 861 /* Visit children first, once */ 862 863 if (Op->Asl.Child) 864 { 865 Level++; 866 Op = Op->Asl.Child; 867 continue; 868 } 869 } 870 else if (Status != AE_CTRL_DEPTH) 871 { 872 /* Exit immediately on any error */ 873 874 return (Status); 875 } 876 } 877 878 /* Terminate walk at start op */ 879 880 if (Op == StartOp) 881 { 882 break; 883 } 884 885 /* No more children, visit peers */ 886 887 if (Op->Asl.Next) 888 { 889 Op = Op->Asl.Next; 890 OpPreviouslyVisited = FALSE; 891 } 892 else 893 { 894 /* No children or peers, re-visit parent */ 895 896 if (Level != 0 ) 897 { 898 Level--; 899 } 900 Op = Op->Asl.Parent; 901 OpPreviouslyVisited = TRUE; 902 } 903 } 904 break; 905 906 default: 907 /* No other types supported */ 908 break; 909 } 910 911 /* If we get here, the walk completed with no errors */ 912 913 return (AE_OK); 914 } 915