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