1 /****************************************************************************** 2 * 3 * Module Name: asltransform - Parse tree transforms 4 * 5 *****************************************************************************/ 6 7 /****************************************************************************** 8 * 9 * 1. Copyright Notice 10 * 11 * Some or all of this work - Copyright (c) 1999 - 2020, Intel Corp. 12 * All rights reserved. 13 * 14 * 2. License 15 * 16 * 2.1. This is your license from Intel Corp. under its intellectual property 17 * rights. You may have additional license terms from the party that provided 18 * you this software, covering your right to use that party's intellectual 19 * property rights. 20 * 21 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 22 * copy of the source code appearing in this file ("Covered Code") an 23 * irrevocable, perpetual, worldwide license under Intel's copyrights in the 24 * base code distributed originally by Intel ("Original Intel Code") to copy, 25 * make derivatives, distribute, use and display any portion of the Covered 26 * Code in any form, with the right to sublicense such rights; and 27 * 28 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 29 * license (with the right to sublicense), under only those claims of Intel 30 * patents that are infringed by the Original Intel Code, to make, use, sell, 31 * offer to sell, and import the Covered Code and derivative works thereof 32 * solely to the minimum extent necessary to exercise the above copyright 33 * license, and in no event shall the patent license extend to any additions 34 * to or modifications of the Original Intel Code. No other license or right 35 * is granted directly or by implication, estoppel or otherwise; 36 * 37 * The above copyright and patent license is granted only if the following 38 * conditions are met: 39 * 40 * 3. Conditions 41 * 42 * 3.1. Redistribution of Source with Rights to Further Distribute Source. 43 * Redistribution of source code of any substantial portion of the Covered 44 * Code or modification with rights to further distribute source must include 45 * the above Copyright Notice, the above License, this list of Conditions, 46 * and the following Disclaimer and Export Compliance provision. In addition, 47 * Licensee must cause all Covered Code to which Licensee contributes to 48 * contain a file documenting the changes Licensee made to create that Covered 49 * Code and the date of any change. Licensee must include in that file the 50 * documentation of any changes made by any predecessor Licensee. Licensee 51 * must include a prominent statement that the modification is derived, 52 * directly or indirectly, from Original Intel Code. 53 * 54 * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 55 * Redistribution of source code of any substantial portion of the Covered 56 * Code or modification without rights to further distribute source must 57 * include the following Disclaimer and Export Compliance provision in the 58 * documentation and/or other materials provided with distribution. In 59 * addition, Licensee may not authorize further sublicense of source of any 60 * portion of the Covered Code, and must include terms to the effect that the 61 * license from Licensee to its licensee is limited to the intellectual 62 * property embodied in the software Licensee provides to its licensee, and 63 * not to intellectual property embodied in modifications its licensee may 64 * make. 65 * 66 * 3.3. Redistribution of Executable. Redistribution in executable form of any 67 * substantial portion of the Covered Code or modification must reproduce the 68 * above Copyright Notice, and the following Disclaimer and Export Compliance 69 * provision in the documentation and/or other materials provided with the 70 * distribution. 71 * 72 * 3.4. Intel retains all right, title, and interest in and to the Original 73 * Intel Code. 74 * 75 * 3.5. Neither the name Intel nor any other trademark owned or controlled by 76 * Intel shall be used in advertising or otherwise to promote the sale, use or 77 * other dealings in products derived from or relating to the Covered Code 78 * without prior written authorization from Intel. 79 * 80 * 4. Disclaimer and Export Compliance 81 * 82 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 83 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 84 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 85 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 86 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 87 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 88 * PARTICULAR PURPOSE. 89 * 90 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 91 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 92 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 93 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 94 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 95 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 96 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 97 * LIMITED REMEDY. 98 * 99 * 4.3. Licensee shall not export, either directly or indirectly, any of this 100 * software or system incorporating such software without first obtaining any 101 * required license or other approval from the U. S. Department of Commerce or 102 * any other agency or department of the United States Government. In the 103 * event Licensee exports any such software from the United States or 104 * re-exports any such software from a foreign destination, Licensee shall 105 * ensure that the distribution and export/re-export of the software is in 106 * compliance with all laws, regulations, orders, or other restrictions of the 107 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 108 * any of its subsidiaries will export/re-export any technical data, process, 109 * software, or service, directly or indirectly, to any country for which the 110 * United States government or any agency thereof requires an export license, 111 * other governmental approval, or letter of assurance, without first obtaining 112 * such license, approval or letter. 113 * 114 ***************************************************************************** 115 * 116 * Alternatively, you may choose to be licensed under the terms of the 117 * following license: 118 * 119 * Redistribution and use in source and binary forms, with or without 120 * modification, are permitted provided that the following conditions 121 * are met: 122 * 1. Redistributions of source code must retain the above copyright 123 * notice, this list of conditions, and the following disclaimer, 124 * without modification. 125 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 126 * substantially similar to the "NO WARRANTY" disclaimer below 127 * ("Disclaimer") and any redistribution must be conditioned upon 128 * including a substantially similar Disclaimer requirement for further 129 * binary redistribution. 130 * 3. Neither the names of the above-listed copyright holders nor the names 131 * of any contributors may be used to endorse or promote products derived 132 * from this software without specific prior written permission. 133 * 134 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 135 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 136 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 137 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 138 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 139 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 140 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 141 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 142 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 143 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 144 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 145 * 146 * Alternatively, you may choose to be licensed under the terms of the 147 * GNU General Public License ("GPL") version 2 as published by the Free 148 * Software Foundation. 149 * 150 *****************************************************************************/ 151 152 #include <contrib/dev/acpica/compiler/aslcompiler.h> 153 #include "aslcompiler.y.h" 154 #include <contrib/dev/acpica/include/acnamesp.h> 155 156 #define _COMPONENT ACPI_COMPILER 157 ACPI_MODULE_NAME ("asltransform") 158 159 /* Local prototypes */ 160 161 static void 162 TrTransformSubtree ( 163 ACPI_PARSE_OBJECT *Op); 164 165 static char * 166 TrAmlGetNextTempName ( 167 ACPI_PARSE_OBJECT *Op, 168 UINT8 *TempCount); 169 170 static void 171 TrAmlInitLineNumbers ( 172 ACPI_PARSE_OBJECT *Op, 173 ACPI_PARSE_OBJECT *Neighbor); 174 175 static void 176 TrAmlInitNode ( 177 ACPI_PARSE_OBJECT *Op, 178 UINT16 ParseOpcode); 179 180 static void 181 TrAmlSetSubtreeParent ( 182 ACPI_PARSE_OBJECT *Op, 183 ACPI_PARSE_OBJECT *Parent); 184 185 static void 186 TrAmlInsertPeer ( 187 ACPI_PARSE_OBJECT *Op, 188 ACPI_PARSE_OBJECT *NewPeer); 189 190 static void 191 TrDoDefinitionBlock ( 192 ACPI_PARSE_OBJECT *Op); 193 194 static void 195 TrDoSwitch ( 196 ACPI_PARSE_OBJECT *StartNode); 197 198 static void 199 TrCheckForDuplicateCase ( 200 ACPI_PARSE_OBJECT *CaseOp, 201 ACPI_PARSE_OBJECT *Predicate1); 202 203 static BOOLEAN 204 TrCheckForBufferMatch ( 205 ACPI_PARSE_OBJECT *Next1, 206 ACPI_PARSE_OBJECT *Next2); 207 208 static void 209 TrDoMethod ( 210 ACPI_PARSE_OBJECT *Op); 211 212 213 /******************************************************************************* 214 * 215 * FUNCTION: TrAmlGetNextTempName 216 * 217 * PARAMETERS: Op - Current parse op 218 * TempCount - Current temporary counter. Was originally 219 * per-module; Currently per method, could be 220 * expanded to per-scope. 221 * 222 * RETURN: A pointer to name (allocated here). 223 * 224 * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are 225 * reserved for use by the ASL compiler. (_T_0 through _T_Z) 226 * 227 ******************************************************************************/ 228 229 static char * 230 TrAmlGetNextTempName ( 231 ACPI_PARSE_OBJECT *Op, 232 UINT8 *TempCount) 233 { 234 char *TempName; 235 236 237 if (*TempCount >= (10 + 26)) /* 0-35 valid: 0-9 and A-Z for TempName[3] */ 238 { 239 /* Too many temps */ 240 241 AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL); 242 return (NULL); 243 } 244 245 TempName = UtLocalCalloc (5); 246 247 if (*TempCount < 10) /* 0-9 */ 248 { 249 TempName[3] = (char) (*TempCount + '0'); 250 } 251 else /* 10-35: A-Z */ 252 { 253 TempName[3] = (char) (*TempCount + ('A' - 10)); 254 } 255 256 (*TempCount)++; 257 258 /* First three characters are always "_T_" */ 259 260 TempName[0] = '_'; 261 TempName[1] = 'T'; 262 TempName[2] = '_'; 263 264 return (TempName); 265 } 266 267 268 /******************************************************************************* 269 * 270 * FUNCTION: TrAmlInitLineNumbers 271 * 272 * PARAMETERS: Op - Op to be initialized 273 * Neighbor - Op used for initialization values 274 * 275 * RETURN: None 276 * 277 * DESCRIPTION: Initialized the various line numbers for a parse node. 278 * 279 ******************************************************************************/ 280 281 static void 282 TrAmlInitLineNumbers ( 283 ACPI_PARSE_OBJECT *Op, 284 ACPI_PARSE_OBJECT *Neighbor) 285 { 286 287 Op->Asl.EndLine = Neighbor->Asl.EndLine; 288 Op->Asl.EndLogicalLine = Neighbor->Asl.EndLogicalLine; 289 Op->Asl.LineNumber = Neighbor->Asl.LineNumber; 290 Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset; 291 Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber; 292 } 293 294 295 /******************************************************************************* 296 * 297 * FUNCTION: TrAmlInitNode 298 * 299 * PARAMETERS: Op - Op to be initialized 300 * ParseOpcode - Opcode for this node 301 * 302 * RETURN: None 303 * 304 * DESCRIPTION: Initialize a node with the parse opcode and opcode name. 305 * 306 ******************************************************************************/ 307 308 static void 309 TrAmlInitNode ( 310 ACPI_PARSE_OBJECT *Op, 311 UINT16 ParseOpcode) 312 { 313 314 Op->Asl.ParseOpcode = ParseOpcode; 315 UtSetParseOpName (Op); 316 } 317 318 319 /******************************************************************************* 320 * 321 * FUNCTION: TrAmlSetSubtreeParent 322 * 323 * PARAMETERS: Op - First node in a list of peer nodes 324 * Parent - Parent of the subtree 325 * 326 * RETURN: None 327 * 328 * DESCRIPTION: Set the parent for all peer nodes in a subtree 329 * 330 ******************************************************************************/ 331 332 static void 333 TrAmlSetSubtreeParent ( 334 ACPI_PARSE_OBJECT *Op, 335 ACPI_PARSE_OBJECT *Parent) 336 { 337 ACPI_PARSE_OBJECT *Next; 338 339 340 Next = Op; 341 while (Next) 342 { 343 Next->Asl.Parent = Parent; 344 Next = Next->Asl.Next; 345 } 346 } 347 348 349 /******************************************************************************* 350 * 351 * FUNCTION: TrAmlInsertPeer 352 * 353 * PARAMETERS: Op - First node in a list of peer nodes 354 * NewPeer - Peer node to insert 355 * 356 * RETURN: None 357 * 358 * DESCRIPTION: Insert a new peer node into a list of peers. 359 * 360 ******************************************************************************/ 361 362 static void 363 TrAmlInsertPeer ( 364 ACPI_PARSE_OBJECT *Op, 365 ACPI_PARSE_OBJECT *NewPeer) 366 { 367 368 NewPeer->Asl.Next = Op->Asl.Next; 369 Op->Asl.Next = NewPeer; 370 } 371 372 373 /******************************************************************************* 374 * 375 * FUNCTION: TrAmlTransformWalkBegin 376 * 377 * PARAMETERS: ASL_WALK_CALLBACK 378 * 379 * RETURN: None 380 * 381 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 382 * operands. 383 * 384 ******************************************************************************/ 385 386 ACPI_STATUS 387 TrAmlTransformWalkBegin ( 388 ACPI_PARSE_OBJECT *Op, 389 UINT32 Level, 390 void *Context) 391 { 392 393 TrTransformSubtree (Op); 394 return (AE_OK); 395 } 396 397 398 /******************************************************************************* 399 * 400 * FUNCTION: TrAmlTransformWalkEnd 401 * 402 * PARAMETERS: ASL_WALK_CALLBACK 403 * 404 * RETURN: None 405 * 406 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 407 * operands. 408 * 409 ******************************************************************************/ 410 411 ACPI_STATUS 412 TrAmlTransformWalkEnd ( 413 ACPI_PARSE_OBJECT *Op, 414 UINT32 Level, 415 void *Context) 416 { 417 418 /* Save possible Externals list in the DefintionBlock Op */ 419 420 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 421 { 422 Op->Asl.Value.Arg = AslGbl_ExternalsListHead; 423 AslGbl_ExternalsListHead = NULL; 424 } 425 426 return (AE_OK); 427 } 428 429 430 /******************************************************************************* 431 * 432 * FUNCTION: TrTransformSubtree 433 * 434 * PARAMETERS: Op - The parent parse node 435 * 436 * RETURN: None 437 * 438 * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more 439 * complex AML opcodes require processing of the child nodes 440 * (arguments/operands). 441 * 442 ******************************************************************************/ 443 444 static void 445 TrTransformSubtree ( 446 ACPI_PARSE_OBJECT *Op) 447 { 448 ACPI_PARSE_OBJECT *MethodOp; 449 ACPI_NAMESTRING_INFO Info; 450 451 452 if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) 453 { 454 return; 455 } 456 457 switch (Op->Asl.ParseOpcode) 458 { 459 case PARSEOP_DEFINITION_BLOCK: 460 461 TrDoDefinitionBlock (Op); 462 break; 463 464 case PARSEOP_SWITCH: 465 466 TrDoSwitch (Op); 467 break; 468 469 case PARSEOP_METHOD: 470 471 TrDoMethod (Op); 472 break; 473 474 case PARSEOP_EXTERNAL: 475 476 ExDoExternal (Op); 477 break; 478 479 case PARSEOP___METHOD__: 480 481 /* Transform to a string op containing the parent method name */ 482 483 Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL; 484 UtSetParseOpName (Op); 485 486 /* Find the parent control method op */ 487 488 MethodOp = Op; 489 while (MethodOp) 490 { 491 if (MethodOp->Asl.ParseOpcode == PARSEOP_METHOD) 492 { 493 /* First child contains the method name */ 494 495 MethodOp = MethodOp->Asl.Child; 496 Op->Asl.Value.String = MethodOp->Asl.Value.String; 497 return; 498 } 499 500 MethodOp = MethodOp->Asl.Parent; 501 } 502 503 /* At the root, invocation not within a control method */ 504 505 Op->Asl.Value.String = "\\"; 506 break; 507 508 case PARSEOP_NAMESTRING: 509 /* 510 * A NameString can be up to 255 (0xFF) individual NameSegs maximum 511 * (with 254 dot separators) - as per the ACPI specification. Note: 512 * Cannot check for NumSegments == 0 because things like 513 * Scope(\) are legal and OK. 514 */ 515 Info.ExternalName = Op->Asl.Value.String; 516 AcpiNsGetInternalNameLength (&Info); 517 518 if (Info.NumSegments > 255) 519 { 520 AslError (ASL_ERROR, ASL_MSG_NAMESTRING_LENGTH, Op, NULL); 521 } 522 break; 523 524 case PARSEOP_UNLOAD: 525 526 AslError (ASL_WARNING, ASL_MSG_UNLOAD, Op, NULL); 527 break; 528 529 case PARSEOP_SLEEP: 530 531 /* Remark for very long sleep values */ 532 533 if (Op->Asl.Child->Asl.Value.Integer > 1000) 534 { 535 AslError (ASL_REMARK, ASL_MSG_LONG_SLEEP, Op, NULL); 536 } 537 break; 538 539 case PARSEOP_PROCESSOR: 540 541 AslError (ASL_WARNING, ASL_MSG_LEGACY_PROCESSOR_OP, Op, Op->Asl.ExternalName); 542 break; 543 544 default: 545 546 /* Nothing to do here for other opcodes */ 547 548 break; 549 } 550 } 551 552 553 /******************************************************************************* 554 * 555 * FUNCTION: TrDoDefinitionBlock 556 * 557 * PARAMETERS: Op - Parse node 558 * 559 * RETURN: None 560 * 561 * DESCRIPTION: Find the end of the definition block and set a global to this 562 * node. It is used by the compiler to insert compiler-generated 563 * names at the root level of the namespace. 564 * 565 ******************************************************************************/ 566 567 static void 568 TrDoDefinitionBlock ( 569 ACPI_PARSE_OBJECT *Op) 570 { 571 ACPI_PARSE_OBJECT *Next; 572 UINT32 i; 573 574 575 /* Reset external list when starting a definition block */ 576 577 AslGbl_ExternalsListHead = NULL; 578 579 Next = Op->Asl.Child; 580 for (i = 0; i < 5; i++) 581 { 582 Next = Next->Asl.Next; 583 if (i == 0) 584 { 585 /* 586 * This is the table signature. Only the DSDT can be assumed 587 * to be at the root of the namespace; Therefore, namepath 588 * optimization can only be performed on the DSDT. 589 */ 590 if (!ACPI_COMPARE_NAMESEG (Next->Asl.Value.String, ACPI_SIG_DSDT)) 591 { 592 AslGbl_ReferenceOptimizationFlag = FALSE; 593 } 594 } 595 } 596 597 AslGbl_FirstLevelInsertionNode = Next; 598 } 599 600 601 /******************************************************************************* 602 * 603 * FUNCTION: TrDoSwitch 604 * 605 * PARAMETERS: StartNode - Parse node for SWITCH 606 * 607 * RETURN: None 608 * 609 * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is 610 * no actual AML opcode for SWITCH -- it must be simulated. 611 * 612 ******************************************************************************/ 613 614 static void 615 TrDoSwitch ( 616 ACPI_PARSE_OBJECT *StartNode) 617 { 618 ACPI_PARSE_OBJECT *Next; 619 ACPI_PARSE_OBJECT *CaseOp = NULL; 620 ACPI_PARSE_OBJECT *CaseBlock = NULL; 621 ACPI_PARSE_OBJECT *DefaultOp = NULL; 622 ACPI_PARSE_OBJECT *CurrentParentNode; 623 ACPI_PARSE_OBJECT *Conditional = NULL; 624 ACPI_PARSE_OBJECT *Predicate; 625 ACPI_PARSE_OBJECT *Peer; 626 ACPI_PARSE_OBJECT *NewOp; 627 ACPI_PARSE_OBJECT *NewOp2; 628 ACPI_PARSE_OBJECT *MethodOp; 629 ACPI_PARSE_OBJECT *StoreOp; 630 ACPI_PARSE_OBJECT *BreakOp; 631 ACPI_PARSE_OBJECT *BufferOp; 632 char *PredicateValueName; 633 UINT16 Index; 634 UINT32 Btype; 635 636 637 /* Start node is the Switch() node */ 638 639 CurrentParentNode = StartNode; 640 641 /* Create a new temp name of the form _T_x */ 642 643 PredicateValueName = TrAmlGetNextTempName (StartNode, &AslGbl_TempCount); 644 if (!PredicateValueName) 645 { 646 return; 647 } 648 649 /* First child is the Switch() predicate */ 650 651 Next = StartNode->Asl.Child; 652 653 /* 654 * Examine the return type of the Switch Value - 655 * must be Integer/Buffer/String 656 */ 657 Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); 658 Btype = AslKeywordMapping[Index].AcpiBtype; 659 if ((Btype != ACPI_BTYPE_INTEGER) && 660 (Btype != ACPI_BTYPE_STRING) && 661 (Btype != ACPI_BTYPE_BUFFER)) 662 { 663 AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL); 664 Btype = ACPI_BTYPE_INTEGER; 665 } 666 667 /* CASE statements start at next child */ 668 669 Peer = Next->Asl.Next; 670 while (Peer) 671 { 672 Next = Peer; 673 Peer = Next->Asl.Next; 674 675 if (Next->Asl.ParseOpcode == PARSEOP_CASE) 676 { 677 TrCheckForDuplicateCase (Next, Next->Asl.Child); 678 679 if (CaseOp) 680 { 681 /* Add an ELSE to complete the previous CASE */ 682 683 NewOp = TrCreateLeafOp (PARSEOP_ELSE); 684 NewOp->Asl.Parent = Conditional->Asl.Parent; 685 TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent); 686 687 /* Link ELSE node as a peer to the previous IF */ 688 689 TrAmlInsertPeer (Conditional, NewOp); 690 CurrentParentNode = NewOp; 691 } 692 693 CaseOp = Next; 694 Conditional = CaseOp; 695 CaseBlock = CaseOp->Asl.Child->Asl.Next; 696 Conditional->Asl.Child->Asl.Next = NULL; 697 Predicate = CaseOp->Asl.Child; 698 699 if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) || 700 (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) 701 { 702 /* 703 * Convert the package declaration to this form: 704 * 705 * If (LNotEqual (Match (Package(<size>){<data>}, 706 * MEQ, _T_x, MTR, Zero, Zero), Ones)) 707 */ 708 NewOp2 = TrCreateLeafOp (PARSEOP_MATCHTYPE_MEQ); 709 Predicate->Asl.Next = NewOp2; 710 TrAmlInitLineNumbers (NewOp2, Conditional); 711 712 NewOp = NewOp2; 713 NewOp2 = TrCreateValuedLeafOp (PARSEOP_NAMESTRING, 714 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 715 NewOp->Asl.Next = NewOp2; 716 TrAmlInitLineNumbers (NewOp2, Predicate); 717 718 NewOp = NewOp2; 719 NewOp2 = TrCreateLeafOp (PARSEOP_MATCHTYPE_MTR); 720 NewOp->Asl.Next = NewOp2; 721 TrAmlInitLineNumbers (NewOp2, Predicate); 722 723 NewOp = NewOp2; 724 NewOp2 = TrCreateLeafOp (PARSEOP_ZERO); 725 NewOp->Asl.Next = NewOp2; 726 TrAmlInitLineNumbers (NewOp2, Predicate); 727 728 NewOp = NewOp2; 729 NewOp2 = TrCreateLeafOp (PARSEOP_ZERO); 730 NewOp->Asl.Next = NewOp2; 731 TrAmlInitLineNumbers (NewOp2, Predicate); 732 733 NewOp2 = TrCreateLeafOp (PARSEOP_MATCH); 734 NewOp2->Asl.Child = Predicate; /* PARSEOP_PACKAGE */ 735 TrAmlInitLineNumbers (NewOp2, Conditional); 736 TrAmlSetSubtreeParent (Predicate, NewOp2); 737 738 NewOp = NewOp2; 739 NewOp2 = TrCreateLeafOp (PARSEOP_ONES); 740 NewOp->Asl.Next = NewOp2; 741 TrAmlInitLineNumbers (NewOp2, Conditional); 742 743 NewOp2 = TrCreateLeafOp (PARSEOP_LEQUAL); 744 NewOp2->Asl.Child = NewOp; 745 NewOp->Asl.Parent = NewOp2; 746 TrAmlInitLineNumbers (NewOp2, Conditional); 747 TrAmlSetSubtreeParent (NewOp, NewOp2); 748 749 NewOp = NewOp2; 750 NewOp2 = TrCreateLeafOp (PARSEOP_LNOT); 751 NewOp2->Asl.Child = NewOp; 752 NewOp2->Asl.Parent = Conditional; 753 NewOp->Asl.Parent = NewOp2; 754 TrAmlInitLineNumbers (NewOp2, Conditional); 755 756 Conditional->Asl.Child = NewOp2; 757 NewOp2->Asl.Next = CaseBlock; 758 } 759 else 760 { 761 /* 762 * Integer and Buffer case. 763 * 764 * Change CaseOp() to: If (LEqual (SwitchValue, CaseValue)) {...} 765 * Note: SwitchValue is first to allow the CaseValue to be implicitly 766 * converted to the type of SwitchValue if necessary. 767 * 768 * CaseOp->Child is the case value 769 * CaseOp->Child->Peer is the beginning of the case block 770 */ 771 NewOp = TrCreateValuedLeafOp (PARSEOP_NAMESTRING, 772 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 773 NewOp->Asl.Next = Predicate; 774 TrAmlInitLineNumbers (NewOp, Predicate); 775 776 NewOp2 = TrCreateLeafOp (PARSEOP_LEQUAL); 777 NewOp2->Asl.Parent = Conditional; 778 NewOp2->Asl.Child = NewOp; 779 TrAmlInitLineNumbers (NewOp2, Conditional); 780 781 TrAmlSetSubtreeParent (NewOp, NewOp2); 782 783 Predicate = NewOp2; 784 Predicate->Asl.Next = CaseBlock; 785 786 TrAmlSetSubtreeParent (Predicate, Conditional); 787 Conditional->Asl.Child = Predicate; 788 } 789 790 /* Reinitialize the CASE node to an IF node */ 791 792 TrAmlInitNode (Conditional, PARSEOP_IF); 793 794 /* 795 * The first CASE(IF) is not nested under an ELSE. 796 * All other CASEs are children of a parent ELSE. 797 */ 798 if (CurrentParentNode == StartNode) 799 { 800 Conditional->Asl.Next = NULL; 801 } 802 else 803 { 804 /* 805 * The IF is a child of previous IF/ELSE. It 806 * is therefore without peer. 807 */ 808 CurrentParentNode->Asl.Child = Conditional; 809 Conditional->Asl.Parent = CurrentParentNode; 810 Conditional->Asl.Next = NULL; 811 } 812 } 813 else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT) 814 { 815 if (DefaultOp) 816 { 817 /* 818 * More than one Default 819 * (Parser does not catch this, must check here) 820 */ 821 AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL); 822 } 823 else 824 { 825 /* Save the DEFAULT node for later, after CASEs */ 826 827 DefaultOp = Next; 828 } 829 } 830 else 831 { 832 /* Unknown peer opcode */ 833 834 AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n", 835 Next->Asl.ParseOpName, Next->Asl.ParseOpcode); 836 } 837 } 838 839 /* Add the default case at the end of the if/else construct */ 840 841 if (DefaultOp) 842 { 843 /* If no CASE statements, this is an error - see below */ 844 845 if (CaseOp) 846 { 847 /* Convert the DEFAULT node to an ELSE */ 848 849 TrAmlInitNode (DefaultOp, PARSEOP_ELSE); 850 DefaultOp->Asl.Parent = Conditional->Asl.Parent; 851 852 /* Link ELSE node as a peer to the previous IF */ 853 854 TrAmlInsertPeer (Conditional, DefaultOp); 855 } 856 } 857 858 if (!CaseOp) 859 { 860 AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL); 861 } 862 863 864 /* 865 * Create a Name(_T_x, ...) statement. This statement must appear at the 866 * method level, in case a loop surrounds the switch statement and could 867 * cause the name to be created twice (error). 868 */ 869 870 /* Create the Name node */ 871 872 Predicate = StartNode->Asl.Child; 873 NewOp = TrCreateLeafOp (PARSEOP_NAME); 874 TrAmlInitLineNumbers (NewOp, StartNode); 875 876 /* Find the parent method */ 877 878 Next = StartNode; 879 while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) && 880 (Next->Asl.ParseOpcode != PARSEOP_DEFINITION_BLOCK)) 881 { 882 Next = Next->Asl.Parent; 883 } 884 MethodOp = Next; 885 886 NewOp->Asl.CompileFlags |= OP_COMPILER_EMITTED; 887 NewOp->Asl.Parent = Next; 888 889 /* Insert name after the method name and arguments */ 890 891 Next = Next->Asl.Child; /* Name */ 892 Next = Next->Asl.Next; /* NumArgs */ 893 Next = Next->Asl.Next; /* SerializeRule */ 894 895 /* 896 * If method is not Serialized, we must make is so, because of the way 897 * that Switch() must be implemented -- we cannot allow multiple threads 898 * to execute this method concurrently since we need to create local 899 * temporary name(s). 900 */ 901 if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL) 902 { 903 AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp, 904 "Due to use of Switch operator"); 905 Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL; 906 } 907 908 Next = Next->Asl.Next; /* SyncLevel */ 909 Next = Next->Asl.Next; /* ReturnType */ 910 Next = Next->Asl.Next; /* ParameterTypes */ 911 912 TrAmlInsertPeer (Next, NewOp); 913 TrAmlInitLineNumbers (NewOp, Next); 914 915 /* Create the NameSeg child for the Name node */ 916 917 NewOp2 = TrCreateValuedLeafOp (PARSEOP_NAMESEG, 918 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 919 TrAmlInitLineNumbers (NewOp2, NewOp); 920 NewOp2->Asl.CompileFlags |= OP_IS_NAME_DECLARATION; 921 NewOp->Asl.Child = NewOp2; 922 923 /* Create the initial value for the Name. Btype was already validated above */ 924 925 switch (Btype) 926 { 927 case ACPI_BTYPE_INTEGER: 928 929 NewOp2->Asl.Next = TrCreateValuedLeafOp (PARSEOP_ZERO, 930 (UINT64) 0); 931 TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 932 break; 933 934 case ACPI_BTYPE_STRING: 935 936 NewOp2->Asl.Next = TrCreateValuedLeafOp (PARSEOP_STRING_LITERAL, 937 (UINT64) ACPI_TO_INTEGER ("")); 938 TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 939 break; 940 941 case ACPI_BTYPE_BUFFER: 942 943 (void) TrLinkPeerOp (NewOp2, TrCreateValuedLeafOp (PARSEOP_BUFFER, 944 (UINT64) 0)); 945 Next = NewOp2->Asl.Next; 946 TrAmlInitLineNumbers (Next, NewOp2); 947 948 (void) TrLinkOpChildren (Next, 1, TrCreateValuedLeafOp (PARSEOP_ZERO, 949 (UINT64) 1)); 950 TrAmlInitLineNumbers (Next->Asl.Child, Next); 951 952 BufferOp = TrCreateValuedLeafOp (PARSEOP_DEFAULT_ARG, (UINT64) 0); 953 TrAmlInitLineNumbers (BufferOp, Next->Asl.Child); 954 (void) TrLinkPeerOp (Next->Asl.Child, BufferOp); 955 956 TrAmlSetSubtreeParent (Next->Asl.Child, Next); 957 break; 958 959 default: 960 961 break; 962 } 963 964 TrAmlSetSubtreeParent (NewOp2, NewOp); 965 966 /* 967 * Transform the Switch() into a While(One)-Break node. 968 * And create a Store() node which will be used to save the 969 * Switch() value. The store is of the form: Store (Value, _T_x) 970 * where _T_x is the temp variable. 971 */ 972 TrAmlInitNode (StartNode, PARSEOP_WHILE); 973 NewOp = TrCreateLeafOp (PARSEOP_ONE); 974 TrAmlInitLineNumbers (NewOp, StartNode); 975 NewOp->Asl.Next = Predicate->Asl.Next; 976 NewOp->Asl.Parent = StartNode; 977 StartNode->Asl.Child = NewOp; 978 979 /* Create a Store() node */ 980 981 StoreOp = TrCreateLeafOp (PARSEOP_STORE); 982 TrAmlInitLineNumbers (StoreOp, NewOp); 983 StoreOp->Asl.Parent = StartNode; 984 TrAmlInsertPeer (NewOp, StoreOp); 985 986 /* Complete the Store subtree */ 987 988 StoreOp->Asl.Child = Predicate; 989 Predicate->Asl.Parent = StoreOp; 990 991 NewOp = TrCreateValuedLeafOp (PARSEOP_NAMESEG, 992 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 993 TrAmlInitLineNumbers (NewOp, StoreOp); 994 NewOp->Asl.Parent = StoreOp; 995 Predicate->Asl.Next = NewOp; 996 997 /* Create a Break() node and insert it into the end of While() */ 998 999 Conditional = StartNode->Asl.Child; 1000 while (Conditional->Asl.Next) 1001 { 1002 Conditional = Conditional->Asl.Next; 1003 } 1004 1005 BreakOp = TrCreateLeafOp (PARSEOP_BREAK); 1006 TrAmlInitLineNumbers (BreakOp, NewOp); 1007 BreakOp->Asl.Parent = StartNode; 1008 TrAmlInsertPeer (Conditional, BreakOp); 1009 } 1010 1011 1012 /******************************************************************************* 1013 * 1014 * FUNCTION: TrCheckForDuplicateCase 1015 * 1016 * PARAMETERS: CaseOp - Parse node for first Case statement in list 1017 * Predicate1 - Case value for the input CaseOp 1018 * 1019 * RETURN: None 1020 * 1021 * DESCRIPTION: Check for duplicate case values. Currently, only handles 1022 * Integers, Strings and Buffers. No support for Package objects. 1023 * 1024 ******************************************************************************/ 1025 1026 static void 1027 TrCheckForDuplicateCase ( 1028 ACPI_PARSE_OBJECT *CaseOp, 1029 ACPI_PARSE_OBJECT *Predicate1) 1030 { 1031 ACPI_PARSE_OBJECT *Next; 1032 ACPI_PARSE_OBJECT *Predicate2; 1033 1034 1035 /* Walk the list of CASE opcodes */ 1036 1037 Next = CaseOp->Asl.Next; 1038 while (Next) 1039 { 1040 if (Next->Asl.ParseOpcode == PARSEOP_CASE) 1041 { 1042 /* Emit error only once */ 1043 1044 if (Next->Asl.CompileFlags & OP_IS_DUPLICATE) 1045 { 1046 goto NextCase; 1047 } 1048 1049 /* Check for a duplicate plain integer */ 1050 1051 Predicate2 = Next->Asl.Child; 1052 if ((Predicate1->Asl.ParseOpcode == PARSEOP_INTEGER) && 1053 (Predicate2->Asl.ParseOpcode == PARSEOP_INTEGER)) 1054 { 1055 if (Predicate1->Asl.Value.Integer == Predicate2->Asl.Value.Integer) 1056 { 1057 goto FoundDuplicate; 1058 } 1059 } 1060 1061 /* Check for pairs of the constants ZERO, ONE, ONES */ 1062 1063 else if (((Predicate1->Asl.ParseOpcode == PARSEOP_ZERO) && 1064 (Predicate2->Asl.ParseOpcode == PARSEOP_ZERO)) || 1065 ((Predicate1->Asl.ParseOpcode == PARSEOP_ONE) && 1066 (Predicate2->Asl.ParseOpcode == PARSEOP_ONE)) || 1067 ((Predicate1->Asl.ParseOpcode == PARSEOP_ONES) && 1068 (Predicate2->Asl.ParseOpcode == PARSEOP_ONES))) 1069 { 1070 goto FoundDuplicate; 1071 } 1072 1073 /* Check for a duplicate string constant (literal) */ 1074 1075 else if ((Predicate1->Asl.ParseOpcode == PARSEOP_STRING_LITERAL) && 1076 (Predicate2->Asl.ParseOpcode == PARSEOP_STRING_LITERAL)) 1077 { 1078 if (!strcmp (Predicate1->Asl.Value.String, 1079 Predicate2->Asl.Value.String)) 1080 { 1081 goto FoundDuplicate; 1082 } 1083 } 1084 1085 /* Check for a duplicate buffer constant */ 1086 1087 else if ((Predicate1->Asl.ParseOpcode == PARSEOP_BUFFER) && 1088 (Predicate2->Asl.ParseOpcode == PARSEOP_BUFFER)) 1089 { 1090 if (TrCheckForBufferMatch (Predicate1->Asl.Child, 1091 Predicate2->Asl.Child)) 1092 { 1093 goto FoundDuplicate; 1094 } 1095 } 1096 } 1097 goto NextCase; 1098 1099 FoundDuplicate: 1100 /* Emit error message only once */ 1101 1102 Next->Asl.CompileFlags |= OP_IS_DUPLICATE; 1103 1104 AslDualParseOpError (ASL_ERROR, ASL_MSG_DUPLICATE_CASE, Next, 1105 Next->Asl.Value.String, ASL_MSG_CASE_FOUND_HERE, CaseOp, 1106 CaseOp->Asl.ExternalName); 1107 1108 NextCase: 1109 Next = Next->Asl.Next; 1110 } 1111 } 1112 1113 /******************************************************************************* 1114 * 1115 * FUNCTION: TrBufferIsAllZero 1116 * 1117 * PARAMETERS: Op - Parse node for first opcode in buffer initializer 1118 * list 1119 * 1120 * RETURN: TRUE if buffer contains all zeros or a DEFAULT_ARG 1121 * 1122 * DESCRIPTION: Check for duplicate Buffer case values. 1123 * 1124 ******************************************************************************/ 1125 1126 static BOOLEAN 1127 TrBufferIsAllZero ( 1128 ACPI_PARSE_OBJECT *Op) 1129 { 1130 while (Op) 1131 { 1132 if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 1133 { 1134 return (TRUE); 1135 } 1136 else if (Op->Asl.Value.Integer != 0) 1137 { 1138 return (FALSE); 1139 } 1140 1141 Op = Op->Asl.Next; 1142 } 1143 1144 return (TRUE); 1145 } 1146 1147 1148 /******************************************************************************* 1149 * 1150 * FUNCTION: TrCheckForBufferMatch 1151 * 1152 * PARAMETERS: Next1 - Parse node for first opcode in first buffer list 1153 * (The DEFAULT_ARG or INTEGER node) 1154 * Next2 - Parse node for first opcode in second buffer list 1155 * (The DEFAULT_ARG or INTEGER node) 1156 * 1157 * RETURN: TRUE if buffers match, FALSE otherwise 1158 * 1159 * DESCRIPTION: Check for duplicate Buffer case values. 1160 * 1161 ******************************************************************************/ 1162 1163 static BOOLEAN 1164 TrCheckForBufferMatch ( 1165 ACPI_PARSE_OBJECT *NextOp1, 1166 ACPI_PARSE_OBJECT *NextOp2) 1167 { 1168 /* 1169 * The buffer length can be a DEFAULT_ARG or INTEGER. If any of the nodes 1170 * are DEFAULT_ARG, it means that the length has yet to be computed. 1171 * However, the initializer list can be compared to determine if these two 1172 * buffers match. 1173 */ 1174 if ((NextOp1->Asl.ParseOpcode == PARSEOP_INTEGER && 1175 NextOp2->Asl.ParseOpcode == PARSEOP_INTEGER) && 1176 NextOp1->Asl.Value.Integer != NextOp2->Asl.Value.Integer) 1177 { 1178 return (FALSE); 1179 } 1180 1181 /* 1182 * Buffers that have explicit lengths but no initializer lists are 1183 * filled with zeros at runtime. This is equivalent to buffers that have the 1184 * same length that are filled with zeros. 1185 * 1186 * In other words, the following buffers are equivalent: 1187 * 1188 * Buffer(0x4) {} 1189 * Buffer() {0x0, 0x0, 0x0, 0x0} 1190 * 1191 * This statement checks for matches where one buffer does not have an 1192 * initializer list and another buffer contains all zeros. 1193 */ 1194 if (NextOp1->Asl.ParseOpcode != NextOp2->Asl.ParseOpcode && 1195 TrBufferIsAllZero (NextOp1->Asl.Next) && 1196 TrBufferIsAllZero (NextOp2->Asl.Next)) 1197 { 1198 return (TRUE); 1199 } 1200 1201 /* Start at the BYTECONST initializer node list */ 1202 1203 NextOp1 = NextOp1->Asl.Next; 1204 NextOp2 = NextOp2->Asl.Next; 1205 1206 /* 1207 * Walk both lists until either a mismatch is found, or one or more 1208 * end-of-lists are found 1209 */ 1210 while (NextOp1 && NextOp2) 1211 { 1212 if ((NextOp1->Asl.ParseOpcode == PARSEOP_STRING_LITERAL) && 1213 (NextOp2->Asl.ParseOpcode == PARSEOP_STRING_LITERAL)) 1214 { 1215 if (!strcmp (NextOp1->Asl.Value.String, NextOp2->Asl.Value.String)) 1216 { 1217 return (TRUE); 1218 } 1219 else 1220 { 1221 return (FALSE); 1222 } 1223 } 1224 if ((UINT8) NextOp1->Asl.Value.Integer != (UINT8) NextOp2->Asl.Value.Integer) 1225 { 1226 return (FALSE); 1227 } 1228 1229 NextOp1 = NextOp1->Asl.Next; 1230 NextOp2 = NextOp2->Asl.Next; 1231 } 1232 1233 /* Not a match if one of the lists is not at end-of-list */ 1234 1235 if (NextOp1 || NextOp2) 1236 { 1237 return (FALSE); 1238 } 1239 1240 /* Otherwise, the buffers match */ 1241 1242 return (TRUE); 1243 } 1244 1245 1246 /******************************************************************************* 1247 * 1248 * FUNCTION: TrDoMethod 1249 * 1250 * PARAMETERS: Op - Parse node for SWITCH 1251 * 1252 * RETURN: None 1253 * 1254 * DESCRIPTION: Determine that parameter count of an ASL method node by 1255 * translating the parameter count parse node from 1256 * PARSEOP_DEFAULT_ARG to PARSEOP_BYTECONST. 1257 * 1258 ******************************************************************************/ 1259 1260 static void 1261 TrDoMethod ( 1262 ACPI_PARSE_OBJECT *Op) 1263 { 1264 ACPI_PARSE_OBJECT *ArgCountOp; 1265 UINT8 ArgCount; 1266 ACPI_PARSE_OBJECT *ParameterOp; 1267 1268 1269 /* 1270 * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global, 1271 * however 1272 */ 1273 AslGbl_TempCount = 0; 1274 1275 ArgCountOp = Op->Asl.Child->Asl.Next; 1276 if (ArgCountOp->Asl.ParseOpcode == PARSEOP_BYTECONST) 1277 { 1278 /* 1279 * Parameter count for this method has already been recorded in the 1280 * method declaration. 1281 */ 1282 return; 1283 } 1284 1285 /* 1286 * Parameter count has been omitted in the method declaration. 1287 * Count the amount of arguments here. 1288 */ 1289 ParameterOp = ArgCountOp->Asl.Next->Asl.Next->Asl.Next->Asl.Next; 1290 if (ParameterOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 1291 { 1292 ArgCount = 0; 1293 ParameterOp = ParameterOp->Asl.Child; 1294 1295 while (ParameterOp) 1296 { 1297 ParameterOp = ParameterOp->Asl.Next; 1298 ArgCount++; 1299 } 1300 1301 ArgCountOp->Asl.Value.Integer = ArgCount; 1302 ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST; 1303 } 1304 else 1305 { 1306 /* 1307 * Method parameters can be counted by analyzing the Parameter type 1308 * list. If the Parameter list contains more than 1 parameter, it 1309 * is nested under PARSEOP_DEFAULT_ARG. When there is only 1 1310 * parameter, the parse tree contains a single node representing 1311 * that type. 1312 */ 1313 ArgCountOp->Asl.Value.Integer = 1; 1314 ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST; 1315 } 1316 } 1317