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