asltransform.c revision 306536
1214501Srpaulo/****************************************************************************** 2214501Srpaulo * 3214501Srpaulo * Module Name: asltransform - Parse tree transforms 4214501Srpaulo * 5214501Srpaulo *****************************************************************************/ 6214501Srpaulo 7214501Srpaulo/* 8214501Srpaulo * Copyright (C) 2000 - 2016, Intel Corp. 9214501Srpaulo * All rights reserved. 10214501Srpaulo * 11214501Srpaulo * Redistribution and use in source and binary forms, with or without 12214501Srpaulo * modification, are permitted provided that the following conditions 13214501Srpaulo * are met: 14214501Srpaulo * 1. Redistributions of source code must retain the above copyright 15214501Srpaulo * notice, this list of conditions, and the following disclaimer, 16214501Srpaulo * without modification. 17214501Srpaulo * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18214501Srpaulo * substantially similar to the "NO WARRANTY" disclaimer below 19214501Srpaulo * ("Disclaimer") and any redistribution must be conditioned upon 20214501Srpaulo * including a substantially similar Disclaimer requirement for further 21214501Srpaulo * binary redistribution. 22214501Srpaulo * 3. Neither the names of the above-listed copyright holders nor the names 23214501Srpaulo * of any contributors may be used to endorse or promote products derived 24214501Srpaulo * from this software without specific prior written permission. 25214501Srpaulo * 26214501Srpaulo * Alternatively, this software may be distributed under the terms of the 27214501Srpaulo * GNU General Public License ("GPL") version 2 as published by the Free 28214501Srpaulo * Software Foundation. 29214501Srpaulo * 30214501Srpaulo * NO WARRANTY 31214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32214501Srpaulo * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33214501Srpaulo * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34214501Srpaulo * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35214501Srpaulo * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39214501Srpaulo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40214501Srpaulo * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41214501Srpaulo * POSSIBILITY OF SUCH DAMAGES. 42214501Srpaulo */ 43214501Srpaulo 44214501Srpaulo#include <contrib/dev/acpica/compiler/aslcompiler.h> 45214501Srpaulo#include "aslcompiler.y.h" 46214501Srpaulo 47214501Srpaulo#define _COMPONENT ACPI_COMPILER 48214501Srpaulo ACPI_MODULE_NAME ("asltransform") 49214501Srpaulo 50214501Srpaulo/* Local prototypes */ 51214501Srpaulo 52214501Srpaulostatic void 53214501SrpauloTrTransformSubtree ( 54214501Srpaulo ACPI_PARSE_OBJECT *Op); 55214501Srpaulo 56214501Srpaulostatic char * 57214501SrpauloTrAmlGetNextTempName ( 58214501Srpaulo ACPI_PARSE_OBJECT *Op, 59214501Srpaulo UINT8 *TempCount); 60214501Srpaulo 61214501Srpaulostatic void 62214501SrpauloTrAmlInitLineNumbers ( 63214501Srpaulo ACPI_PARSE_OBJECT *Op, 64214501Srpaulo ACPI_PARSE_OBJECT *Neighbor); 65214501Srpaulo 66214501Srpaulostatic void 67214501SrpauloTrAmlInitNode ( 68214501Srpaulo ACPI_PARSE_OBJECT *Op, 69214501Srpaulo UINT16 ParseOpcode); 70214501Srpaulo 71214501Srpaulostatic void 72214501SrpauloTrAmlSetSubtreeParent ( 73214501Srpaulo ACPI_PARSE_OBJECT *Op, 74214501Srpaulo ACPI_PARSE_OBJECT *Parent); 75214501Srpaulo 76214501Srpaulostatic void 77214501SrpauloTrAmlInsertPeer ( 78214501Srpaulo ACPI_PARSE_OBJECT *Op, 79214501Srpaulo ACPI_PARSE_OBJECT *NewPeer); 80214501Srpaulo 81214501Srpaulostatic void 82214501SrpauloTrDoDefinitionBlock ( 83214501Srpaulo ACPI_PARSE_OBJECT *Op); 84214501Srpaulo 85214501Srpaulostatic void 86214501SrpauloTrDoSwitch ( 87214501Srpaulo ACPI_PARSE_OBJECT *StartNode); 88214501Srpaulo 89214501Srpaulo 90214501Srpaulo/******************************************************************************* 91214501Srpaulo * 92214501Srpaulo * FUNCTION: TrAmlGetNextTempName 93214501Srpaulo * 94214501Srpaulo * PARAMETERS: Op - Current parse op 95214501Srpaulo * TempCount - Current temporary counter. Was originally 96214501Srpaulo * per-module; Currently per method, could be 97214501Srpaulo * expanded to per-scope. 98214501Srpaulo * 99214501Srpaulo * RETURN: A pointer to name (allocated here). 100214501Srpaulo * 101214501Srpaulo * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are 102214501Srpaulo * reserved for use by the ASL compiler. (_T_0 through _T_Z) 103214501Srpaulo * 104214501Srpaulo ******************************************************************************/ 105214501Srpaulo 106214501Srpaulostatic char * 107214501SrpauloTrAmlGetNextTempName ( 108214501Srpaulo ACPI_PARSE_OBJECT *Op, 109214501Srpaulo UINT8 *TempCount) 110214501Srpaulo{ 111214501Srpaulo char *TempName; 112214501Srpaulo 113214501Srpaulo 114214501Srpaulo if (*TempCount >= (10 + 26)) /* 0-35 valid: 0-9 and A-Z for TempName[3] */ 115214501Srpaulo { 116214501Srpaulo /* Too many temps */ 117214501Srpaulo 118214501Srpaulo AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL); 119214501Srpaulo return (NULL); 120214501Srpaulo } 121214501Srpaulo 122214501Srpaulo TempName = UtLocalCalloc (5); 123214501Srpaulo 124214501Srpaulo if (*TempCount < 10) /* 0-9 */ 125214501Srpaulo { 126214501Srpaulo TempName[3] = (char) (*TempCount + '0'); 127214501Srpaulo } 128214501Srpaulo else /* 10-35: A-Z */ 129214501Srpaulo { 130214501Srpaulo TempName[3] = (char) (*TempCount + ('A' - 10)); 131214501Srpaulo } 132214501Srpaulo 133214501Srpaulo (*TempCount)++; 134214501Srpaulo 135214501Srpaulo /* First three characters are always "_T_" */ 136214501Srpaulo 137214501Srpaulo TempName[0] = '_'; 138214501Srpaulo TempName[1] = 'T'; 139214501Srpaulo TempName[2] = '_'; 140214501Srpaulo 141214501Srpaulo return (TempName); 142214501Srpaulo} 143214501Srpaulo 144214501Srpaulo 145214501Srpaulo/******************************************************************************* 146214501Srpaulo * 147214501Srpaulo * FUNCTION: TrAmlInitLineNumbers 148214501Srpaulo * 149214501Srpaulo * PARAMETERS: Op - Op to be initialized 150214501Srpaulo * Neighbor - Op used for initialization values 151214501Srpaulo * 152214501Srpaulo * RETURN: None 153214501Srpaulo * 154214501Srpaulo * DESCRIPTION: Initialized the various line numbers for a parse node. 155214501Srpaulo * 156214501Srpaulo ******************************************************************************/ 157214501Srpaulo 158214501Srpaulostatic void 159214501SrpauloTrAmlInitLineNumbers ( 160214501Srpaulo ACPI_PARSE_OBJECT *Op, 161214501Srpaulo ACPI_PARSE_OBJECT *Neighbor) 162214501Srpaulo{ 163214501Srpaulo 164214501Srpaulo Op->Asl.EndLine = Neighbor->Asl.EndLine; 165214501Srpaulo Op->Asl.EndLogicalLine = Neighbor->Asl.EndLogicalLine; 166214501Srpaulo Op->Asl.LineNumber = Neighbor->Asl.LineNumber; 167214501Srpaulo Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset; 168214501Srpaulo Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber; 169214501Srpaulo} 170214501Srpaulo 171214501Srpaulo 172214501Srpaulo/******************************************************************************* 173214501Srpaulo * 174214501Srpaulo * FUNCTION: TrAmlInitNode 175214501Srpaulo * 176214501Srpaulo * PARAMETERS: Op - Op to be initialized 177214501Srpaulo * ParseOpcode - Opcode for this node 178214501Srpaulo * 179214501Srpaulo * RETURN: None 180214501Srpaulo * 181214501Srpaulo * DESCRIPTION: Initialize a node with the parse opcode and opcode name. 182214501Srpaulo * 183214501Srpaulo ******************************************************************************/ 184214501Srpaulo 185214501Srpaulostatic void 186214501SrpauloTrAmlInitNode ( 187214501Srpaulo ACPI_PARSE_OBJECT *Op, 188214501Srpaulo UINT16 ParseOpcode) 189214501Srpaulo{ 190214501Srpaulo 191214501Srpaulo Op->Asl.ParseOpcode = ParseOpcode; 192214501Srpaulo UtSetParseOpName (Op); 193214501Srpaulo} 194214501Srpaulo 195214501Srpaulo 196214501Srpaulo/******************************************************************************* 197214501Srpaulo * 198214501Srpaulo * FUNCTION: TrAmlSetSubtreeParent 199214501Srpaulo * 200214501Srpaulo * PARAMETERS: Op - First node in a list of peer nodes 201214501Srpaulo * Parent - Parent of the subtree 202214501Srpaulo * 203214501Srpaulo * RETURN: None 204214501Srpaulo * 205214501Srpaulo * DESCRIPTION: Set the parent for all peer nodes in a subtree 206214501Srpaulo * 207214501Srpaulo ******************************************************************************/ 208214501Srpaulo 209214501Srpaulostatic void 210214501SrpauloTrAmlSetSubtreeParent ( 211214501Srpaulo ACPI_PARSE_OBJECT *Op, 212214501Srpaulo ACPI_PARSE_OBJECT *Parent) 213214501Srpaulo{ 214214501Srpaulo ACPI_PARSE_OBJECT *Next; 215214501Srpaulo 216214501Srpaulo 217214501Srpaulo Next = Op; 218214501Srpaulo while (Next) 219214501Srpaulo { 220214501Srpaulo Next->Asl.Parent = Parent; 221214501Srpaulo Next = Next->Asl.Next; 222214501Srpaulo } 223214501Srpaulo} 224214501Srpaulo 225214501Srpaulo 226214501Srpaulo/******************************************************************************* 227214501Srpaulo * 228214501Srpaulo * FUNCTION: TrAmlInsertPeer 229214501Srpaulo * 230214501Srpaulo * PARAMETERS: Op - First node in a list of peer nodes 231214501Srpaulo * NewPeer - Peer node to insert 232214501Srpaulo * 233214501Srpaulo * RETURN: None 234214501Srpaulo * 235214501Srpaulo * DESCRIPTION: Insert a new peer node into a list of peers. 236214501Srpaulo * 237214501Srpaulo ******************************************************************************/ 238214501Srpaulo 239214501Srpaulostatic void 240214501SrpauloTrAmlInsertPeer ( 241214501Srpaulo ACPI_PARSE_OBJECT *Op, 242214501Srpaulo ACPI_PARSE_OBJECT *NewPeer) 243214501Srpaulo{ 244214501Srpaulo 245214501Srpaulo NewPeer->Asl.Next = Op->Asl.Next; 246214501Srpaulo Op->Asl.Next = NewPeer; 247214501Srpaulo} 248214501Srpaulo 249214501Srpaulo 250214501Srpaulo/******************************************************************************* 251214501Srpaulo * 252214501Srpaulo * FUNCTION: TrAmlTransformWalkBegin 253214501Srpaulo * 254214501Srpaulo * PARAMETERS: ASL_WALK_CALLBACK 255214501Srpaulo * 256214501Srpaulo * RETURN: None 257214501Srpaulo * 258214501Srpaulo * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 259214501Srpaulo * operands. 260214501Srpaulo * 261214501Srpaulo ******************************************************************************/ 262214501Srpaulo 263214501SrpauloACPI_STATUS 264214501SrpauloTrAmlTransformWalkBegin ( 265214501Srpaulo ACPI_PARSE_OBJECT *Op, 266214501Srpaulo UINT32 Level, 267214501Srpaulo void *Context) 268214501Srpaulo{ 269214501Srpaulo 270214501Srpaulo TrTransformSubtree (Op); 271214501Srpaulo return (AE_OK); 272214501Srpaulo} 273214501Srpaulo 274214501Srpaulo 275214501Srpaulo/******************************************************************************* 276214501Srpaulo * 277214501Srpaulo * FUNCTION: TrAmlTransformWalkEnd 278214501Srpaulo * 279214501Srpaulo * PARAMETERS: ASL_WALK_CALLBACK 280214501Srpaulo * 281214501Srpaulo * RETURN: None 282214501Srpaulo * 283214501Srpaulo * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 284214501Srpaulo * operands. 285214501Srpaulo * 286214501Srpaulo ******************************************************************************/ 287214501Srpaulo 288214501SrpauloACPI_STATUS 289214501SrpauloTrAmlTransformWalkEnd ( 290214501Srpaulo ACPI_PARSE_OBJECT *Op, 291214501Srpaulo UINT32 Level, 292214501Srpaulo void *Context) 293214501Srpaulo{ 294214501Srpaulo 295214501Srpaulo /* Save possible Externals list in the DefintionBlock Op */ 296214501Srpaulo 297214501Srpaulo if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 298214501Srpaulo { 299214501Srpaulo Op->Asl.Value.Arg = Gbl_ExternalsListHead; 300214501Srpaulo Gbl_ExternalsListHead = NULL; 301214501Srpaulo } 302214501Srpaulo 303214501Srpaulo return (AE_OK); 304214501Srpaulo} 305214501Srpaulo 306214501Srpaulo 307214501Srpaulo/******************************************************************************* 308214501Srpaulo * 309214501Srpaulo * FUNCTION: TrTransformSubtree 310214501Srpaulo * 311214501Srpaulo * PARAMETERS: Op - The parent parse node 312214501Srpaulo * 313214501Srpaulo * RETURN: None 314214501Srpaulo * 315214501Srpaulo * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more 316214501Srpaulo * complex AML opcodes require processing of the child nodes 317214501Srpaulo * (arguments/operands). 318214501Srpaulo * 319214501Srpaulo ******************************************************************************/ 320214501Srpaulo 321214501Srpaulostatic void 322214501SrpauloTrTransformSubtree ( 323214501Srpaulo ACPI_PARSE_OBJECT *Op) 324214501Srpaulo{ 325214501Srpaulo 326214501Srpaulo if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) 327214501Srpaulo { 328214501Srpaulo return; 329214501Srpaulo } 330214501Srpaulo 331214501Srpaulo switch (Op->Asl.ParseOpcode) 332214501Srpaulo { 333214501Srpaulo case PARSEOP_DEFINITION_BLOCK: 334214501Srpaulo 335214501Srpaulo TrDoDefinitionBlock (Op); 336214501Srpaulo break; 337214501Srpaulo 338214501Srpaulo case PARSEOP_SWITCH: 339214501Srpaulo 340214501Srpaulo TrDoSwitch (Op); 341214501Srpaulo break; 342214501Srpaulo 343214501Srpaulo case PARSEOP_METHOD: 344214501Srpaulo /* 345214501Srpaulo * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global, 346214501Srpaulo * however 347214501Srpaulo */ 348214501Srpaulo Gbl_TempCount = 0; 349214501Srpaulo break; 350214501Srpaulo 351214501Srpaulo case PARSEOP_EXTERNAL: 352214501Srpaulo 353214501Srpaulo if (Gbl_DoExternals == TRUE) 354214501Srpaulo { 355214501Srpaulo ExDoExternal (Op); 356214501Srpaulo } 357214501Srpaulo 358214501Srpaulo break; 359214501Srpaulo 360214501Srpaulo default: 361214501Srpaulo 362214501Srpaulo /* Nothing to do here for other opcodes */ 363214501Srpaulo 364214501Srpaulo break; 365214501Srpaulo } 366214501Srpaulo} 367214501Srpaulo 368214501Srpaulo 369214501Srpaulo/******************************************************************************* 370214501Srpaulo * 371214501Srpaulo * FUNCTION: TrDoDefinitionBlock 372214501Srpaulo * 373214501Srpaulo * PARAMETERS: Op - Parse node 374214501Srpaulo * 375214501Srpaulo * RETURN: None 376214501Srpaulo * 377214501Srpaulo * DESCRIPTION: Find the end of the definition block and set a global to this 378214501Srpaulo * node. It is used by the compiler to insert compiler-generated 379214501Srpaulo * names at the root level of the namespace. 380214501Srpaulo * 381214501Srpaulo ******************************************************************************/ 382214501Srpaulo 383214501Srpaulostatic void 384214501SrpauloTrDoDefinitionBlock ( 385214501Srpaulo ACPI_PARSE_OBJECT *Op) 386214501Srpaulo{ 387214501Srpaulo ACPI_PARSE_OBJECT *Next; 388214501Srpaulo UINT32 i; 389214501Srpaulo 390214501Srpaulo 391214501Srpaulo /* Reset external list when starting a definition block */ 392214501Srpaulo 393214501Srpaulo Gbl_ExternalsListHead = NULL; 394214501Srpaulo 395214501Srpaulo Next = Op->Asl.Child; 396214501Srpaulo for (i = 0; i < 5; i++) 397214501Srpaulo { 398214501Srpaulo Next = Next->Asl.Next; 399214501Srpaulo if (i == 0) 400214501Srpaulo { 401214501Srpaulo /* 402214501Srpaulo * This is the table signature. Only the DSDT can be assumed 403214501Srpaulo * to be at the root of the namespace; Therefore, namepath 404214501Srpaulo * optimization can only be performed on the DSDT. 405214501Srpaulo */ 406214501Srpaulo if (!ACPI_COMPARE_NAME (Next->Asl.Value.String, ACPI_SIG_DSDT)) 407214501Srpaulo { 408214501Srpaulo Gbl_ReferenceOptimizationFlag = FALSE; 409214501Srpaulo } 410214501Srpaulo } 411214501Srpaulo } 412214501Srpaulo 413214501Srpaulo Gbl_FirstLevelInsertionNode = Next; 414214501Srpaulo} 415214501Srpaulo 416214501Srpaulo 417214501Srpaulo/******************************************************************************* 418214501Srpaulo * 419214501Srpaulo * FUNCTION: TrDoSwitch 420214501Srpaulo * 421214501Srpaulo * PARAMETERS: StartNode - Parse node for SWITCH 422214501Srpaulo * 423214501Srpaulo * RETURN: None 424214501Srpaulo * 425214501Srpaulo * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is 426214501Srpaulo * no actual AML opcode for SWITCH -- it must be simulated. 427214501Srpaulo * 428214501Srpaulo ******************************************************************************/ 429214501Srpaulo 430214501Srpaulostatic void 431214501SrpauloTrDoSwitch ( 432214501Srpaulo ACPI_PARSE_OBJECT *StartNode) 433214501Srpaulo{ 434214501Srpaulo ACPI_PARSE_OBJECT *Next; 435214501Srpaulo ACPI_PARSE_OBJECT *CaseOp = NULL; 436214501Srpaulo ACPI_PARSE_OBJECT *CaseBlock = NULL; 437214501Srpaulo ACPI_PARSE_OBJECT *DefaultOp = NULL; 438214501Srpaulo ACPI_PARSE_OBJECT *CurrentParentNode; 439214501Srpaulo ACPI_PARSE_OBJECT *Conditional = NULL; 440214501Srpaulo ACPI_PARSE_OBJECT *Predicate; 441214501Srpaulo ACPI_PARSE_OBJECT *Peer; 442214501Srpaulo ACPI_PARSE_OBJECT *NewOp; 443214501Srpaulo ACPI_PARSE_OBJECT *NewOp2; 444214501Srpaulo ACPI_PARSE_OBJECT *MethodOp; 445214501Srpaulo ACPI_PARSE_OBJECT *StoreOp; 446214501Srpaulo ACPI_PARSE_OBJECT *BreakOp; 447214501Srpaulo ACPI_PARSE_OBJECT *BufferOp; 448214501Srpaulo char *PredicateValueName; 449214501Srpaulo UINT16 Index; 450214501Srpaulo UINT32 Btype; 451214501Srpaulo 452214501Srpaulo 453214501Srpaulo /* Start node is the Switch() node */ 454214501Srpaulo 455214501Srpaulo CurrentParentNode = StartNode; 456214501Srpaulo 457214501Srpaulo /* Create a new temp name of the form _T_x */ 458214501Srpaulo 459214501Srpaulo PredicateValueName = TrAmlGetNextTempName (StartNode, &Gbl_TempCount); 460214501Srpaulo if (!PredicateValueName) 461214501Srpaulo { 462214501Srpaulo return; 463214501Srpaulo } 464214501Srpaulo 465214501Srpaulo /* First child is the Switch() predicate */ 466214501Srpaulo 467214501Srpaulo Next = StartNode->Asl.Child; 468214501Srpaulo 469214501Srpaulo /* 470214501Srpaulo * Examine the return type of the Switch Value - 471214501Srpaulo * must be Integer/Buffer/String 472214501Srpaulo */ 473214501Srpaulo Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); 474214501Srpaulo Btype = AslKeywordMapping[Index].AcpiBtype; 475214501Srpaulo if ((Btype != ACPI_BTYPE_INTEGER) && 476214501Srpaulo (Btype != ACPI_BTYPE_STRING) && 477214501Srpaulo (Btype != ACPI_BTYPE_BUFFER)) 478214501Srpaulo { 479214501Srpaulo AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL); 480214501Srpaulo Btype = ACPI_BTYPE_INTEGER; 481214501Srpaulo } 482214501Srpaulo 483214501Srpaulo /* CASE statements start at next child */ 484214501Srpaulo 485214501Srpaulo Peer = Next->Asl.Next; 486214501Srpaulo while (Peer) 487214501Srpaulo { 488214501Srpaulo Next = Peer; 489214501Srpaulo Peer = Next->Asl.Next; 490214501Srpaulo 491214501Srpaulo if (Next->Asl.ParseOpcode == PARSEOP_CASE) 492214501Srpaulo { 493214501Srpaulo if (CaseOp) 494214501Srpaulo { 495214501Srpaulo /* Add an ELSE to complete the previous CASE */ 496214501Srpaulo 497214501Srpaulo NewOp = TrCreateLeafNode (PARSEOP_ELSE); 498214501Srpaulo NewOp->Asl.Parent = Conditional->Asl.Parent; 499214501Srpaulo TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent); 500214501Srpaulo 501214501Srpaulo /* Link ELSE node as a peer to the previous IF */ 502214501Srpaulo 503214501Srpaulo TrAmlInsertPeer (Conditional, NewOp); 504214501Srpaulo CurrentParentNode = NewOp; 505214501Srpaulo } 506214501Srpaulo 507214501Srpaulo CaseOp = Next; 508214501Srpaulo Conditional = CaseOp; 509214501Srpaulo CaseBlock = CaseOp->Asl.Child->Asl.Next; 510214501Srpaulo Conditional->Asl.Child->Asl.Next = NULL; 511214501Srpaulo Predicate = CaseOp->Asl.Child; 512214501Srpaulo 513214501Srpaulo if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) || 514214501Srpaulo (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) 515214501Srpaulo { 516214501Srpaulo /* 517214501Srpaulo * Convert the package declaration to this form: 518214501Srpaulo * 519214501Srpaulo * If (LNotEqual (Match (Package(<size>){<data>}, 520214501Srpaulo * MEQ, _T_x, MTR, Zero, Zero), Ones)) 521214501Srpaulo */ 522214501Srpaulo NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ); 523214501Srpaulo Predicate->Asl.Next = NewOp2; 524214501Srpaulo TrAmlInitLineNumbers (NewOp2, Conditional); 525214501Srpaulo 526214501Srpaulo NewOp = NewOp2; 527214501Srpaulo NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 528214501Srpaulo (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 529214501Srpaulo NewOp->Asl.Next = NewOp2; 530214501Srpaulo TrAmlInitLineNumbers (NewOp2, Predicate); 531214501Srpaulo 532214501Srpaulo NewOp = NewOp2; 533214501Srpaulo NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR); 534214501Srpaulo NewOp->Asl.Next = NewOp2; 535214501Srpaulo TrAmlInitLineNumbers (NewOp2, Predicate); 536214501Srpaulo 537214501Srpaulo NewOp = NewOp2; 538214501Srpaulo NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 539214501Srpaulo NewOp->Asl.Next = NewOp2; 540214501Srpaulo TrAmlInitLineNumbers (NewOp2, Predicate); 541214501Srpaulo 542214501Srpaulo NewOp = NewOp2; 543214501Srpaulo NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 544214501Srpaulo NewOp->Asl.Next = NewOp2; 545214501Srpaulo TrAmlInitLineNumbers (NewOp2, Predicate); 546214501Srpaulo 547214501Srpaulo NewOp2 = TrCreateLeafNode (PARSEOP_MATCH); 548214501Srpaulo NewOp2->Asl.Child = Predicate; /* PARSEOP_PACKAGE */ 549214501Srpaulo TrAmlInitLineNumbers (NewOp2, Conditional); 550214501Srpaulo TrAmlSetSubtreeParent (Predicate, NewOp2); 551214501Srpaulo 552214501Srpaulo NewOp = NewOp2; 553214501Srpaulo NewOp2 = TrCreateLeafNode (PARSEOP_ONES); 554214501Srpaulo NewOp->Asl.Next = NewOp2; 555214501Srpaulo TrAmlInitLineNumbers (NewOp2, Conditional); 556214501Srpaulo 557214501Srpaulo NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 558214501Srpaulo NewOp2->Asl.Child = NewOp; 559214501Srpaulo NewOp->Asl.Parent = NewOp2; 560214501Srpaulo TrAmlInitLineNumbers (NewOp2, Conditional); 561214501Srpaulo TrAmlSetSubtreeParent (NewOp, NewOp2); 562214501Srpaulo 563214501Srpaulo NewOp = NewOp2; 564214501Srpaulo NewOp2 = TrCreateLeafNode (PARSEOP_LNOT); 565214501Srpaulo NewOp2->Asl.Child = NewOp; 566214501Srpaulo NewOp2->Asl.Parent = Conditional; 567214501Srpaulo NewOp->Asl.Parent = NewOp2; 568214501Srpaulo TrAmlInitLineNumbers (NewOp2, Conditional); 569214501Srpaulo 570214501Srpaulo Conditional->Asl.Child = NewOp2; 571214501Srpaulo NewOp2->Asl.Next = CaseBlock; 572214501Srpaulo } 573214501Srpaulo else 574214501Srpaulo { 575214501Srpaulo /* 576214501Srpaulo * Integer and Buffer case. 577214501Srpaulo * 578214501Srpaulo * Change CaseOp() to: If (LEqual (SwitchValue, CaseValue)) {...} 579214501Srpaulo * Note: SwitchValue is first to allow the CaseValue to be implicitly 580214501Srpaulo * converted to the type of SwitchValue if necessary. 581214501Srpaulo * 582214501Srpaulo * CaseOp->Child is the case value 583214501Srpaulo * CaseOp->Child->Peer is the beginning of the case block 584214501Srpaulo */ 585214501Srpaulo NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 586214501Srpaulo (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 587214501Srpaulo NewOp->Asl.Next = Predicate; 588214501Srpaulo TrAmlInitLineNumbers (NewOp, Predicate); 589214501Srpaulo 590214501Srpaulo NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 591214501Srpaulo NewOp2->Asl.Parent = Conditional; 592214501Srpaulo NewOp2->Asl.Child = NewOp; 593214501Srpaulo TrAmlInitLineNumbers (NewOp2, Conditional); 594214501Srpaulo 595214501Srpaulo TrAmlSetSubtreeParent (NewOp, NewOp2); 596214501Srpaulo 597214501Srpaulo Predicate = NewOp2; 598214501Srpaulo Predicate->Asl.Next = CaseBlock; 599214501Srpaulo 600214501Srpaulo TrAmlSetSubtreeParent (Predicate, Conditional); 601214501Srpaulo Conditional->Asl.Child = Predicate; 602214501Srpaulo } 603214501Srpaulo 604214501Srpaulo /* Reinitialize the CASE node to an IF node */ 605214501Srpaulo 606214501Srpaulo TrAmlInitNode (Conditional, PARSEOP_IF); 607214501Srpaulo 608214501Srpaulo /* 609214501Srpaulo * The first CASE(IF) is not nested under an ELSE. 610214501Srpaulo * All other CASEs are children of a parent ELSE. 611214501Srpaulo */ 612214501Srpaulo if (CurrentParentNode == StartNode) 613214501Srpaulo { 614214501Srpaulo Conditional->Asl.Next = NULL; 615214501Srpaulo } 616214501Srpaulo else 617214501Srpaulo { 618214501Srpaulo /* 619214501Srpaulo * The IF is a child of previous IF/ELSE. It 620214501Srpaulo * is therefore without peer. 621214501Srpaulo */ 622 CurrentParentNode->Asl.Child = Conditional; 623 Conditional->Asl.Parent = CurrentParentNode; 624 Conditional->Asl.Next = NULL; 625 } 626 } 627 else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT) 628 { 629 if (DefaultOp) 630 { 631 /* 632 * More than one Default 633 * (Parser does not catch this, must check here) 634 */ 635 AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL); 636 } 637 else 638 { 639 /* Save the DEFAULT node for later, after CASEs */ 640 641 DefaultOp = Next; 642 } 643 } 644 else 645 { 646 /* Unknown peer opcode */ 647 648 AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n", 649 Next->Asl.ParseOpName, Next->Asl.ParseOpcode); 650 } 651 } 652 653 /* Add the default case at the end of the if/else construct */ 654 655 if (DefaultOp) 656 { 657 /* If no CASE statements, this is an error - see below */ 658 659 if (CaseOp) 660 { 661 /* Convert the DEFAULT node to an ELSE */ 662 663 TrAmlInitNode (DefaultOp, PARSEOP_ELSE); 664 DefaultOp->Asl.Parent = Conditional->Asl.Parent; 665 666 /* Link ELSE node as a peer to the previous IF */ 667 668 TrAmlInsertPeer (Conditional, DefaultOp); 669 } 670 } 671 672 if (!CaseOp) 673 { 674 AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL); 675 } 676 677 678 /* 679 * Create a Name(_T_x, ...) statement. This statement must appear at the 680 * method level, in case a loop surrounds the switch statement and could 681 * cause the name to be created twice (error). 682 */ 683 684 /* Create the Name node */ 685 686 Predicate = StartNode->Asl.Child; 687 NewOp = TrCreateLeafNode (PARSEOP_NAME); 688 TrAmlInitLineNumbers (NewOp, StartNode); 689 690 /* Find the parent method */ 691 692 Next = StartNode; 693 while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) && 694 (Next->Asl.ParseOpcode != PARSEOP_DEFINITION_BLOCK)) 695 { 696 Next = Next->Asl.Parent; 697 } 698 MethodOp = Next; 699 700 NewOp->Asl.CompileFlags |= NODE_COMPILER_EMITTED; 701 NewOp->Asl.Parent = Next; 702 703 /* Insert name after the method name and arguments */ 704 705 Next = Next->Asl.Child; /* Name */ 706 Next = Next->Asl.Next; /* NumArgs */ 707 Next = Next->Asl.Next; /* SerializeRule */ 708 709 /* 710 * If method is not Serialized, we must make is so, because of the way 711 * that Switch() must be implemented -- we cannot allow multiple threads 712 * to execute this method concurrently since we need to create local 713 * temporary name(s). 714 */ 715 if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL) 716 { 717 AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp, 718 "Due to use of Switch operator"); 719 Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL; 720 } 721 722 Next = Next->Asl.Next; /* SyncLevel */ 723 Next = Next->Asl.Next; /* ReturnType */ 724 Next = Next->Asl.Next; /* ParameterTypes */ 725 726 TrAmlInsertPeer (Next, NewOp); 727 TrAmlInitLineNumbers (NewOp, Next); 728 729 /* Create the NameSeg child for the Name node */ 730 731 NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 732 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 733 TrAmlInitLineNumbers (NewOp2, NewOp); 734 NewOp2->Asl.CompileFlags |= NODE_IS_NAME_DECLARATION; 735 NewOp->Asl.Child = NewOp2; 736 737 /* Create the initial value for the Name. Btype was already validated above */ 738 739 switch (Btype) 740 { 741 case ACPI_BTYPE_INTEGER: 742 743 NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_ZERO, 744 (UINT64) 0); 745 TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 746 break; 747 748 case ACPI_BTYPE_STRING: 749 750 NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL, 751 (UINT64) ACPI_TO_INTEGER ("")); 752 TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 753 break; 754 755 case ACPI_BTYPE_BUFFER: 756 757 (void) TrLinkPeerNode (NewOp2, TrCreateValuedLeafNode (PARSEOP_BUFFER, 758 (UINT64) 0)); 759 Next = NewOp2->Asl.Next; 760 TrAmlInitLineNumbers (Next, NewOp2); 761 (void) TrLinkChildren (Next, 1, TrCreateValuedLeafNode (PARSEOP_ZERO, 762 (UINT64) 1)); 763 TrAmlInitLineNumbers (Next->Asl.Child, Next); 764 765 BufferOp = TrCreateValuedLeafNode (PARSEOP_DEFAULT_ARG, (UINT64) 0); 766 TrAmlInitLineNumbers (BufferOp, Next->Asl.Child); 767 (void) TrLinkPeerNode (Next->Asl.Child, BufferOp); 768 769 TrAmlSetSubtreeParent (Next->Asl.Child, Next); 770 break; 771 772 default: 773 774 break; 775 } 776 777 TrAmlSetSubtreeParent (NewOp2, NewOp); 778 779 /* 780 * Transform the Switch() into a While(One)-Break node. 781 * And create a Store() node which will be used to save the 782 * Switch() value. The store is of the form: Store (Value, _T_x) 783 * where _T_x is the temp variable. 784 */ 785 TrAmlInitNode (StartNode, PARSEOP_WHILE); 786 NewOp = TrCreateLeafNode (PARSEOP_ONE); 787 TrAmlInitLineNumbers (NewOp, StartNode); 788 NewOp->Asl.Next = Predicate->Asl.Next; 789 NewOp->Asl.Parent = StartNode; 790 StartNode->Asl.Child = NewOp; 791 792 /* Create a Store() node */ 793 794 StoreOp = TrCreateLeafNode (PARSEOP_STORE); 795 TrAmlInitLineNumbers (StoreOp, NewOp); 796 StoreOp->Asl.Parent = StartNode; 797 TrAmlInsertPeer (NewOp, StoreOp); 798 799 /* Complete the Store subtree */ 800 801 StoreOp->Asl.Child = Predicate; 802 Predicate->Asl.Parent = StoreOp; 803 804 NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 805 (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 806 TrAmlInitLineNumbers (NewOp, StoreOp); 807 NewOp->Asl.Parent = StoreOp; 808 Predicate->Asl.Next = NewOp; 809 810 /* Create a Break() node and insert it into the end of While() */ 811 812 Conditional = StartNode->Asl.Child; 813 while (Conditional->Asl.Next) 814 { 815 Conditional = Conditional->Asl.Next; 816 } 817 818 BreakOp = TrCreateLeafNode (PARSEOP_BREAK); 819 TrAmlInitLineNumbers (BreakOp, NewOp); 820 BreakOp->Asl.Parent = StartNode; 821 TrAmlInsertPeer (Conditional, BreakOp); 822} 823