1 /****************************************************************************** 2 * 3 * Module Name: asltree - parse tree management 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 #include <contrib/dev/acpica/compiler/aslcompiler.h> 45 #include "aslcompiler.y.h" 46 #include <contrib/dev/acpica/include/acapps.h> 47 #include <time.h> 48 49 #define _COMPONENT ACPI_COMPILER 50 ACPI_MODULE_NAME ("asltree") 51 52 /* Local prototypes */ 53 54 static ACPI_PARSE_OBJECT * 55 TrGetNextNode ( 56 void); 57 58 59 /******************************************************************************* 60 * 61 * FUNCTION: TrSetParent 62 * 63 * PARAMETERS: Op - To be set to new parent 64 * ParentOp - The parent 65 * 66 * RETURN: None, sets Op parent directly 67 * 68 * DESCRIPTION: Change the parent of a parse op. 69 * 70 ******************************************************************************/ 71 72 void 73 TrSetParent ( 74 ACPI_PARSE_OBJECT *Op, 75 ACPI_PARSE_OBJECT *ParentOp) 76 { 77 78 Op->Asl.Parent = ParentOp; 79 } 80 81 82 /******************************************************************************* 83 * 84 * FUNCTION: TrGetNextNode 85 * 86 * PARAMETERS: None 87 * 88 * RETURN: New parse node. Aborts on allocation failure 89 * 90 * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local 91 * dynamic memory manager for performance reasons (This has a 92 * major impact on the speed of the compiler.) 93 * 94 ******************************************************************************/ 95 96 static ACPI_PARSE_OBJECT * 97 TrGetNextNode ( 98 void) 99 { 100 ASL_CACHE_INFO *Cache; 101 102 103 if (Gbl_ParseOpCacheNext >= Gbl_ParseOpCacheLast) 104 { 105 /* Allocate a new buffer */ 106 107 Cache = UtLocalCalloc (sizeof (Cache->Next) + 108 (sizeof (ACPI_PARSE_OBJECT) * ASL_PARSEOP_CACHE_SIZE)); 109 110 /* Link new cache buffer to head of list */ 111 112 Cache->Next = Gbl_ParseOpCacheList; 113 Gbl_ParseOpCacheList = Cache; 114 115 /* Setup cache management pointers */ 116 117 Gbl_ParseOpCacheNext = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Cache->Buffer); 118 Gbl_ParseOpCacheLast = Gbl_ParseOpCacheNext + ASL_PARSEOP_CACHE_SIZE; 119 } 120 121 Gbl_ParseOpCount++; 122 return (Gbl_ParseOpCacheNext++); 123 } 124 125 126 /******************************************************************************* 127 * 128 * FUNCTION: TrAllocateNode 129 * 130 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 131 * 132 * RETURN: New parse node. Aborts on allocation failure 133 * 134 * DESCRIPTION: Allocate and initialize a new parse node for the parse tree 135 * 136 ******************************************************************************/ 137 138 ACPI_PARSE_OBJECT * 139 TrAllocateNode ( 140 UINT32 ParseOpcode) 141 { 142 ACPI_PARSE_OBJECT *Op; 143 144 145 Op = TrGetNextNode (); 146 147 Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 148 Op->Asl.Filename = Gbl_Files[ASL_FILE_INPUT].Filename; 149 Op->Asl.LineNumber = Gbl_CurrentLineNumber; 150 Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber; 151 Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset; 152 Op->Asl.Column = Gbl_CurrentColumn; 153 154 UtSetParseOpName (Op); 155 return (Op); 156 } 157 158 159 /******************************************************************************* 160 * 161 * FUNCTION: TrReleaseNode 162 * 163 * PARAMETERS: Op - Op to be released 164 * 165 * RETURN: None 166 * 167 * DESCRIPTION: "release" a node. In truth, nothing is done since the node 168 * is part of a larger buffer 169 * 170 ******************************************************************************/ 171 172 void 173 TrReleaseNode ( 174 ACPI_PARSE_OBJECT *Op) 175 { 176 177 return; 178 } 179 180 181 /******************************************************************************* 182 * 183 * FUNCTION: TrSetCurrentFilename 184 * 185 * PARAMETERS: Op - An existing parse node 186 * 187 * RETURN: None 188 * 189 * DESCRIPTION: Save the include file filename. Used for debug output only. 190 * 191 ******************************************************************************/ 192 193 void 194 TrSetCurrentFilename ( 195 ACPI_PARSE_OBJECT *Op) 196 { 197 Op->Asl.Filename = Gbl_PreviousIncludeFilename; 198 } 199 200 201 /******************************************************************************* 202 * 203 * FUNCTION: TrUpdateNode 204 * 205 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 206 * Op - An existing parse node 207 * 208 * RETURN: The updated node 209 * 210 * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to 211 * change an opcode to DEFAULT_ARG so that the node is ignored 212 * during the code generation. Also used to set generic integers 213 * to a specific size (8, 16, 32, or 64 bits) 214 * 215 ******************************************************************************/ 216 217 ACPI_PARSE_OBJECT * 218 TrUpdateNode ( 219 UINT32 ParseOpcode, 220 ACPI_PARSE_OBJECT *Op) 221 { 222 223 if (!Op) 224 { 225 return (NULL); 226 } 227 228 DbgPrint (ASL_PARSE_OUTPUT, 229 "\nUpdateNode: Old - %s, New - %s\n", 230 UtGetOpName (Op->Asl.ParseOpcode), 231 UtGetOpName (ParseOpcode)); 232 233 /* Assign new opcode and name */ 234 235 if (Op->Asl.ParseOpcode == PARSEOP_ONES) 236 { 237 switch (ParseOpcode) 238 { 239 case PARSEOP_BYTECONST: 240 241 Op->Asl.Value.Integer = ACPI_UINT8_MAX; 242 break; 243 244 case PARSEOP_WORDCONST: 245 246 Op->Asl.Value.Integer = ACPI_UINT16_MAX; 247 break; 248 249 case PARSEOP_DWORDCONST: 250 251 Op->Asl.Value.Integer = ACPI_UINT32_MAX; 252 break; 253 254 /* Don't need to do the QWORD case */ 255 256 default: 257 258 /* Don't care about others */ 259 break; 260 } 261 } 262 263 Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 264 UtSetParseOpName (Op); 265 266 /* 267 * For the BYTE, WORD, and DWORD constants, make sure that the integer 268 * that was passed in will actually fit into the data type 269 */ 270 switch (ParseOpcode) 271 { 272 case PARSEOP_BYTECONST: 273 274 UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX); 275 Op->Asl.Value.Integer &= ACPI_UINT8_MAX; 276 break; 277 278 case PARSEOP_WORDCONST: 279 280 UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX); 281 Op->Asl.Value.Integer &= ACPI_UINT16_MAX; 282 break; 283 284 case PARSEOP_DWORDCONST: 285 286 UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX); 287 Op->Asl.Value.Integer &= ACPI_UINT32_MAX; 288 break; 289 290 default: 291 292 /* Don't care about others, don't need to check QWORD */ 293 294 break; 295 } 296 297 return (Op); 298 } 299 300 301 /******************************************************************************* 302 * 303 * FUNCTION: TrPrintNodeCompileFlags 304 * 305 * PARAMETERS: Flags - Flags word to be decoded 306 * 307 * RETURN: None 308 * 309 * DESCRIPTION: Decode a flags word to text. Displays all flags that are set. 310 * 311 ******************************************************************************/ 312 313 void 314 TrPrintNodeCompileFlags ( 315 UINT32 Flags) 316 { 317 UINT32 i; 318 UINT32 FlagBit = 1; 319 char *FlagName = NULL; 320 321 322 for (i = 0; i < 32; i++) 323 { 324 switch (Flags & FlagBit) 325 { 326 case NODE_VISITED: 327 328 FlagName = "NODE_VISITED"; 329 break; 330 331 case NODE_AML_PACKAGE: 332 333 FlagName = "NODE_AML_PACKAGE"; 334 break; 335 336 case NODE_IS_TARGET: 337 338 FlagName = "NODE_IS_TARGET"; 339 break; 340 341 case NODE_IS_RESOURCE_DESC: 342 343 FlagName = "NODE_IS_RESOURCE_DESC"; 344 break; 345 346 case NODE_IS_RESOURCE_FIELD: 347 348 FlagName = "NODE_IS_RESOURCE_FIELD"; 349 break; 350 351 case NODE_HAS_NO_EXIT: 352 353 FlagName = "NODE_HAS_NO_EXIT"; 354 break; 355 356 case NODE_IF_HAS_NO_EXIT: 357 358 FlagName = "NODE_IF_HAS_NO_EXIT"; 359 break; 360 361 case NODE_NAME_INTERNALIZED: 362 363 FlagName = "NODE_NAME_INTERNALIZED"; 364 break; 365 366 case NODE_METHOD_NO_RETVAL: 367 368 FlagName = "NODE_METHOD_NO_RETVAL"; 369 break; 370 371 case NODE_METHOD_SOME_NO_RETVAL: 372 373 FlagName = "NODE_METHOD_SOME_NO_RETVAL"; 374 break; 375 376 case NODE_RESULT_NOT_USED: 377 378 FlagName = "NODE_RESULT_NOT_USED"; 379 break; 380 381 case NODE_METHOD_TYPED: 382 383 FlagName = "NODE_METHOD_TYPED"; 384 break; 385 386 case NODE_COULD_NOT_REDUCE: 387 388 FlagName = "NODE_COULD_NOT_REDUCE"; 389 break; 390 391 case NODE_COMPILE_TIME_CONST: 392 393 FlagName = "NODE_COMPILE_TIME_CONST"; 394 break; 395 396 case NODE_IS_TERM_ARG: 397 398 FlagName = "NODE_IS_TERM_ARG"; 399 break; 400 401 case NODE_WAS_ONES_OP: 402 403 FlagName = "NODE_WAS_ONES_OP"; 404 break; 405 406 case NODE_IS_NAME_DECLARATION: 407 408 FlagName = "NODE_IS_NAME_DECLARATION"; 409 break; 410 411 case NODE_COMPILER_EMITTED: 412 413 FlagName = "NODE_COMPILER_EMITTED"; 414 break; 415 416 case NODE_IS_DUPLICATE: 417 418 FlagName = "NODE_IS_DUPLICATE"; 419 break; 420 421 case NODE_IS_RESOURCE_DATA: 422 423 FlagName = "NODE_IS_RESOURCE_DATA"; 424 break; 425 426 case NODE_IS_NULL_RETURN: 427 428 FlagName = "NODE_IS_NULL_RETURN"; 429 break; 430 431 default: 432 break; 433 } 434 435 if (FlagName) 436 { 437 DbgPrint (ASL_PARSE_OUTPUT, " %s", FlagName); 438 FlagName = NULL; 439 } 440 441 FlagBit <<= 1; 442 } 443 } 444 445 446 /******************************************************************************* 447 * 448 * FUNCTION: TrSetNodeFlags 449 * 450 * PARAMETERS: Op - An existing parse node 451 * Flags - New flags word 452 * 453 * RETURN: The updated parser op 454 * 455 * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set 456 * 457 ******************************************************************************/ 458 459 ACPI_PARSE_OBJECT * 460 TrSetNodeFlags ( 461 ACPI_PARSE_OBJECT *Op, 462 UINT32 Flags) 463 { 464 465 if (!Op) 466 { 467 return (NULL); 468 } 469 470 DbgPrint (ASL_PARSE_OUTPUT, 471 "\nSetNodeFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags); 472 473 TrPrintNodeCompileFlags (Flags); 474 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 475 476 Op->Asl.CompileFlags |= Flags; 477 return (Op); 478 } 479 480 481 /******************************************************************************* 482 * 483 * FUNCTION: TrSetNodeAmlLength 484 * 485 * PARAMETERS: Op - An existing parse node 486 * Length - AML Length 487 * 488 * RETURN: The updated parser op 489 * 490 * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate 491 * the presence of a node that must be reduced to a fixed length 492 * constant. 493 * 494 ******************************************************************************/ 495 496 ACPI_PARSE_OBJECT * 497 TrSetNodeAmlLength ( 498 ACPI_PARSE_OBJECT *Op, 499 UINT32 Length) 500 { 501 502 DbgPrint (ASL_PARSE_OUTPUT, 503 "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length); 504 505 if (!Op) 506 { 507 return (NULL); 508 } 509 510 Op->Asl.AmlLength = Length; 511 return (Op); 512 } 513 514 515 /******************************************************************************* 516 * 517 * FUNCTION: TrSetEndLineNumber 518 * 519 * PARAMETERS: Op - An existing parse node 520 * 521 * RETURN: None. 522 * 523 * DESCRIPTION: Set the ending line numbers (file line and logical line) of a 524 * parse node to the current line numbers. 525 * 526 ******************************************************************************/ 527 528 void 529 TrSetEndLineNumber ( 530 ACPI_PARSE_OBJECT *Op) 531 { 532 533 /* If the end line # is already set, just return */ 534 535 if (Op->Asl.EndLine) 536 { 537 return; 538 } 539 540 Op->Asl.EndLine = Gbl_CurrentLineNumber; 541 Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber; 542 } 543 544 545 /******************************************************************************* 546 * 547 * FUNCTION: TrCreateAssignmentNode 548 * 549 * PARAMETERS: Target - Assignment target 550 * Source - Assignment source 551 * 552 * RETURN: Pointer to the new node. Aborts on allocation failure 553 * 554 * DESCRIPTION: Implements the C-style '=' operator. It changes the parse 555 * tree if possible to utilize the last argument of the math 556 * operators which is a target operand -- thus saving invocation 557 * of and additional Store() operator. An optimization. 558 * 559 ******************************************************************************/ 560 561 ACPI_PARSE_OBJECT * 562 TrCreateAssignmentNode ( 563 ACPI_PARSE_OBJECT *Target, 564 ACPI_PARSE_OBJECT *Source) 565 { 566 ACPI_PARSE_OBJECT *TargetOp; 567 ACPI_PARSE_OBJECT *SourceOp1; 568 ACPI_PARSE_OBJECT *SourceOp2; 569 ACPI_PARSE_OBJECT *Operator; 570 571 572 DbgPrint (ASL_PARSE_OUTPUT, 573 "\nTrCreateAssignmentNode Line [%u to %u] Source %s Target %s\n", 574 Source->Asl.LineNumber, Source->Asl.EndLine, 575 UtGetOpName (Source->Asl.ParseOpcode), 576 UtGetOpName (Target->Asl.ParseOpcode)); 577 578 TrSetNodeFlags (Target, NODE_IS_TARGET); 579 580 switch (Source->Asl.ParseOpcode) 581 { 582 /* 583 * Only these operators can be optimized because they have 584 * a target operand 585 */ 586 case PARSEOP_ADD: 587 case PARSEOP_AND: 588 case PARSEOP_DIVIDE: 589 case PARSEOP_INDEX: 590 case PARSEOP_MOD: 591 case PARSEOP_MULTIPLY: 592 case PARSEOP_NOT: 593 case PARSEOP_OR: 594 case PARSEOP_SHIFTLEFT: 595 case PARSEOP_SHIFTRIGHT: 596 case PARSEOP_SUBTRACT: 597 case PARSEOP_XOR: 598 599 break; 600 601 /* Otherwise, just create a normal Store operator */ 602 603 default: 604 605 goto CannotOptimize; 606 } 607 608 /* 609 * Transform the parse tree such that the target is moved to the 610 * last operand of the operator 611 */ 612 SourceOp1 = Source->Asl.Child; 613 SourceOp2 = SourceOp1->Asl.Next; 614 615 /* NOT only has one operand, but has a target */ 616 617 if (Source->Asl.ParseOpcode == PARSEOP_NOT) 618 { 619 SourceOp2 = SourceOp1; 620 } 621 622 /* DIVIDE has an extra target operand (remainder) */ 623 624 if (Source->Asl.ParseOpcode == PARSEOP_DIVIDE) 625 { 626 SourceOp2 = SourceOp2->Asl.Next; 627 } 628 629 TargetOp = SourceOp2->Asl.Next; 630 631 /* 632 * Can't perform this optimization if there already is a target 633 * for the operator (ZERO is a "no target" placeholder). 634 */ 635 if (TargetOp->Asl.ParseOpcode != PARSEOP_ZERO) 636 { 637 goto CannotOptimize; 638 } 639 640 /* Link in the target as the final operand */ 641 642 SourceOp2->Asl.Next = Target; 643 Target->Asl.Parent = Source; 644 645 return (Source); 646 647 648 CannotOptimize: 649 650 Operator = TrAllocateNode (PARSEOP_STORE); 651 TrLinkChildren (Operator, 2, Source, Target); 652 653 /* Set the appropriate line numbers for the new node */ 654 655 Operator->Asl.LineNumber = Target->Asl.LineNumber; 656 Operator->Asl.LogicalLineNumber = Target->Asl.LogicalLineNumber; 657 Operator->Asl.LogicalByteOffset = Target->Asl.LogicalByteOffset; 658 Operator->Asl.Column = Target->Asl.Column; 659 660 return (Operator); 661 } 662 663 664 /******************************************************************************* 665 * 666 * FUNCTION: TrCreateLeafNode 667 * 668 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 669 * 670 * RETURN: Pointer to the new node. Aborts on allocation failure 671 * 672 * DESCRIPTION: Create a simple leaf node (no children or peers, and no value 673 * assigned to the node) 674 * 675 ******************************************************************************/ 676 677 ACPI_PARSE_OBJECT * 678 TrCreateLeafNode ( 679 UINT32 ParseOpcode) 680 { 681 ACPI_PARSE_OBJECT *Op; 682 683 684 Op = TrAllocateNode (ParseOpcode); 685 686 DbgPrint (ASL_PARSE_OUTPUT, 687 "\nCreateLeafNode Ln/Col %u/%u NewNode %p Op %s\n\n", 688 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode)); 689 690 return (Op); 691 } 692 693 694 /******************************************************************************* 695 * 696 * FUNCTION: TrCreateNullTarget 697 * 698 * PARAMETERS: None 699 * 700 * RETURN: Pointer to the new node. Aborts on allocation failure 701 * 702 * DESCRIPTION: Create a "null" target node. This is defined by the ACPI 703 * specification to be a zero AML opcode, and indicates that 704 * no target has been specified for the parent operation 705 * 706 ******************************************************************************/ 707 708 ACPI_PARSE_OBJECT * 709 TrCreateNullTarget ( 710 void) 711 { 712 ACPI_PARSE_OBJECT *Op; 713 714 715 Op = TrAllocateNode (PARSEOP_ZERO); 716 Op->Asl.CompileFlags |= (NODE_IS_TARGET | NODE_COMPILE_TIME_CONST); 717 718 DbgPrint (ASL_PARSE_OUTPUT, 719 "\nCreateNullTarget Ln/Col %u/%u NewNode %p Op %s\n", 720 Op->Asl.LineNumber, Op->Asl.Column, Op, 721 UtGetOpName (Op->Asl.ParseOpcode)); 722 723 return (Op); 724 } 725 726 727 /******************************************************************************* 728 * 729 * FUNCTION: TrCreateConstantLeafNode 730 * 731 * PARAMETERS: ParseOpcode - The constant opcode 732 * 733 * RETURN: Pointer to the new node. Aborts on allocation failure 734 * 735 * DESCRIPTION: Create a leaf node (no children or peers) for one of the 736 * special constants - __LINE__, __FILE__, and __DATE__. 737 * 738 * Note: An implemenation of __FUNC__ cannot happen here because we don't 739 * have a full parse tree at this time and cannot find the parent control 740 * method. If it is ever needed, __FUNC__ must be implemented later, after 741 * the parse tree has been fully constructed. 742 * 743 ******************************************************************************/ 744 745 ACPI_PARSE_OBJECT * 746 TrCreateConstantLeafNode ( 747 UINT32 ParseOpcode) 748 { 749 ACPI_PARSE_OBJECT *Op = NULL; 750 time_t CurrentTime; 751 char *StaticTimeString; 752 char *TimeString; 753 char *Filename; 754 755 756 switch (ParseOpcode) 757 { 758 case PARSEOP___LINE__: 759 760 Op = TrAllocateNode (PARSEOP_INTEGER); 761 Op->Asl.Value.Integer = Op->Asl.LineNumber; 762 break; 763 764 case PARSEOP___PATH__: 765 766 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 767 768 /* Op.Asl.Filename contains the full pathname to the file */ 769 770 Op->Asl.Value.String = Op->Asl.Filename; 771 break; 772 773 case PARSEOP___FILE__: 774 775 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 776 777 /* Get the simple filename from the full path */ 778 779 FlSplitInputPathname (Op->Asl.Filename, NULL, &Filename); 780 Op->Asl.Value.String = Filename; 781 break; 782 783 case PARSEOP___DATE__: 784 785 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 786 787 /* Get a copy of the current time */ 788 789 CurrentTime = time (NULL); 790 StaticTimeString = ctime (&CurrentTime); 791 TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1); 792 strcpy (TimeString, StaticTimeString); 793 794 TimeString[strlen(TimeString) -1] = 0; /* Remove trailing newline */ 795 Op->Asl.Value.String = TimeString; 796 break; 797 798 default: /* This would be an internal error */ 799 800 return (NULL); 801 } 802 803 DbgPrint (ASL_PARSE_OUTPUT, 804 "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p " 805 "Op %s Value %8.8X%8.8X \n", 806 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode), 807 ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer)); 808 return (Op); 809 } 810 811 812 /******************************************************************************* 813 * 814 * FUNCTION: TrCreateTargetOperand 815 * 816 * PARAMETERS: OriginalOp - Op to be copied 817 * 818 * RETURN: Pointer to the new node. Aborts on allocation failure 819 * 820 * DESCRIPTION: Copy an existing node (and subtree). Used in ASL+ (C-style) 821 * expressions where the target is the same as one of the 822 * operands. A new node and subtree must be created from the 823 * original so that the parse tree can be linked properly. 824 * 825 * NOTE: This code is specific to target operands that are the last 826 * operand in an ASL/AML operator. Meaning that the top-level 827 * parse Op in a possible subtree has a NULL Next pointer. 828 * This simplifies the recursion. 829 * 830 * Subtree example: 831 * DeRefOf (Local1) += 32 832 * 833 * This gets converted to: 834 * Add (DeRefOf (Local1), 32, DeRefOf (Local1)) 835 * 836 * Each DeRefOf has a single child, Local1. Even more complex 837 * subtrees can be created via the Index and DeRefOf operators. 838 * 839 ******************************************************************************/ 840 841 ACPI_PARSE_OBJECT * 842 TrCreateTargetOperand ( 843 ACPI_PARSE_OBJECT *OriginalOp, 844 ACPI_PARSE_OBJECT *ParentOp) 845 { 846 ACPI_PARSE_OBJECT *Op; 847 848 849 if (!OriginalOp) 850 { 851 return (NULL); 852 } 853 854 Op = TrGetNextNode (); 855 856 /* Copy the pertinent values (omit link pointer fields) */ 857 858 Op->Asl.Value = OriginalOp->Asl.Value; 859 Op->Asl.Filename = OriginalOp->Asl.Filename; 860 Op->Asl.LineNumber = OriginalOp->Asl.LineNumber; 861 Op->Asl.LogicalLineNumber = OriginalOp->Asl.LogicalLineNumber; 862 Op->Asl.LogicalByteOffset = OriginalOp->Asl.LogicalByteOffset; 863 Op->Asl.Column = OriginalOp->Asl.Column; 864 Op->Asl.Flags = OriginalOp->Asl.Flags; 865 Op->Asl.CompileFlags = OriginalOp->Asl.CompileFlags; 866 Op->Asl.AmlOpcode = OriginalOp->Asl.AmlOpcode; 867 Op->Asl.ParseOpcode = OriginalOp->Asl.ParseOpcode; 868 Op->Asl.Parent = ParentOp; 869 UtSetParseOpName (Op); 870 871 /* Copy a possible subtree below this node */ 872 873 if (OriginalOp->Asl.Child) 874 { 875 Op->Asl.Child = TrCreateTargetOperand (OriginalOp->Asl.Child, Op); 876 } 877 878 if (OriginalOp->Asl.Next) /* Null for top-level node */ 879 { 880 Op->Asl.Next = TrCreateTargetOperand (OriginalOp->Asl.Next, ParentOp); 881 } 882 883 return (Op); 884 } 885 886 887 /******************************************************************************* 888 * 889 * FUNCTION: TrCreateValuedLeafNode 890 * 891 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 892 * Value - Value to be assigned to the node 893 * 894 * RETURN: Pointer to the new node. Aborts on allocation failure 895 * 896 * DESCRIPTION: Create a leaf node (no children or peers) with a value 897 * assigned to it 898 * 899 ******************************************************************************/ 900 901 ACPI_PARSE_OBJECT * 902 TrCreateValuedLeafNode ( 903 UINT32 ParseOpcode, 904 UINT64 Value) 905 { 906 ACPI_PARSE_OBJECT *Op; 907 908 909 Op = TrAllocateNode (ParseOpcode); 910 911 DbgPrint (ASL_PARSE_OUTPUT, 912 "\nCreateValuedLeafNode Ln/Col %u/%u NewNode %p " 913 "Op %s Value %8.8X%8.8X ", 914 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode), 915 ACPI_FORMAT_UINT64 (Value)); 916 Op->Asl.Value.Integer = Value; 917 918 switch (ParseOpcode) 919 { 920 case PARSEOP_STRING_LITERAL: 921 922 DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value); 923 break; 924 925 case PARSEOP_NAMESEG: 926 927 DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value); 928 break; 929 930 case PARSEOP_NAMESTRING: 931 932 DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value); 933 break; 934 935 case PARSEOP_EISAID: 936 937 DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value); 938 break; 939 940 case PARSEOP_METHOD: 941 942 DbgPrint (ASL_PARSE_OUTPUT, "METHOD"); 943 break; 944 945 case PARSEOP_INTEGER: 946 947 DbgPrint (ASL_PARSE_OUTPUT, "INTEGER->%8.8X%8.8X", 948 ACPI_FORMAT_UINT64 (Value)); 949 break; 950 951 default: 952 953 break; 954 } 955 956 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 957 return (Op); 958 } 959 960 961 /******************************************************************************* 962 * 963 * FUNCTION: TrCreateNode 964 * 965 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 966 * NumChildren - Number of children to follow 967 * ... - A list of child nodes to link to the new 968 * node. NumChildren long. 969 * 970 * RETURN: Pointer to the new node. Aborts on allocation failure 971 * 972 * DESCRIPTION: Create a new parse node and link together a list of child 973 * nodes underneath the new node. 974 * 975 ******************************************************************************/ 976 977 ACPI_PARSE_OBJECT * 978 TrCreateNode ( 979 UINT32 ParseOpcode, 980 UINT32 NumChildren, 981 ...) 982 { 983 ACPI_PARSE_OBJECT *Op; 984 ACPI_PARSE_OBJECT *Child; 985 ACPI_PARSE_OBJECT *PrevChild; 986 va_list ap; 987 UINT32 i; 988 BOOLEAN FirstChild; 989 990 991 va_start (ap, NumChildren); 992 993 /* Allocate one new node */ 994 995 Op = TrAllocateNode (ParseOpcode); 996 997 DbgPrint (ASL_PARSE_OUTPUT, 998 "\nCreateNode Ln/Col %u/%u NewParent %p Child %u Op %s ", 999 Op->Asl.LineNumber, Op->Asl.Column, Op, 1000 NumChildren, UtGetOpName(ParseOpcode)); 1001 1002 /* Some extra debug output based on the parse opcode */ 1003 1004 switch (ParseOpcode) 1005 { 1006 case PARSEOP_ASL_CODE: 1007 1008 Gbl_ParseTreeRoot = Op; 1009 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1010 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); 1011 break; 1012 1013 case PARSEOP_DEFINITION_BLOCK: 1014 1015 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 1016 break; 1017 1018 case PARSEOP_OPERATIONREGION: 1019 1020 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 1021 break; 1022 1023 case PARSEOP_OR: 1024 1025 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 1026 break; 1027 1028 default: 1029 1030 /* Nothing to do for other opcodes */ 1031 1032 break; 1033 } 1034 1035 /* Link the new node to its children */ 1036 1037 PrevChild = NULL; 1038 FirstChild = TRUE; 1039 for (i = 0; i < NumChildren; i++) 1040 { 1041 /* Get the next child */ 1042 1043 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 1044 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 1045 1046 /* 1047 * If child is NULL, this means that an optional argument 1048 * was omitted. We must create a placeholder with a special 1049 * opcode (DEFAULT_ARG) so that the code generator will know 1050 * that it must emit the correct default for this argument 1051 */ 1052 if (!Child) 1053 { 1054 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 1055 } 1056 1057 /* Link first child to parent */ 1058 1059 if (FirstChild) 1060 { 1061 FirstChild = FALSE; 1062 Op->Asl.Child = Child; 1063 } 1064 1065 /* Point all children to parent */ 1066 1067 Child->Asl.Parent = Op; 1068 1069 /* Link children in a peer list */ 1070 1071 if (PrevChild) 1072 { 1073 PrevChild->Asl.Next = Child; 1074 }; 1075 1076 /* 1077 * This child might be a list, point all nodes in the list 1078 * to the same parent 1079 */ 1080 while (Child->Asl.Next) 1081 { 1082 Child = Child->Asl.Next; 1083 Child->Asl.Parent = Op; 1084 } 1085 1086 PrevChild = Child; 1087 } 1088 va_end(ap); 1089 1090 DbgPrint (ASL_PARSE_OUTPUT, "\n"); 1091 return (Op); 1092 } 1093 1094 1095 /******************************************************************************* 1096 * 1097 * FUNCTION: TrLinkChildren 1098 * 1099 * PARAMETERS: Op - An existing parse node 1100 * NumChildren - Number of children to follow 1101 * ... - A list of child nodes to link to the new 1102 * node. NumChildren long. 1103 * 1104 * RETURN: The updated (linked) node 1105 * 1106 * DESCRIPTION: Link a group of nodes to an existing parse node 1107 * 1108 ******************************************************************************/ 1109 1110 ACPI_PARSE_OBJECT * 1111 TrLinkChildren ( 1112 ACPI_PARSE_OBJECT *Op, 1113 UINT32 NumChildren, 1114 ...) 1115 { 1116 ACPI_PARSE_OBJECT *Child; 1117 ACPI_PARSE_OBJECT *PrevChild; 1118 va_list ap; 1119 UINT32 i; 1120 BOOLEAN FirstChild; 1121 1122 1123 va_start (ap, NumChildren); 1124 1125 1126 TrSetEndLineNumber (Op); 1127 1128 DbgPrint (ASL_PARSE_OUTPUT, 1129 "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ", 1130 Op->Asl.LineNumber, Op->Asl.EndLine, 1131 Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode)); 1132 1133 switch (Op->Asl.ParseOpcode) 1134 { 1135 case PARSEOP_ASL_CODE: 1136 1137 Gbl_ParseTreeRoot = Op; 1138 Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; 1139 DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->"); 1140 break; 1141 1142 case PARSEOP_DEFINITION_BLOCK: 1143 1144 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 1145 break; 1146 1147 case PARSEOP_OPERATIONREGION: 1148 1149 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 1150 break; 1151 1152 case PARSEOP_OR: 1153 1154 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 1155 break; 1156 1157 default: 1158 1159 /* Nothing to do for other opcodes */ 1160 1161 break; 1162 } 1163 1164 /* Link the new node to it's children */ 1165 1166 PrevChild = NULL; 1167 FirstChild = TRUE; 1168 for (i = 0; i < NumChildren; i++) 1169 { 1170 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 1171 1172 if ((Child == PrevChild) && (Child != NULL)) 1173 { 1174 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child, 1175 "Child node list invalid"); 1176 va_end(ap); 1177 return (Op); 1178 } 1179 1180 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 1181 1182 /* 1183 * If child is NULL, this means that an optional argument 1184 * was omitted. We must create a placeholder with a special 1185 * opcode (DEFAULT_ARG) so that the code generator will know 1186 * that it must emit the correct default for this argument 1187 */ 1188 if (!Child) 1189 { 1190 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 1191 } 1192 1193 /* Link first child to parent */ 1194 1195 if (FirstChild) 1196 { 1197 FirstChild = FALSE; 1198 Op->Asl.Child = Child; 1199 } 1200 1201 /* Point all children to parent */ 1202 1203 Child->Asl.Parent = Op; 1204 1205 /* Link children in a peer list */ 1206 1207 if (PrevChild) 1208 { 1209 PrevChild->Asl.Next = Child; 1210 }; 1211 1212 /* 1213 * This child might be a list, point all nodes in the list 1214 * to the same parent 1215 */ 1216 while (Child->Asl.Next) 1217 { 1218 Child = Child->Asl.Next; 1219 Child->Asl.Parent = Op; 1220 } 1221 1222 PrevChild = Child; 1223 } 1224 1225 va_end(ap); 1226 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 1227 return (Op); 1228 } 1229 1230 1231 /******************************************************************************* 1232 * 1233 * FUNCTION: TrLinkPeerNode 1234 * 1235 * PARAMETERS: Op1 - First peer 1236 * Op2 - Second peer 1237 * 1238 * RETURN: Op1 or the non-null node. 1239 * 1240 * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null. 1241 * 1242 ******************************************************************************/ 1243 1244 ACPI_PARSE_OBJECT * 1245 TrLinkPeerNode ( 1246 ACPI_PARSE_OBJECT *Op1, 1247 ACPI_PARSE_OBJECT *Op2) 1248 { 1249 ACPI_PARSE_OBJECT *Next; 1250 1251 1252 DbgPrint (ASL_PARSE_OUTPUT, 1253 "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n", 1254 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL, 1255 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL); 1256 1257 1258 if ((!Op1) && (!Op2)) 1259 { 1260 DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n"); 1261 return (Op1); 1262 } 1263 1264 /* If one of the nodes is null, just return the non-null node */ 1265 1266 if (!Op2) 1267 { 1268 return (Op1); 1269 } 1270 1271 if (!Op1) 1272 { 1273 return (Op2); 1274 } 1275 1276 if (Op1 == Op2) 1277 { 1278 DbgPrint (ASL_DEBUG_OUTPUT, 1279 "\n************* Internal error, linking node to itself %p\n", 1280 Op1); 1281 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1, 1282 "Linking node to itself"); 1283 return (Op1); 1284 } 1285 1286 Op1->Asl.Parent = Op2->Asl.Parent; 1287 1288 /* 1289 * Op 1 may already have a peer list (such as an IF/ELSE pair), 1290 * so we must walk to the end of the list and attach the new 1291 * peer at the end 1292 */ 1293 Next = Op1; 1294 while (Next->Asl.Next) 1295 { 1296 Next = Next->Asl.Next; 1297 } 1298 1299 Next->Asl.Next = Op2; 1300 return (Op1); 1301 } 1302 1303 1304 /******************************************************************************* 1305 * 1306 * FUNCTION: TrLinkPeerNodes 1307 * 1308 * PARAMETERS: NumPeers - The number of nodes in the list to follow 1309 * ... - A list of nodes to link together as peers 1310 * 1311 * RETURN: The first node in the list (head of the peer list) 1312 * 1313 * DESCRIPTION: Link together an arbitrary number of peer nodes. 1314 * 1315 ******************************************************************************/ 1316 1317 ACPI_PARSE_OBJECT * 1318 TrLinkPeerNodes ( 1319 UINT32 NumPeers, 1320 ...) 1321 { 1322 ACPI_PARSE_OBJECT *This; 1323 ACPI_PARSE_OBJECT *Next; 1324 va_list ap; 1325 UINT32 i; 1326 ACPI_PARSE_OBJECT *Start; 1327 1328 1329 DbgPrint (ASL_PARSE_OUTPUT, 1330 "\nLinkPeerNodes: (%u) ", NumPeers); 1331 1332 va_start (ap, NumPeers); 1333 This = va_arg (ap, ACPI_PARSE_OBJECT *); 1334 Start = This; 1335 1336 /* 1337 * Link all peers 1338 */ 1339 for (i = 0; i < (NumPeers -1); i++) 1340 { 1341 DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This); 1342 1343 while (This->Asl.Next) 1344 { 1345 This = This->Asl.Next; 1346 } 1347 1348 /* Get another peer node */ 1349 1350 Next = va_arg (ap, ACPI_PARSE_OBJECT *); 1351 if (!Next) 1352 { 1353 Next = TrAllocateNode (PARSEOP_DEFAULT_ARG); 1354 } 1355 1356 /* link new node to the current node */ 1357 1358 This->Asl.Next = Next; 1359 This = Next; 1360 } 1361 va_end (ap); 1362 1363 DbgPrint (ASL_PARSE_OUTPUT,"\n"); 1364 return (Start); 1365 } 1366 1367 1368 /******************************************************************************* 1369 * 1370 * FUNCTION: TrLinkChildNode 1371 * 1372 * PARAMETERS: Op1 - Parent node 1373 * Op2 - Op to become a child 1374 * 1375 * RETURN: The parent node 1376 * 1377 * DESCRIPTION: Link two nodes together as a parent and child 1378 * 1379 ******************************************************************************/ 1380 1381 ACPI_PARSE_OBJECT * 1382 TrLinkChildNode ( 1383 ACPI_PARSE_OBJECT *Op1, 1384 ACPI_PARSE_OBJECT *Op2) 1385 { 1386 ACPI_PARSE_OBJECT *Next; 1387 1388 1389 DbgPrint (ASL_PARSE_OUTPUT, 1390 "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n", 1391 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL, 1392 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL); 1393 1394 if (!Op1 || !Op2) 1395 { 1396 return (Op1); 1397 } 1398 1399 Op1->Asl.Child = Op2; 1400 1401 /* Set the child and all peers of the child to point to the parent */ 1402 1403 Next = Op2; 1404 while (Next) 1405 { 1406 Next->Asl.Parent = Op1; 1407 Next = Next->Asl.Next; 1408 } 1409 1410 return (Op1); 1411 } 1412 1413 1414 /******************************************************************************* 1415 * 1416 * FUNCTION: TrWalkParseTree 1417 * 1418 * PARAMETERS: Visitation - Type of walk 1419 * DescendingCallback - Called during tree descent 1420 * AscendingCallback - Called during tree ascent 1421 * Context - To be passed to the callbacks 1422 * 1423 * RETURN: Status from callback(s) 1424 * 1425 * DESCRIPTION: Walk the entire parse tree. 1426 * 1427 ******************************************************************************/ 1428 1429 ACPI_STATUS 1430 TrWalkParseTree ( 1431 ACPI_PARSE_OBJECT *Op, 1432 UINT32 Visitation, 1433 ASL_WALK_CALLBACK DescendingCallback, 1434 ASL_WALK_CALLBACK AscendingCallback, 1435 void *Context) 1436 { 1437 UINT32 Level; 1438 BOOLEAN NodePreviouslyVisited; 1439 ACPI_PARSE_OBJECT *StartOp = Op; 1440 ACPI_STATUS Status; 1441 1442 1443 if (!Gbl_ParseTreeRoot) 1444 { 1445 return (AE_OK); 1446 } 1447 1448 Level = 0; 1449 NodePreviouslyVisited = FALSE; 1450 1451 switch (Visitation) 1452 { 1453 case ASL_WALK_VISIT_DOWNWARD: 1454 1455 while (Op) 1456 { 1457 if (!NodePreviouslyVisited) 1458 { 1459 /* Let the callback process the node. */ 1460 1461 Status = DescendingCallback (Op, Level, Context); 1462 if (ACPI_SUCCESS (Status)) 1463 { 1464 /* Visit children first, once */ 1465 1466 if (Op->Asl.Child) 1467 { 1468 Level++; 1469 Op = Op->Asl.Child; 1470 continue; 1471 } 1472 } 1473 else if (Status != AE_CTRL_DEPTH) 1474 { 1475 /* Exit immediately on any error */ 1476 1477 return (Status); 1478 } 1479 } 1480 1481 /* Terminate walk at start op */ 1482 1483 if (Op == StartOp) 1484 { 1485 break; 1486 } 1487 1488 /* No more children, visit peers */ 1489 1490 if (Op->Asl.Next) 1491 { 1492 Op = Op->Asl.Next; 1493 NodePreviouslyVisited = FALSE; 1494 } 1495 else 1496 { 1497 /* No children or peers, re-visit parent */ 1498 1499 if (Level != 0 ) 1500 { 1501 Level--; 1502 } 1503 Op = Op->Asl.Parent; 1504 NodePreviouslyVisited = TRUE; 1505 } 1506 } 1507 break; 1508 1509 case ASL_WALK_VISIT_UPWARD: 1510 1511 while (Op) 1512 { 1513 /* Visit leaf node (no children) or parent node on return trip */ 1514 1515 if ((!Op->Asl.Child) || 1516 (NodePreviouslyVisited)) 1517 { 1518 /* Let the callback process the node. */ 1519 1520 Status = AscendingCallback (Op, Level, Context); 1521 if (ACPI_FAILURE (Status)) 1522 { 1523 return (Status); 1524 } 1525 } 1526 else 1527 { 1528 /* Visit children first, once */ 1529 1530 Level++; 1531 Op = Op->Asl.Child; 1532 continue; 1533 } 1534 1535 /* Terminate walk at start op */ 1536 1537 if (Op == StartOp) 1538 { 1539 break; 1540 } 1541 1542 /* No more children, visit peers */ 1543 1544 if (Op->Asl.Next) 1545 { 1546 Op = Op->Asl.Next; 1547 NodePreviouslyVisited = FALSE; 1548 } 1549 else 1550 { 1551 /* No children or peers, re-visit parent */ 1552 1553 if (Level != 0 ) 1554 { 1555 Level--; 1556 } 1557 Op = Op->Asl.Parent; 1558 NodePreviouslyVisited = TRUE; 1559 } 1560 } 1561 break; 1562 1563 case ASL_WALK_VISIT_TWICE: 1564 1565 while (Op) 1566 { 1567 if (NodePreviouslyVisited) 1568 { 1569 Status = AscendingCallback (Op, Level, Context); 1570 if (ACPI_FAILURE (Status)) 1571 { 1572 return (Status); 1573 } 1574 } 1575 else 1576 { 1577 /* Let the callback process the node. */ 1578 1579 Status = DescendingCallback (Op, Level, Context); 1580 if (ACPI_SUCCESS (Status)) 1581 { 1582 /* Visit children first, once */ 1583 1584 if (Op->Asl.Child) 1585 { 1586 Level++; 1587 Op = Op->Asl.Child; 1588 continue; 1589 } 1590 } 1591 else if (Status != AE_CTRL_DEPTH) 1592 { 1593 /* Exit immediately on any error */ 1594 1595 return (Status); 1596 } 1597 } 1598 1599 /* Terminate walk at start op */ 1600 1601 if (Op == StartOp) 1602 { 1603 break; 1604 } 1605 1606 /* No more children, visit peers */ 1607 1608 if (Op->Asl.Next) 1609 { 1610 Op = Op->Asl.Next; 1611 NodePreviouslyVisited = FALSE; 1612 } 1613 else 1614 { 1615 /* No children or peers, re-visit parent */ 1616 1617 if (Level != 0 ) 1618 { 1619 Level--; 1620 } 1621 Op = Op->Asl.Parent; 1622 NodePreviouslyVisited = TRUE; 1623 } 1624 } 1625 break; 1626 1627 default: 1628 /* No other types supported */ 1629 break; 1630 } 1631 1632 /* If we get here, the walk completed with no errors */ 1633 1634 return (AE_OK); 1635 } 1636