1 /****************************************************************************** 2 * 3 * Module Name: asltransform - Parse tree transforms 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2019, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include "aslcompiler.h" 45 #include "aslcompiler.y.h" 46 47 #define _COMPONENT ACPI_COMPILER 48 ACPI_MODULE_NAME ("asltransform") 49 50 /* Local prototypes */ 51 52 static void 53 TrTransformSubtree ( 54 ACPI_PARSE_OBJECT *Op); 55 56 static char * 57 TrAmlGetNextTempName ( 58 ACPI_PARSE_OBJECT *Op, 59 UINT8 *TempCount); 60 61 static void 62 TrAmlInitLineNumbers ( 63 ACPI_PARSE_OBJECT *Op, 64 ACPI_PARSE_OBJECT *Neighbor); 65 66 static void 67 TrAmlInitNode ( 68 ACPI_PARSE_OBJECT *Op, 69 UINT16 ParseOpcode); 70 71 static void 72 TrAmlSetSubtreeParent ( 73 ACPI_PARSE_OBJECT *Op, 74 ACPI_PARSE_OBJECT *Parent); 75 76 static void 77 TrAmlInsertPeer ( 78 ACPI_PARSE_OBJECT *Op, 79 ACPI_PARSE_OBJECT *NewPeer); 80 81 static void 82 TrDoDefinitionBlock ( 83 ACPI_PARSE_OBJECT *Op); 84 85 static void 86 TrDoSwitch ( 87 ACPI_PARSE_OBJECT *StartNode); 88 89 90 /******************************************************************************* 91 * 92 * FUNCTION: TrAmlGetNextTempName 93 * 94 * PARAMETERS: Op - Current parse op 95 * TempCount - Current temporary counter. Was originally 96 * per-module; Currently per method, could be 97 * expanded to per-scope. 98 * 99 * RETURN: A pointer to name (allocated here). 100 * 101 * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are 102 * reserved for use by the ASL compiler. (_T_0 through _T_Z) 103 * 104 ******************************************************************************/ 105 106 static char * 107 TrAmlGetNextTempName ( 108 ACPI_PARSE_OBJECT *Op, 109 UINT8 *TempCount) 110 { 111 char *TempName; 112 113 114 if (*TempCount >= (10 + 26)) /* 0-35 valid: 0-9 and A-Z for TempName[3] */ 115 { 116 /* Too many temps */ 117 118 AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL); 119 return (NULL); 120 } 121 122 TempName = UtLocalCalloc (5); 123 124 if (*TempCount < 10) /* 0-9 */ 125 { 126 TempName[3] = (char) (*TempCount + '0'); 127 } 128 else /* 10-35: A-Z */ 129 { 130 TempName[3] = (char) (*TempCount + ('A' - 10)); 131 } 132 133 (*TempCount)++; 134 135 /* First three characters are always "_T_" */ 136 137 TempName[0] = '_'; 138 TempName[1] = 'T'; 139 TempName[2] = '_'; 140 141 return (TempName); 142 } 143 144 145 /******************************************************************************* 146 * 147 * FUNCTION: TrAmlInitLineNumbers 148 * 149 * PARAMETERS: Op - Op to be initialized 150 * Neighbor - Op used for initialization values 151 * 152 * RETURN: None 153 * 154 * DESCRIPTION: Initialized the various line numbers for a parse node. 155 * 156 ******************************************************************************/ 157 158 static void 159 TrAmlInitLineNumbers ( 160 ACPI_PARSE_OBJECT *Op, 161 ACPI_PARSE_OBJECT *Neighbor) 162 { 163 164 Op->Asl.EndLine = Neighbor->Asl.EndLine; 165 Op->Asl.EndLogicalLine = Neighbor->Asl.EndLogicalLine; 166 Op->Asl.LineNumber = Neighbor->Asl.LineNumber; 167 Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset; 168 Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber; 169 } 170 171 172 /******************************************************************************* 173 * 174 * FUNCTION: TrAmlInitNode 175 * 176 * PARAMETERS: Op - Op to be initialized 177 * ParseOpcode - Opcode for this node 178 * 179 * RETURN: None 180 * 181 * DESCRIPTION: Initialize a node with the parse opcode and opcode name. 182 * 183 ******************************************************************************/ 184 185 static void 186 TrAmlInitNode ( 187 ACPI_PARSE_OBJECT *Op, 188 UINT16 ParseOpcode) 189 { 190 191 Op->Asl.ParseOpcode = ParseOpcode; 192 UtSetParseOpName (Op); 193 } 194 195 196 /******************************************************************************* 197 * 198 * FUNCTION: TrAmlSetSubtreeParent 199 * 200 * PARAMETERS: Op - First node in a list of peer nodes 201 * Parent - Parent of the subtree 202 * 203 * RETURN: None 204 * 205 * DESCRIPTION: Set the parent for all peer nodes in a subtree 206 * 207 ******************************************************************************/ 208 209 static void 210 TrAmlSetSubtreeParent ( 211 ACPI_PARSE_OBJECT *Op, 212 ACPI_PARSE_OBJECT *Parent) 213 { 214 ACPI_PARSE_OBJECT *Next; 215 216 217 Next = Op; 218 while (Next) 219 { 220 Next->Asl.Parent = Parent; 221 Next = Next->Asl.Next; 222 } 223 } 224 225 226 /******************************************************************************* 227 * 228 * FUNCTION: TrAmlInsertPeer 229 * 230 * PARAMETERS: Op - First node in a list of peer nodes 231 * NewPeer - Peer node to insert 232 * 233 * RETURN: None 234 * 235 * DESCRIPTION: Insert a new peer node into a list of peers. 236 * 237 ******************************************************************************/ 238 239 static void 240 TrAmlInsertPeer ( 241 ACPI_PARSE_OBJECT *Op, 242 ACPI_PARSE_OBJECT *NewPeer) 243 { 244 245 NewPeer->Asl.Next = Op->Asl.Next; 246 Op->Asl.Next = NewPeer; 247 } 248 249 250 /******************************************************************************* 251 * 252 * FUNCTION: TrAmlTransformWalkBegin 253 * 254 * PARAMETERS: ASL_WALK_CALLBACK 255 * 256 * RETURN: None 257 * 258 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 259 * operands. 260 * 261 ******************************************************************************/ 262 263 ACPI_STATUS 264 TrAmlTransformWalkBegin ( 265 ACPI_PARSE_OBJECT *Op, 266 UINT32 Level, 267 void *Context) 268 { 269 270 TrTransformSubtree (Op); 271 return (AE_OK); 272 } 273 274 275 /******************************************************************************* 276 * 277 * FUNCTION: TrAmlTransformWalkEnd 278 * 279 * PARAMETERS: ASL_WALK_CALLBACK 280 * 281 * RETURN: None 282 * 283 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 284 * operands. 285 * 286 ******************************************************************************/ 287 288 ACPI_STATUS 289 TrAmlTransformWalkEnd ( 290 ACPI_PARSE_OBJECT *Op, 291 UINT32 Level, 292 void *Context) 293 { 294 295 /* Save possible Externals list in the DefintionBlock Op */ 296 297 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 298 { 299 Op->Asl.Value.Arg = AslGbl_ExternalsListHead; 300 AslGbl_ExternalsListHead = NULL; 301 } 302 303 return (AE_OK); 304 } 305 306 307 /******************************************************************************* 308 * 309 * FUNCTION: TrTransformSubtree 310 * 311 * PARAMETERS: Op - The parent parse node 312 * 313 * RETURN: None 314 * 315 * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more 316 * complex AML opcodes require processing of the child nodes 317 * (arguments/operands). 318 * 319 ******************************************************************************/ 320 321 static void 322 TrTransformSubtree ( 323 ACPI_PARSE_OBJECT *Op) 324 { 325 ACPI_PARSE_OBJECT *MethodOp; 326 327 328 if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) 329 { 330 return; 331 } 332 333 switch (Op->Asl.ParseOpcode) 334 { 335 case PARSEOP_DEFINITION_BLOCK: 336 337 TrDoDefinitionBlock (Op); 338 break; 339 340 case PARSEOP_SWITCH: 341 342 TrDoSwitch (Op); 343 break; 344 345 case PARSEOP_METHOD: 346 /* 347 * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global, 348 * however 349 */ 350 AslGbl_TempCount = 0; 351 break; 352 353 case PARSEOP_EXTERNAL: 354 355 ExDoExternal (Op); 356 break; 357 358 case PARSEOP___METHOD__: 359 360 /* Transform to a string op containing the parent method name */ 361 362 Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; 363 UtSetParseOpName (Op); 364 365 /* Find the parent control method op */ 366 367 MethodOp = Op; 368 while (MethodOp) 369 { 370 if (MethodOp->Asl.ParseOpcode == PARSEOP_METHOD) 371 { 372 /* First child contains the method name */ 373 374 MethodOp = MethodOp->Asl.Child; 375 Op->Asl.Value.String = MethodOp->Asl.Value.String; 376 return; 377 } 378 379 MethodOp = MethodOp->Asl.Parent; 380 } 381 382 /* At the root, invocation not within a control method */ 383 384 Op->Asl.Value.String = "\\"; 385 break; 386 387 case PARSEOP_UNLOAD: 388 389 AslError (ASL_WARNING, ASL_MSG_UNLOAD, Op, NULL); 390 break; 391 392 case PARSEOP_SLEEP: 393 394 /* Remark for very long sleep values */ 395 396 if (Op->Asl.Child->Asl.Value.Integer > 1000) 397 { 398 AslError (ASL_REMARK, ASL_MSG_LONG_SLEEP, Op, NULL); 399 } 400 break; 401 402 case PARSEOP_PROCESSOR: 403 404 AslError (ASL_WARNING, ASL_MSG_LEGACY_PROCESSOR_OP, Op, Op->Asl.ExternalName); 405 406 break; 407 408 default: 409 410 /* Nothing to do here for other opcodes */ 411 412 break; 413 } 414 } 415 416 417 /******************************************************************************* 418 * 419 * FUNCTION: TrDoDefinitionBlock 420 * 421 * PARAMETERS: Op - Parse node 422 * 423 * RETURN: None 424 * 425 * DESCRIPTION: Find the end of the definition block and set a global to this 426 * node. It is used by the compiler to insert compiler-generated 427 * names at the root level of the namespace. 428 * 429 ******************************************************************************/ 430 431 static void 432 TrDoDefinitionBlock ( 433 ACPI_PARSE_OBJECT *Op) 434 { 435 ACPI_PARSE_OBJECT *Next; 436 UINT32 i; 437 438 439 /* Reset external list when starting a definition block */ 440 441 AslGbl_ExternalsListHead = NULL; 442 443 Next = Op->Asl.Child; 444 for (i = 0; i < 5; i++) 445 { 446 Next = Next->Asl.Next; 447 if (i == 0) 448 { 449 /* 450 * This is the table signature. Only the DSDT can be assumed 451 * to be at the root of the namespace; Therefore, namepath 452 * optimization can only be performed on the DSDT. 453 */ 454 if (!ACPI_COMPARE_NAMESEG (Next->Asl.Value.String, ACPI_SIG_DSDT)) 455 { 456 AslGbl_ReferenceOptimizationFlag = FALSE; 457 } 458 } 459 } 460 461 AslGbl_FirstLevelInsertionNode = Next; 462 } 463 464 465 /******************************************************************************* 466 * 467 * FUNCTION: TrDoSwitch 468 * 469 * PARAMETERS: StartNode - Parse node for SWITCH 470 * 471 * RETURN: None 472 * 473 * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is 474 * no actual AML opcode for SWITCH -- it must be simulated. 475 * 476 ******************************************************************************/ 477 478 static void 479 TrDoSwitch ( 480 ACPI_PARSE_OBJECT *StartNode) 481 { 482 ACPI_PARSE_OBJECT *Next; 483 ACPI_PARSE_OBJECT *CaseOp = NULL; 484 ACPI_PARSE_OBJECT *CaseBlock = NULL; 485 ACPI_PARSE_OBJECT *DefaultOp = NULL; 486 ACPI_PARSE_OBJECT *CurrentParentNode; 487 ACPI_PARSE_OBJECT *Conditional = NULL; 488 ACPI_PARSE_OBJECT *Predicate; 489 ACPI_PARSE_OBJECT *Peer; 490 ACPI_PARSE_OBJECT *NewOp; 491 ACPI_PARSE_OBJECT *NewOp2; 492 ACPI_PARSE_OBJECT *MethodOp; 493 ACPI_PARSE_OBJECT *StoreOp; 494 ACPI_PARSE_OBJECT *BreakOp; 495 ACPI_PARSE_OBJECT *BufferOp; 496 char *PredicateValueName; 497 UINT16 Index; 498 UINT32 Btype; 499 500 501 /* Start node is the Switch() node */ 502 503 CurrentParentNode = StartNode; 504 505 /* Create a new temp name of the form _T_x */ 506 507 PredicateValueName = TrAmlGetNextTempName (StartNode, &AslGbl_TempCount); 508 if (!PredicateValueName) 509 { 510 return; 511 } 512 513 /* First child is the Switch() predicate */ 514 515 Next = StartNode->Asl.Child; 516 517 /* 518 * Examine the return type of the Switch Value - 519 * must be Integer/Buffer/String 520 */ 521 Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); 522 Btype = AslKeywordMapping[Index].AcpiBtype; 523 if ((Btype != ACPI_BTYPE_INTEGER) && 524 (Btype != ACPI_BTYPE_STRING) && 525 (Btype != ACPI_BTYPE_BUFFER)) 526 { 527 AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL); 528 Btype = ACPI_BTYPE_INTEGER; 529 } 530 531 /* CASE statements start at next child */ 532 533 Peer = Next->Asl.Next; 534 while (Peer) 535 { 536 Next = Peer; 537 Peer = Next->Asl.Next; 538 539 if (Next->Asl.ParseOpcode == PARSEOP_CASE) 540 { 541 if (CaseOp) 542 { 543 /* Add an ELSE to complete the previous CASE */ 544 545 NewOp = TrCreateLeafOp (PARSEOP_ELSE); 546 NewOp->Asl.Parent = Conditional->Asl.Parent; 547 TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent); 548 549 /* Link ELSE node as a peer to the previous IF */ 550 551 TrAmlInsertPeer (Conditional, NewOp); 552 CurrentParentNode = NewOp; 553 } 554 555 CaseOp = Next; 556 Conditional = CaseOp; 557 CaseBlock = CaseOp->Asl.Child->Asl.Next; 558 Conditional->Asl.Child->Asl.Next = NULL; 559 Predicate = CaseOp->Asl.Child; 560 561 if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) || 562 (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) 563 { 564 /* 565 * Convert the package declaration to this form: 566 * 567 * If (LNotEqual (Match (Package(<size>){<data>}, 568 * MEQ, _T_x, MTR, Zero, Zero), Ones)) 569 */ 570 NewOp2 = TrCreateLeafOp (PARSEOP_MATCHTYPE_MEQ); 571 Predicate->Asl.Next = NewOp2; 572 TrAmlInitLineNumbers (NewOp2, Conditional); 573 574 NewOp = NewOp2; 575 NewOp2 = TrCreateValuedLeafOp (PARSEOP_NAMESTRING, 576 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 577 NewOp->Asl.Next = NewOp2; 578 TrAmlInitLineNumbers (NewOp2, Predicate); 579 580 NewOp = NewOp2; 581 NewOp2 = TrCreateLeafOp (PARSEOP_MATCHTYPE_MTR); 582 NewOp->Asl.Next = NewOp2; 583 TrAmlInitLineNumbers (NewOp2, Predicate); 584 585 NewOp = NewOp2; 586 NewOp2 = TrCreateLeafOp (PARSEOP_ZERO); 587 NewOp->Asl.Next = NewOp2; 588 TrAmlInitLineNumbers (NewOp2, Predicate); 589 590 NewOp = NewOp2; 591 NewOp2 = TrCreateLeafOp (PARSEOP_ZERO); 592 NewOp->Asl.Next = NewOp2; 593 TrAmlInitLineNumbers (NewOp2, Predicate); 594 595 NewOp2 = TrCreateLeafOp (PARSEOP_MATCH); 596 NewOp2->Asl.Child = Predicate; /* PARSEOP_PACKAGE */ 597 TrAmlInitLineNumbers (NewOp2, Conditional); 598 TrAmlSetSubtreeParent (Predicate, NewOp2); 599 600 NewOp = NewOp2; 601 NewOp2 = TrCreateLeafOp (PARSEOP_ONES); 602 NewOp->Asl.Next = NewOp2; 603 TrAmlInitLineNumbers (NewOp2, Conditional); 604 605 NewOp2 = TrCreateLeafOp (PARSEOP_LEQUAL); 606 NewOp2->Asl.Child = NewOp; 607 NewOp->Asl.Parent = NewOp2; 608 TrAmlInitLineNumbers (NewOp2, Conditional); 609 TrAmlSetSubtreeParent (NewOp, NewOp2); 610 611 NewOp = NewOp2; 612 NewOp2 = TrCreateLeafOp (PARSEOP_LNOT); 613 NewOp2->Asl.Child = NewOp; 614 NewOp2->Asl.Parent = Conditional; 615 NewOp->Asl.Parent = NewOp2; 616 TrAmlInitLineNumbers (NewOp2, Conditional); 617 618 Conditional->Asl.Child = NewOp2; 619 NewOp2->Asl.Next = CaseBlock; 620 } 621 else 622 { 623 /* 624 * Integer and Buffer case. 625 * 626 * Change CaseOp() to: If (LEqual (SwitchValue, CaseValue)) {...} 627 * Note: SwitchValue is first to allow the CaseValue to be implicitly 628 * converted to the type of SwitchValue if necessary. 629 * 630 * CaseOp->Child is the case value 631 * CaseOp->Child->Peer is the beginning of the case block 632 */ 633 NewOp = TrCreateValuedLeafOp (PARSEOP_NAMESTRING, 634 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 635 NewOp->Asl.Next = Predicate; 636 TrAmlInitLineNumbers (NewOp, Predicate); 637 638 NewOp2 = TrCreateLeafOp (PARSEOP_LEQUAL); 639 NewOp2->Asl.Parent = Conditional; 640 NewOp2->Asl.Child = NewOp; 641 TrAmlInitLineNumbers (NewOp2, Conditional); 642 643 TrAmlSetSubtreeParent (NewOp, NewOp2); 644 645 Predicate = NewOp2; 646 Predicate->Asl.Next = CaseBlock; 647 648 TrAmlSetSubtreeParent (Predicate, Conditional); 649 Conditional->Asl.Child = Predicate; 650 } 651 652 /* Reinitialize the CASE node to an IF node */ 653 654 TrAmlInitNode (Conditional, PARSEOP_IF); 655 656 /* 657 * The first CASE(IF) is not nested under an ELSE. 658 * All other CASEs are children of a parent ELSE. 659 */ 660 if (CurrentParentNode == StartNode) 661 { 662 Conditional->Asl.Next = NULL; 663 } 664 else 665 { 666 /* 667 * The IF is a child of previous IF/ELSE. It 668 * is therefore without peer. 669 */ 670 CurrentParentNode->Asl.Child = Conditional; 671 Conditional->Asl.Parent = CurrentParentNode; 672 Conditional->Asl.Next = NULL; 673 } 674 } 675 else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT) 676 { 677 if (DefaultOp) 678 { 679 /* 680 * More than one Default 681 * (Parser does not catch this, must check here) 682 */ 683 AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL); 684 } 685 else 686 { 687 /* Save the DEFAULT node for later, after CASEs */ 688 689 DefaultOp = Next; 690 } 691 } 692 else 693 { 694 /* Unknown peer opcode */ 695 696 AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n", 697 Next->Asl.ParseOpName, Next->Asl.ParseOpcode); 698 } 699 } 700 701 /* Add the default case at the end of the if/else construct */ 702 703 if (DefaultOp) 704 { 705 /* If no CASE statements, this is an error - see below */ 706 707 if (CaseOp) 708 { 709 /* Convert the DEFAULT node to an ELSE */ 710 711 TrAmlInitNode (DefaultOp, PARSEOP_ELSE); 712 DefaultOp->Asl.Parent = Conditional->Asl.Parent; 713 714 /* Link ELSE node as a peer to the previous IF */ 715 716 TrAmlInsertPeer (Conditional, DefaultOp); 717 } 718 } 719 720 if (!CaseOp) 721 { 722 AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL); 723 } 724 725 726 /* 727 * Create a Name(_T_x, ...) statement. This statement must appear at the 728 * method level, in case a loop surrounds the switch statement and could 729 * cause the name to be created twice (error). 730 */ 731 732 /* Create the Name node */ 733 734 Predicate = StartNode->Asl.Child; 735 NewOp = TrCreateLeafOp (PARSEOP_NAME); 736 TrAmlInitLineNumbers (NewOp, StartNode); 737 738 /* Find the parent method */ 739 740 Next = StartNode; 741 while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) && 742 (Next->Asl.ParseOpcode != PARSEOP_DEFINITION_BLOCK)) 743 { 744 Next = Next->Asl.Parent; 745 } 746 MethodOp = Next; 747 748 NewOp->Asl.CompileFlags |= OP_COMPILER_EMITTED; 749 NewOp->Asl.Parent = Next; 750 751 /* Insert name after the method name and arguments */ 752 753 Next = Next->Asl.Child; /* Name */ 754 Next = Next->Asl.Next; /* NumArgs */ 755 Next = Next->Asl.Next; /* SerializeRule */ 756 757 /* 758 * If method is not Serialized, we must make is so, because of the way 759 * that Switch() must be implemented -- we cannot allow multiple threads 760 * to execute this method concurrently since we need to create local 761 * temporary name(s). 762 */ 763 if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL) 764 { 765 AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp, 766 "Due to use of Switch operator"); 767 Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL; 768 } 769 770 Next = Next->Asl.Next; /* SyncLevel */ 771 Next = Next->Asl.Next; /* ReturnType */ 772 Next = Next->Asl.Next; /* ParameterTypes */ 773 774 TrAmlInsertPeer (Next, NewOp); 775 TrAmlInitLineNumbers (NewOp, Next); 776 777 /* Create the NameSeg child for the Name node */ 778 779 NewOp2 = TrCreateValuedLeafOp (PARSEOP_NAMESEG, 780 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 781 TrAmlInitLineNumbers (NewOp2, NewOp); 782 NewOp2->Asl.CompileFlags |= OP_IS_NAME_DECLARATION; 783 NewOp->Asl.Child = NewOp2; 784 785 /* Create the initial value for the Name. Btype was already validated above */ 786 787 switch (Btype) 788 { 789 case ACPI_BTYPE_INTEGER: 790 791 NewOp2->Asl.Next = TrCreateValuedLeafOp (PARSEOP_ZERO, 792 (UINT64) 0); 793 TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 794 break; 795 796 case ACPI_BTYPE_STRING: 797 798 NewOp2->Asl.Next = TrCreateValuedLeafOp (PARSEOP_STRING_LITERAL, 799 (UINT64) ACPI_TO_INTEGER ("")); 800 TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 801 break; 802 803 case ACPI_BTYPE_BUFFER: 804 805 (void) TrLinkPeerOp (NewOp2, TrCreateValuedLeafOp (PARSEOP_BUFFER, 806 (UINT64) 0)); 807 Next = NewOp2->Asl.Next; 808 TrAmlInitLineNumbers (Next, NewOp2); 809 810 (void) TrLinkOpChildren (Next, 1, TrCreateValuedLeafOp (PARSEOP_ZERO, 811 (UINT64) 1)); 812 TrAmlInitLineNumbers (Next->Asl.Child, Next); 813 814 BufferOp = TrCreateValuedLeafOp (PARSEOP_DEFAULT_ARG, (UINT64) 0); 815 TrAmlInitLineNumbers (BufferOp, Next->Asl.Child); 816 (void) TrLinkPeerOp (Next->Asl.Child, BufferOp); 817 818 TrAmlSetSubtreeParent (Next->Asl.Child, Next); 819 break; 820 821 default: 822 823 break; 824 } 825 826 TrAmlSetSubtreeParent (NewOp2, NewOp); 827 828 /* 829 * Transform the Switch() into a While(One)-Break node. 830 * And create a Store() node which will be used to save the 831 * Switch() value. The store is of the form: Store (Value, _T_x) 832 * where _T_x is the temp variable. 833 */ 834 TrAmlInitNode (StartNode, PARSEOP_WHILE); 835 NewOp = TrCreateLeafOp (PARSEOP_ONE); 836 TrAmlInitLineNumbers (NewOp, StartNode); 837 NewOp->Asl.Next = Predicate->Asl.Next; 838 NewOp->Asl.Parent = StartNode; 839 StartNode->Asl.Child = NewOp; 840 841 /* Create a Store() node */ 842 843 StoreOp = TrCreateLeafOp (PARSEOP_STORE); 844 TrAmlInitLineNumbers (StoreOp, NewOp); 845 StoreOp->Asl.Parent = StartNode; 846 TrAmlInsertPeer (NewOp, StoreOp); 847 848 /* Complete the Store subtree */ 849 850 StoreOp->Asl.Child = Predicate; 851 Predicate->Asl.Parent = StoreOp; 852 853 NewOp = TrCreateValuedLeafOp (PARSEOP_NAMESEG, 854 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 855 TrAmlInitLineNumbers (NewOp, StoreOp); 856 NewOp->Asl.Parent = StoreOp; 857 Predicate->Asl.Next = NewOp; 858 859 /* Create a Break() node and insert it into the end of While() */ 860 861 Conditional = StartNode->Asl.Child; 862 while (Conditional->Asl.Next) 863 { 864 Conditional = Conditional->Asl.Next; 865 } 866 867 BreakOp = TrCreateLeafOp (PARSEOP_BREAK); 868 TrAmlInitLineNumbers (BreakOp, NewOp); 869 BreakOp->Asl.Parent = StartNode; 870 TrAmlInsertPeer (Conditional, BreakOp); 871 } 872