1 /****************************************************************************** 2 * 3 * Module Name: asltree - parse tree management 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 45 #include <contrib/dev/acpica/compiler/aslcompiler.h> 46 #include "aslcompiler.y.h" 47 #include <contrib/dev/acpica/include/acapps.h> 48 #include <time.h> 49 50 #define _COMPONENT ACPI_COMPILER 51 ACPI_MODULE_NAME ("asltree") 52 53 /* Local prototypes */ 54 55 static ACPI_PARSE_OBJECT * 56 TrGetNextNode ( 57 void); 58 59 static char * 60 TrGetNodeFlagName ( 61 UINT32 Flags); 62 63 64 /******************************************************************************* 65 * 66 * FUNCTION: TrGetNextNode 67 * 68 * PARAMETERS: None 69 * 70 * RETURN: New parse node. Aborts on allocation failure 71 * 72 * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local 73 * dynamic memory manager for performance reasons (This has a 74 * major impact on the speed of the compiler.) 75 * 76 ******************************************************************************/ 77 78 static ACPI_PARSE_OBJECT * 79 TrGetNextNode ( 80 void) 81 { 82 83 if (Gbl_NodeCacheNext >= Gbl_NodeCacheLast) 84 { 85 Gbl_NodeCacheNext = UtLocalCalloc (sizeof (ACPI_PARSE_OBJECT) * 86 ASL_NODE_CACHE_SIZE); 87 Gbl_NodeCacheLast = Gbl_NodeCacheNext + ASL_NODE_CACHE_SIZE; 88 } 89 90 return (Gbl_NodeCacheNext++); 91 } 92 93 94 /******************************************************************************* 95 * 96 * FUNCTION: TrAllocateNode 97 * 98 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 99 * 100 * RETURN: New parse node. Aborts on allocation failure 101 * 102 * DESCRIPTION: Allocate and initialize a new parse node for the parse tree 103 * 104 ******************************************************************************/ 105 106 ACPI_PARSE_OBJECT * 107 TrAllocateNode ( 108 UINT32 ParseOpcode) 109 { 110 ACPI_PARSE_OBJECT *Op; 111 112 113 Op = TrGetNextNode (); 114 115 Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 116 Op->Asl.Filename = Gbl_Files[ASL_FILE_INPUT].Filename; 117 Op->Asl.LineNumber = Gbl_CurrentLineNumber; 118 Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber; 119 Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset; 120 Op->Asl.Column = Gbl_CurrentColumn; 121 122 UtSetParseOpName (Op); 123 return (Op); 124 } 125 126 127 /******************************************************************************* 128 * 129 * FUNCTION: TrReleaseNode 130 * 131 * PARAMETERS: Op - Op to be released 132 * 133 * RETURN: None 134 * 135 * DESCRIPTION: "release" a node. In truth, nothing is done since the node 136 * is part of a larger buffer 137 * 138 ******************************************************************************/ 139 140 void 141 TrReleaseNode ( 142 ACPI_PARSE_OBJECT *Op) 143 { 144 145 return; 146 } 147 148 149 /******************************************************************************* 150 * 151 * FUNCTION: TrUpdateNode 152 * 153 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 154 * Op - An existing parse node 155 * 156 * RETURN: The updated node 157 * 158 * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to 159 * change an opcode to DEFAULT_ARG so that the node is ignored 160 * during the code generation. Also used to set generic integers 161 * to a specific size (8, 16, 32, or 64 bits) 162 * 163 ******************************************************************************/ 164 165 ACPI_PARSE_OBJECT * 166 TrUpdateNode ( 167 UINT32 ParseOpcode, 168 ACPI_PARSE_OBJECT *Op) 169 { 170 171 if (!Op) 172 { 173 return (NULL); 174 } 175 176 DbgPrint (ASL_PARSE_OUTPUT, 177 "\nUpdateNode: Old - %s, New - %s\n\n", 178 UtGetOpName (Op->Asl.ParseOpcode), 179 UtGetOpName (ParseOpcode)); 180 181 /* Assign new opcode and name */ 182 183 if (Op->Asl.ParseOpcode == PARSEOP_ONES) 184 { 185 switch (ParseOpcode) 186 { 187 case PARSEOP_BYTECONST: 188 Op->Asl.Value.Integer = ACPI_UINT8_MAX; 189 break; 190 191 case PARSEOP_WORDCONST: 192 Op->Asl.Value.Integer = ACPI_UINT16_MAX; 193 break; 194 195 case PARSEOP_DWORDCONST: 196 Op->Asl.Value.Integer = ACPI_UINT32_MAX; 197 break; 198 199 /* Don't need to do the QWORD case */ 200 201 default: 202 /* Don't care about others */ 203 break; 204 } 205 } 206 207 Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 208 UtSetParseOpName (Op); 209 210 /* 211 * For the BYTE, WORD, and DWORD constants, make sure that the integer 212 * that was passed in will actually fit into the data type 213 */ 214 switch (ParseOpcode) 215 { 216 case PARSEOP_BYTECONST: 217 UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX); 218 Op->Asl.Value.Integer &= ACPI_UINT8_MAX; 219 break; 220 221 case PARSEOP_WORDCONST: 222 UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX); 223 Op->Asl.Value.Integer &= ACPI_UINT16_MAX; 224 break; 225 226 case PARSEOP_DWORDCONST: 227 UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX); 228 Op->Asl.Value.Integer &= ACPI_UINT32_MAX; 229 break; 230 231 default: 232 /* Don't care about others, don't need to check QWORD */ 233 break; 234 } 235 236 return (Op); 237 } 238 239 240 /******************************************************************************* 241 * 242 * FUNCTION: TrGetNodeFlagName 243 * 244 * PARAMETERS: Flags - Flags word to be decoded 245 * 246 * RETURN: Name string. Always returns a valid string pointer. 247 * 248 * DESCRIPTION: Decode a flags word 249 * 250 ******************************************************************************/ 251 252 static char * 253 TrGetNodeFlagName ( 254 UINT32 Flags) 255 { 256 257 switch (Flags) 258 { 259 case NODE_VISITED: 260 return ("NODE_VISITED"); 261 262 case NODE_AML_PACKAGE: 263 return ("NODE_AML_PACKAGE"); 264 265 case NODE_IS_TARGET: 266 return ("NODE_IS_TARGET"); 267 268 case NODE_IS_RESOURCE_DESC: 269 return ("NODE_IS_RESOURCE_DESC"); 270 271 case NODE_IS_RESOURCE_FIELD: 272 return ("NODE_IS_RESOURCE_FIELD"); 273 274 case NODE_HAS_NO_EXIT: 275 return ("NODE_HAS_NO_EXIT"); 276 277 case NODE_IF_HAS_NO_EXIT: 278 return ("NODE_IF_HAS_NO_EXIT"); 279 280 case NODE_NAME_INTERNALIZED: 281 return ("NODE_NAME_INTERNALIZED"); 282 283 case NODE_METHOD_NO_RETVAL: 284 return ("NODE_METHOD_NO_RETVAL"); 285 286 case NODE_METHOD_SOME_NO_RETVAL: 287 return ("NODE_METHOD_SOME_NO_RETVAL"); 288 289 case NODE_RESULT_NOT_USED: 290 return ("NODE_RESULT_NOT_USED"); 291 292 case NODE_METHOD_TYPED: 293 return ("NODE_METHOD_TYPED"); 294 295 case NODE_COMPILE_TIME_CONST: 296 return ("NODE_COMPILE_TIME_CONST"); 297 298 case NODE_IS_TERM_ARG: 299 return ("NODE_IS_TERM_ARG"); 300 301 case NODE_WAS_ONES_OP: 302 return ("NODE_WAS_ONES_OP"); 303 304 case NODE_IS_NAME_DECLARATION: 305 return ("NODE_IS_NAME_DECLARATION"); 306 307 default: 308 return ("Multiple Flags (or unknown flag) set"); 309 } 310 } 311 312 313 /******************************************************************************* 314 * 315 * FUNCTION: TrSetNodeFlags 316 * 317 * PARAMETERS: Op - An existing parse node 318 * Flags - New flags word 319 * 320 * RETURN: The updated parser op 321 * 322 * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set 323 * 324 ******************************************************************************/ 325 326 ACPI_PARSE_OBJECT * 327 TrSetNodeFlags ( 328 ACPI_PARSE_OBJECT *Op, 329 UINT32 Flags) 330 { 331 332 DbgPrint (ASL_PARSE_OUTPUT, 333 "\nSetNodeFlags: Op %p, %8.8X %s\n\n", Op, Flags, 334 TrGetNodeFlagName (Flags)); 335 336 if (!Op) 337 { 338 return (NULL); 339 } 340 341 Op->Asl.CompileFlags |= Flags; 342 return (Op); 343 } 344 345 346 /******************************************************************************* 347 * 348 * FUNCTION: TrSetNodeAmlLength 349 * 350 * PARAMETERS: Op - An existing parse node 351 * Length - AML Length 352 * 353 * RETURN: The updated parser op 354 * 355 * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate 356 * the presence of a node that must be reduced to a fixed length 357 * constant. 358 * 359 ******************************************************************************/ 360 361 ACPI_PARSE_OBJECT * 362 TrSetNodeAmlLength ( 363 ACPI_PARSE_OBJECT *Op, 364 UINT32 Length) 365 { 366 367 DbgPrint (ASL_PARSE_OUTPUT, 368 "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length); 369 370 if (!Op) 371 { 372 return (NULL); 373 } 374 375 Op->Asl.AmlLength = Length; 376 return (Op); 377 } 378 379 380 /******************************************************************************* 381 * 382 * FUNCTION: TrSetEndLineNumber 383 * 384 * PARAMETERS: Op - An existing parse node 385 * 386 * RETURN: None. 387 * 388 * DESCRIPTION: Set the ending line numbers (file line and logical line) of a 389 * parse node to the current line numbers. 390 * 391 ******************************************************************************/ 392 393 void 394 TrSetEndLineNumber ( 395 ACPI_PARSE_OBJECT *Op) 396 { 397 398 /* If the end line # is already set, just return */ 399 400 if (Op->Asl.EndLine) 401 { 402 return; 403 } 404 405 Op->Asl.EndLine = Gbl_CurrentLineNumber; 406 Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber; 407 } 408 409 410 /******************************************************************************* 411 * 412 * FUNCTION: TrCreateLeafNode 413 * 414 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 415 * 416 * RETURN: Pointer to the new node. Aborts on allocation failure 417 * 418 * DESCRIPTION: Create a simple leaf node (no children or peers, and no value 419 * assigned to the node) 420 * 421 ******************************************************************************/ 422 423 ACPI_PARSE_OBJECT * 424 TrCreateLeafNode ( 425 UINT32 ParseOpcode) 426 { 427 ACPI_PARSE_OBJECT *Op; 428 429 430 Op = TrAllocateNode (ParseOpcode); 431 432 DbgPrint (ASL_PARSE_OUTPUT, 433 "\nCreateLeafNode Ln/Col %u/%u NewNode %p Op %s\n\n", 434 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode)); 435 436 return (Op); 437 } 438 439 440 /******************************************************************************* 441 * 442 * FUNCTION: TrCreateConstantLeafNode 443 * 444 * PARAMETERS: ParseOpcode - The constant opcode 445 * 446 * RETURN: Pointer to the new node. Aborts on allocation failure 447 * 448 * DESCRIPTION: Create a leaf node (no children or peers) for one of the 449 * special constants - __LINE__, __FILE__, and __DATE__. 450 * 451 * Note: An implemenation of __FUNC__ cannot happen here because we don't 452 * have a full parse tree at this time and cannot find the parent control 453 * method. If it is ever needed, __FUNC__ must be implemented later, after 454 * the parse tree has been fully constructed. 455 * 456 ******************************************************************************/ 457 458 ACPI_PARSE_OBJECT * 459 TrCreateConstantLeafNode ( 460 UINT32 ParseOpcode) 461 { 462 ACPI_PARSE_OBJECT *Op = NULL; 463 time_t CurrentTime; 464 char *StaticTimeString; 465 char *TimeString; 466 char *Path; 467 char *Filename; 468 469 470 switch (ParseOpcode) 471 { 472 case PARSEOP___LINE__: 473 Op = TrAllocateNode (PARSEOP_INTEGER); 474 Op->Asl.Value.Integer = Op->Asl.LineNumber; 475 break; 476 477 case PARSEOP___PATH__: 478 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 479 480 /* Op.Asl.Filename contains the full pathname to the file */ 481 482 Op->Asl.Value.String = Op->Asl.Filename; 483 break; 484 485 case PARSEOP___FILE__: 486 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 487 488 /* Get the simple filename from the full path */ 489 490 FlSplitInputPathname (Op->Asl.Filename, &Path, &Filename); 491 ACPI_FREE (Path); 492 Op->Asl.Value.String = Filename; 493 break; 494 495 case PARSEOP___DATE__: 496 Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 497 498 /* Get a copy of the current time */ 499 500 CurrentTime = time (NULL); 501 StaticTimeString = ctime (&CurrentTime); 502 TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1); 503 strcpy (TimeString, StaticTimeString); 504 505 TimeString[strlen(TimeString) -1] = 0; /* Remove trailing newline */ 506 Op->Asl.Value.String = TimeString; 507 break; 508 509 default: /* This would be an internal error */ 510 return (NULL); 511 } 512 513 DbgPrint (ASL_PARSE_OUTPUT, 514 "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p Op %s Value %8.8X%8.8X ", 515 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode), 516 ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer)); 517 return (Op); 518 } 519 520 521 /******************************************************************************* 522 * 523 * FUNCTION: TrCreateValuedLeafNode 524 * 525 * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 526 * Value - Value to be assigned to the node 527 * 528 * RETURN: Pointer to the new node. Aborts on allocation failure 529 * 530 * DESCRIPTION: Create a leaf node (no children or peers) with a value 531 * assigned to it 532 * 533 ******************************************************************************/ 534 535 ACPI_PARSE_OBJECT * 536 TrCreateValuedLeafNode ( 537 UINT32 ParseOpcode, 538 UINT64 Value) 539 { 540 ACPI_PARSE_OBJECT *Op; 541 542 543 Op = TrAllocateNode (ParseOpcode); 544 545 DbgPrint (ASL_PARSE_OUTPUT, 546 "\nCreateValuedLeafNode Ln/Col %u/%u NewNode %p Op %s Value %8.8X%8.8X ", 547 Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode), 548 ACPI_FORMAT_UINT64 (Value)); 549 Op->Asl.Value.Integer = Value; 550 551 switch (ParseOpcode) 552 { 553 case PARSEOP_STRING_LITERAL: 554 DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value); 555 break; 556 557 case PARSEOP_NAMESEG: 558 DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value); 559 break; 560 561 case PARSEOP_NAMESTRING: 562 DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value); 563 break; 564 565 case PARSEOP_EISAID: 566 DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value); 567 break; 568 569 case PARSEOP_METHOD: 570 DbgPrint (ASL_PARSE_OUTPUT, "METHOD"); 571 break; 572 573 case PARSEOP_INTEGER: 574 DbgPrint (ASL_PARSE_OUTPUT, "INTEGER"); 575 break; 576 577 default: 578 break; 579 } 580 581 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 582 return (Op); 583 } 584 585 586 /******************************************************************************* 587 * 588 * FUNCTION: TrCreateNode 589 * 590 * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 591 * NumChildren - Number of children to follow 592 * ... - A list of child nodes to link to the new 593 * node. NumChildren long. 594 * 595 * RETURN: Pointer to the new node. Aborts on allocation failure 596 * 597 * DESCRIPTION: Create a new parse node and link together a list of child 598 * nodes underneath the new node. 599 * 600 ******************************************************************************/ 601 602 ACPI_PARSE_OBJECT * 603 TrCreateNode ( 604 UINT32 ParseOpcode, 605 UINT32 NumChildren, 606 ...) 607 { 608 ACPI_PARSE_OBJECT *Op; 609 ACPI_PARSE_OBJECT *Child; 610 ACPI_PARSE_OBJECT *PrevChild; 611 va_list ap; 612 UINT32 i; 613 BOOLEAN FirstChild; 614 615 616 va_start (ap, NumChildren); 617 618 /* Allocate one new node */ 619 620 Op = TrAllocateNode (ParseOpcode); 621 622 DbgPrint (ASL_PARSE_OUTPUT, 623 "\nCreateNode Ln/Col %u/%u NewParent %p Child %u Op %s ", 624 Op->Asl.LineNumber, Op->Asl.Column, Op, NumChildren, UtGetOpName(ParseOpcode)); 625 626 /* Some extra debug output based on the parse opcode */ 627 628 switch (ParseOpcode) 629 { 630 case PARSEOP_DEFINITIONBLOCK: 631 RootNode = Op; 632 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 633 break; 634 635 case PARSEOP_OPERATIONREGION: 636 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 637 break; 638 639 case PARSEOP_OR: 640 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 641 break; 642 643 default: 644 /* Nothing to do for other opcodes */ 645 break; 646 } 647 648 /* Link the new node to its children */ 649 650 PrevChild = NULL; 651 FirstChild = TRUE; 652 for (i = 0; i < NumChildren; i++) 653 { 654 /* Get the next child */ 655 656 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 657 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 658 659 /* 660 * If child is NULL, this means that an optional argument 661 * was omitted. We must create a placeholder with a special 662 * opcode (DEFAULT_ARG) so that the code generator will know 663 * that it must emit the correct default for this argument 664 */ 665 if (!Child) 666 { 667 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 668 } 669 670 /* Link first child to parent */ 671 672 if (FirstChild) 673 { 674 FirstChild = FALSE; 675 Op->Asl.Child = Child; 676 } 677 678 /* Point all children to parent */ 679 680 Child->Asl.Parent = Op; 681 682 /* Link children in a peer list */ 683 684 if (PrevChild) 685 { 686 PrevChild->Asl.Next = Child; 687 }; 688 689 /* 690 * This child might be a list, point all nodes in the list 691 * to the same parent 692 */ 693 while (Child->Asl.Next) 694 { 695 Child = Child->Asl.Next; 696 Child->Asl.Parent = Op; 697 } 698 699 PrevChild = Child; 700 } 701 va_end(ap); 702 703 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 704 return (Op); 705 } 706 707 708 /******************************************************************************* 709 * 710 * FUNCTION: TrLinkChildren 711 * 712 * PARAMETERS: Op - An existing parse node 713 * NumChildren - Number of children to follow 714 * ... - A list of child nodes to link to the new 715 * node. NumChildren long. 716 * 717 * RETURN: The updated (linked) node 718 * 719 * DESCRIPTION: Link a group of nodes to an existing parse node 720 * 721 ******************************************************************************/ 722 723 ACPI_PARSE_OBJECT * 724 TrLinkChildren ( 725 ACPI_PARSE_OBJECT *Op, 726 UINT32 NumChildren, 727 ...) 728 { 729 ACPI_PARSE_OBJECT *Child; 730 ACPI_PARSE_OBJECT *PrevChild; 731 va_list ap; 732 UINT32 i; 733 BOOLEAN FirstChild; 734 735 736 va_start (ap, NumChildren); 737 738 739 TrSetEndLineNumber (Op); 740 741 DbgPrint (ASL_PARSE_OUTPUT, 742 "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ", 743 Op->Asl.LineNumber, Op->Asl.EndLine, 744 Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode)); 745 746 switch (Op->Asl.ParseOpcode) 747 { 748 case PARSEOP_DEFINITIONBLOCK: 749 RootNode = Op; 750 DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 751 break; 752 753 case PARSEOP_OPERATIONREGION: 754 DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 755 break; 756 757 case PARSEOP_OR: 758 DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 759 break; 760 761 default: 762 /* Nothing to do for other opcodes */ 763 break; 764 } 765 766 /* Link the new node to it's children */ 767 768 PrevChild = NULL; 769 FirstChild = TRUE; 770 for (i = 0; i < NumChildren; i++) 771 { 772 Child = va_arg (ap, ACPI_PARSE_OBJECT *); 773 774 if ((Child == PrevChild) && (Child != NULL)) 775 { 776 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child, 777 "Child node list invalid"); 778 return (Op); 779 } 780 781 DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 782 783 /* 784 * If child is NULL, this means that an optional argument 785 * was omitted. We must create a placeholder with a special 786 * opcode (DEFAULT_ARG) so that the code generator will know 787 * that it must emit the correct default for this argument 788 */ 789 if (!Child) 790 { 791 Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 792 } 793 794 /* Link first child to parent */ 795 796 if (FirstChild) 797 { 798 FirstChild = FALSE; 799 Op->Asl.Child = Child; 800 } 801 802 /* Point all children to parent */ 803 804 Child->Asl.Parent = Op; 805 806 /* Link children in a peer list */ 807 808 if (PrevChild) 809 { 810 PrevChild->Asl.Next = Child; 811 }; 812 813 /* 814 * This child might be a list, point all nodes in the list 815 * to the same parent 816 */ 817 while (Child->Asl.Next) 818 { 819 Child = Child->Asl.Next; 820 Child->Asl.Parent = Op; 821 } 822 PrevChild = Child; 823 } 824 va_end(ap); 825 826 DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 827 return (Op); 828 } 829 830 831 /******************************************************************************* 832 * 833 * FUNCTION: TrLinkPeerNode 834 * 835 * PARAMETERS: Op1 - First peer 836 * Op2 - Second peer 837 * 838 * RETURN: Op1 or the non-null node. 839 * 840 * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null. 841 * 842 ******************************************************************************/ 843 844 ACPI_PARSE_OBJECT * 845 TrLinkPeerNode ( 846 ACPI_PARSE_OBJECT *Op1, 847 ACPI_PARSE_OBJECT *Op2) 848 { 849 ACPI_PARSE_OBJECT *Next; 850 851 852 DbgPrint (ASL_PARSE_OUTPUT, 853 "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n\n", 854 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL, 855 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL); 856 857 858 if ((!Op1) && (!Op2)) 859 { 860 DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n"); 861 return (Op1); 862 } 863 864 /* If one of the nodes is null, just return the non-null node */ 865 866 if (!Op2) 867 { 868 return (Op1); 869 } 870 871 if (!Op1) 872 { 873 return (Op2); 874 } 875 876 if (Op1 == Op2) 877 { 878 DbgPrint (ASL_DEBUG_OUTPUT, 879 "\n\n************* Internal error, linking node to itself %p\n\n\n", 880 Op1); 881 AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1, 882 "Linking node to itself"); 883 return (Op1); 884 } 885 886 Op1->Asl.Parent = Op2->Asl.Parent; 887 888 /* 889 * Op 1 may already have a peer list (such as an IF/ELSE pair), 890 * so we must walk to the end of the list and attach the new 891 * peer at the end 892 */ 893 Next = Op1; 894 while (Next->Asl.Next) 895 { 896 Next = Next->Asl.Next; 897 } 898 899 Next->Asl.Next = Op2; 900 return (Op1); 901 } 902 903 904 /******************************************************************************* 905 * 906 * FUNCTION: TrLinkPeerNodes 907 * 908 * PARAMETERS: NumPeers - The number of nodes in the list to follow 909 * ... - A list of nodes to link together as peers 910 * 911 * RETURN: The first node in the list (head of the peer list) 912 * 913 * DESCRIPTION: Link together an arbitrary number of peer nodes. 914 * 915 ******************************************************************************/ 916 917 ACPI_PARSE_OBJECT * 918 TrLinkPeerNodes ( 919 UINT32 NumPeers, 920 ...) 921 { 922 ACPI_PARSE_OBJECT *This; 923 ACPI_PARSE_OBJECT *Next; 924 va_list ap; 925 UINT32 i; 926 ACPI_PARSE_OBJECT *Start; 927 928 929 DbgPrint (ASL_PARSE_OUTPUT, 930 "\nLinkPeerNodes: (%u) ", NumPeers); 931 932 va_start (ap, NumPeers); 933 This = va_arg (ap, ACPI_PARSE_OBJECT *); 934 Start = This; 935 936 /* 937 * Link all peers 938 */ 939 for (i = 0; i < (NumPeers -1); i++) 940 { 941 DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This); 942 943 while (This->Asl.Next) 944 { 945 This = This->Asl.Next; 946 } 947 948 /* Get another peer node */ 949 950 Next = va_arg (ap, ACPI_PARSE_OBJECT *); 951 if (!Next) 952 { 953 Next = TrAllocateNode (PARSEOP_DEFAULT_ARG); 954 } 955 956 /* link new node to the current node */ 957 958 This->Asl.Next = Next; 959 This = Next; 960 } 961 va_end (ap); 962 963 DbgPrint (ASL_PARSE_OUTPUT,"\n\n"); 964 return (Start); 965 } 966 967 968 /******************************************************************************* 969 * 970 * FUNCTION: TrLinkChildNode 971 * 972 * PARAMETERS: Op1 - Parent node 973 * Op2 - Op to become a child 974 * 975 * RETURN: The parent node 976 * 977 * DESCRIPTION: Link two nodes together as a parent and child 978 * 979 ******************************************************************************/ 980 981 ACPI_PARSE_OBJECT * 982 TrLinkChildNode ( 983 ACPI_PARSE_OBJECT *Op1, 984 ACPI_PARSE_OBJECT *Op2) 985 { 986 ACPI_PARSE_OBJECT *Next; 987 988 989 DbgPrint (ASL_PARSE_OUTPUT, 990 "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n\n", 991 Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL, 992 Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL); 993 994 if (!Op1 || !Op2) 995 { 996 return (Op1); 997 } 998 999 Op1->Asl.Child = Op2; 1000 1001 /* Set the child and all peers of the child to point to the parent */ 1002 1003 Next = Op2; 1004 while (Next) 1005 { 1006 Next->Asl.Parent = Op1; 1007 Next = Next->Asl.Next; 1008 } 1009 1010 return (Op1); 1011 } 1012 1013 1014 /******************************************************************************* 1015 * 1016 * FUNCTION: TrWalkParseTree 1017 * 1018 * PARAMETERS: Visitation - Type of walk 1019 * DescendingCallback - Called during tree descent 1020 * AscendingCallback - Called during tree ascent 1021 * Context - To be passed to the callbacks 1022 * 1023 * RETURN: Status from callback(s) 1024 * 1025 * DESCRIPTION: Walk the entire parse tree. 1026 * 1027 ******************************************************************************/ 1028 1029 ACPI_STATUS 1030 TrWalkParseTree ( 1031 ACPI_PARSE_OBJECT *Op, 1032 UINT32 Visitation, 1033 ASL_WALK_CALLBACK DescendingCallback, 1034 ASL_WALK_CALLBACK AscendingCallback, 1035 void *Context) 1036 { 1037 UINT32 Level; 1038 BOOLEAN NodePreviouslyVisited; 1039 ACPI_PARSE_OBJECT *StartOp = Op; 1040 ACPI_STATUS Status; 1041 1042 1043 if (!RootNode) 1044 { 1045 return (AE_OK); 1046 } 1047 1048 Level = 0; 1049 NodePreviouslyVisited = FALSE; 1050 1051 switch (Visitation) 1052 { 1053 case ASL_WALK_VISIT_DOWNWARD: 1054 1055 while (Op) 1056 { 1057 if (!NodePreviouslyVisited) 1058 { 1059 /* Let the callback process the node. */ 1060 1061 Status = DescendingCallback (Op, Level, Context); 1062 if (ACPI_SUCCESS (Status)) 1063 { 1064 /* Visit children first, once */ 1065 1066 if (Op->Asl.Child) 1067 { 1068 Level++; 1069 Op = Op->Asl.Child; 1070 continue; 1071 } 1072 } 1073 else if (Status != AE_CTRL_DEPTH) 1074 { 1075 /* Exit immediately on any error */ 1076 1077 return (Status); 1078 } 1079 } 1080 1081 /* Terminate walk at start op */ 1082 1083 if (Op == StartOp) 1084 { 1085 break; 1086 } 1087 1088 /* No more children, visit peers */ 1089 1090 if (Op->Asl.Next) 1091 { 1092 Op = Op->Asl.Next; 1093 NodePreviouslyVisited = FALSE; 1094 } 1095 else 1096 { 1097 /* No children or peers, re-visit parent */ 1098 1099 if (Level != 0 ) 1100 { 1101 Level--; 1102 } 1103 Op = Op->Asl.Parent; 1104 NodePreviouslyVisited = TRUE; 1105 } 1106 } 1107 break; 1108 1109 1110 case ASL_WALK_VISIT_UPWARD: 1111 1112 while (Op) 1113 { 1114 /* Visit leaf node (no children) or parent node on return trip */ 1115 1116 if ((!Op->Asl.Child) || 1117 (NodePreviouslyVisited)) 1118 { 1119 /* Let the callback process the node. */ 1120 1121 Status = AscendingCallback (Op, Level, Context); 1122 if (ACPI_FAILURE (Status)) 1123 { 1124 return (Status); 1125 } 1126 } 1127 else 1128 { 1129 /* Visit children first, once */ 1130 1131 Level++; 1132 Op = Op->Asl.Child; 1133 continue; 1134 } 1135 1136 /* Terminate walk at start op */ 1137 1138 if (Op == StartOp) 1139 { 1140 break; 1141 } 1142 1143 /* No more children, visit peers */ 1144 1145 if (Op->Asl.Next) 1146 { 1147 Op = Op->Asl.Next; 1148 NodePreviouslyVisited = FALSE; 1149 } 1150 else 1151 { 1152 /* No children or peers, re-visit parent */ 1153 1154 if (Level != 0 ) 1155 { 1156 Level--; 1157 } 1158 Op = Op->Asl.Parent; 1159 NodePreviouslyVisited = TRUE; 1160 } 1161 } 1162 break; 1163 1164 1165 case ASL_WALK_VISIT_TWICE: 1166 1167 while (Op) 1168 { 1169 if (NodePreviouslyVisited) 1170 { 1171 Status = AscendingCallback (Op, Level, Context); 1172 if (ACPI_FAILURE (Status)) 1173 { 1174 return (Status); 1175 } 1176 } 1177 else 1178 { 1179 /* Let the callback process the node. */ 1180 1181 Status = DescendingCallback (Op, Level, Context); 1182 if (ACPI_SUCCESS (Status)) 1183 { 1184 /* Visit children first, once */ 1185 1186 if (Op->Asl.Child) 1187 { 1188 Level++; 1189 Op = Op->Asl.Child; 1190 continue; 1191 } 1192 } 1193 else if (Status != AE_CTRL_DEPTH) 1194 { 1195 /* Exit immediately on any error */ 1196 1197 return (Status); 1198 } 1199 } 1200 1201 /* Terminate walk at start op */ 1202 1203 if (Op == StartOp) 1204 { 1205 break; 1206 } 1207 1208 /* No more children, visit peers */ 1209 1210 if (Op->Asl.Next) 1211 { 1212 Op = Op->Asl.Next; 1213 NodePreviouslyVisited = FALSE; 1214 } 1215 else 1216 { 1217 /* No children or peers, re-visit parent */ 1218 1219 if (Level != 0 ) 1220 { 1221 Level--; 1222 } 1223 Op = Op->Asl.Parent; 1224 NodePreviouslyVisited = TRUE; 1225 } 1226 } 1227 break; 1228 1229 default: 1230 /* No other types supported */ 1231 break; 1232 } 1233 1234 /* If we get here, the walk completed with no errors */ 1235 1236 return (AE_OK); 1237 } 1238