1 /****************************************************************************** 2 * 3 * Module Name: aslexternal - ASL External opcode compiler support 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, 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 #include "acparser.h" 47 #include "amlcode.h" 48 #include "acnamesp.h" 49 50 51 #define _COMPONENT ACPI_COMPILER 52 ACPI_MODULE_NAME ("aslexternal") 53 54 55 /* Local prototypes */ 56 57 static void 58 ExInsertArgCount ( 59 ACPI_PARSE_OBJECT *Op); 60 61 static void 62 ExMoveExternals ( 63 ACPI_PARSE_OBJECT *DefinitionBlockOp); 64 65 66 /******************************************************************************* 67 * 68 * FUNCTION: ExDoExternal 69 * 70 * PARAMETERS: Op - Current Parse node 71 * 72 * RETURN: None 73 * 74 * DESCRIPTION: Add an External() definition to the global list. This list 75 * is used to generate External opcodes. 76 * 77 ******************************************************************************/ 78 79 void 80 ExDoExternal ( 81 ACPI_PARSE_OBJECT *Op) 82 { 83 ACPI_PARSE_OBJECT *ListOp; 84 ACPI_PARSE_OBJECT *Prev; 85 ACPI_PARSE_OBJECT *Next; 86 ACPI_PARSE_OBJECT *ArgCountOp; 87 88 89 ArgCountOp = Op->Asl.Child->Asl.Next->Asl.Next; 90 ArgCountOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 91 ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST; 92 ArgCountOp->Asl.Value.Integer = 0; 93 UtSetParseOpName (ArgCountOp); 94 95 /* Create new list node of arbitrary type */ 96 97 ListOp = TrAllocateNode (PARSEOP_DEFAULT_ARG); 98 99 /* Store External node as child */ 100 101 ListOp->Asl.Child = Op; 102 ListOp->Asl.Next = NULL; 103 104 if (Gbl_ExternalsListHead) 105 { 106 /* Link new External to end of list */ 107 108 Prev = Gbl_ExternalsListHead; 109 Next = Prev; 110 while (Next) 111 { 112 Prev = Next; 113 Next = Next->Asl.Next; 114 } 115 116 Prev->Asl.Next = ListOp; 117 } 118 else 119 { 120 Gbl_ExternalsListHead = ListOp; 121 } 122 } 123 124 125 /******************************************************************************* 126 * 127 * FUNCTION: ExInsertArgCount 128 * 129 * PARAMETERS: Op - Op for a method invocation 130 * 131 * RETURN: None 132 * 133 * DESCRIPTION: Obtain the number of arguments for a control method -- from 134 * the actual invocation. 135 * 136 ******************************************************************************/ 137 138 static void 139 ExInsertArgCount ( 140 ACPI_PARSE_OBJECT *Op) 141 { 142 ACPI_PARSE_OBJECT *Next; 143 ACPI_PARSE_OBJECT *NameOp; 144 ACPI_PARSE_OBJECT *Child; 145 ACPI_PARSE_OBJECT *ArgCountOp; 146 char * ExternalName; 147 char * CallName; 148 UINT16 ArgCount = 0; 149 150 151 CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE); 152 153 Next = Gbl_ExternalsListHead; 154 while (Next) 155 { 156 ArgCount = 0; 157 158 /* Skip if External node already handled */ 159 160 if (Next->Asl.Child->Asl.CompileFlags & NODE_VISITED) 161 { 162 Next = Next->Asl.Next; 163 continue; 164 } 165 166 NameOp = Next->Asl.Child->Asl.Child; 167 ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE); 168 169 if (!strcmp (CallName, ExternalName)) 170 { 171 Next->Asl.Child->Asl.CompileFlags |= NODE_VISITED; 172 173 /* 174 * Since we will reposition Externals to the Root, set Namepath 175 * to the fully qualified name and recalculate the aml length 176 */ 177 if (ACPI_FAILURE (UtInternalizeName ( 178 ExternalName, &NameOp->Asl.Value.String))) 179 { 180 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, 181 NULL, "- Could not Internalize External"); 182 183 break; 184 } 185 186 NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String); 187 188 /* Get argument count */ 189 190 Child = Op->Asl.Child; 191 while (Child) 192 { 193 ArgCount++; 194 Child = Child->Asl.Next; 195 } 196 197 /* Setup ArgCount operand */ 198 199 ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next; 200 ArgCountOp->Asl.Value.Integer = ArgCount; 201 break; 202 } 203 204 Next = Next->Asl.Next; 205 } 206 } 207 208 209 /******************************************************************************* 210 * 211 * FUNCTION: ExAmlExternalWalkBegin 212 * 213 * PARAMETERS: ASL_WALK_CALLBACK 214 * 215 * RETURN: None 216 * 217 * DESCRIPTION: Parse tree walk to create external opcode list for methods. 218 * 219 ******************************************************************************/ 220 221 ACPI_STATUS 222 ExAmlExternalWalkBegin ( 223 ACPI_PARSE_OBJECT *Op, 224 UINT32 Level, 225 void *Context) 226 { 227 228 /* External list head saved in the definition block op */ 229 230 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 231 { 232 Gbl_ExternalsListHead = Op->Asl.Value.Arg; 233 } 234 235 if (!Gbl_ExternalsListHead) 236 { 237 return (AE_OK); 238 } 239 240 if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL) 241 { 242 return (AE_OK); 243 } 244 245 /* 246 * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL 247 * by XfNamespaceLocateBegin(). Ignore these. 248 */ 249 if (Op->Asl.Parent && 250 Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL) 251 { 252 return (AE_OK); 253 } 254 255 ExInsertArgCount (Op); 256 return (AE_OK); 257 } 258 259 260 /******************************************************************************* 261 * 262 * FUNCTION: ExAmlExternalWalkEnd 263 * 264 * PARAMETERS: ASL_WALK_CALLBACK 265 * 266 * RETURN: None 267 * 268 * DESCRIPTION: Parse tree walk to create external opcode list for methods. 269 * Here, we just want to catch the case where a definition block 270 * has been completed. Then we move all of the externals into 271 * a single block in the parse tree and thus the AML code. 272 * 273 ******************************************************************************/ 274 275 ACPI_STATUS 276 ExAmlExternalWalkEnd ( 277 ACPI_PARSE_OBJECT *Op, 278 UINT32 Level, 279 void *Context) 280 { 281 282 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 283 { 284 /* 285 * Process any existing external list. (Support for 286 * multiple definition blocks in a single file/compile) 287 */ 288 ExMoveExternals (Op); 289 Gbl_ExternalsListHead = NULL; 290 } 291 292 return (AE_OK); 293 } 294 295 296 /******************************************************************************* 297 * 298 * FUNCTION: ExMoveExternals 299 * 300 * PARAMETERS: DefinitionBlockOp - Op for current definition block 301 * 302 * RETURN: None 303 * 304 * DESCRIPTION: Move all externals present in the source file into a single 305 * block of AML code, surrounded by an "If (0)" to prevent 306 * AML interpreters from attempting to execute the External 307 * opcodes. 308 * 309 ******************************************************************************/ 310 311 static void 312 ExMoveExternals ( 313 ACPI_PARSE_OBJECT *DefinitionBlockOp) 314 { 315 ACPI_PARSE_OBJECT *ParentOp; 316 ACPI_PARSE_OBJECT *ExternalOp; 317 ACPI_PARSE_OBJECT *PredicateOp; 318 ACPI_PARSE_OBJECT *NextOp; 319 ACPI_PARSE_OBJECT *Prev; 320 ACPI_PARSE_OBJECT *Next; 321 ACPI_OBJECT_TYPE ObjType; 322 UINT32 i; 323 324 325 if (!Gbl_ExternalsListHead) 326 { 327 return; 328 } 329 330 /* Remove the External nodes from the tree */ 331 332 NextOp = Gbl_ExternalsListHead; 333 while (NextOp) 334 { 335 /* 336 * The External is stored in child pointer of each node in the 337 * list 338 */ 339 ExternalOp = NextOp->Asl.Child; 340 341 /* Set line numbers (for listings, etc.) */ 342 343 ExternalOp->Asl.LineNumber = 0; 344 ExternalOp->Asl.LogicalLineNumber = 0; 345 346 Next = ExternalOp->Asl.Child; 347 Next->Asl.LineNumber = 0; 348 Next->Asl.LogicalLineNumber = 0; 349 350 Next = Next->Asl.Next; 351 Next->Asl.LineNumber = 0; 352 Next->Asl.LogicalLineNumber = 0; 353 354 Next = Next->Asl.Next; 355 Next->Asl.LineNumber = 0; 356 Next->Asl.LogicalLineNumber = 0; 357 358 Next = Next->Asl.Next; 359 Next->Asl.LineNumber = 0; 360 Next->Asl.LogicalLineNumber = 0; 361 362 ParentOp = ExternalOp->Asl.Parent; 363 Prev = Next = ParentOp->Asl.Child; 364 365 /* Now find the External node's position in parse tree */ 366 367 while (Next != ExternalOp) 368 { 369 Prev = Next; 370 Next = Next->Asl.Next; 371 } 372 373 /* Remove the External from the parse tree */ 374 375 if (Prev == ExternalOp) 376 { 377 /* External was the first child node */ 378 379 ParentOp->Asl.Child = ExternalOp->Asl.Next; 380 } 381 382 Prev->Asl.Next = ExternalOp->Asl.Next; 383 ExternalOp->Asl.Next = NULL; 384 ExternalOp->Asl.Parent = Gbl_ExternalsListHead; 385 386 /* Point the External to the next in the list */ 387 388 if (NextOp->Asl.Next) 389 { 390 ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child; 391 } 392 393 NextOp = NextOp->Asl.Next; 394 } 395 396 /* 397 * Loop again to remove MethodObj Externals for which 398 * a MethodCall was not found (dead external reference) 399 */ 400 Prev = Gbl_ExternalsListHead->Asl.Child; 401 Next = Prev; 402 while (Next) 403 { 404 ObjType = (ACPI_OBJECT_TYPE) 405 Next->Asl.Child->Asl.Next->Asl.Value.Integer; 406 407 if (ObjType == ACPI_TYPE_METHOD && 408 !(Next->Asl.CompileFlags & NODE_VISITED)) 409 { 410 if (Next == Prev) 411 { 412 Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next; 413 Next->Asl.Next = NULL; 414 Prev = Gbl_ExternalsListHead->Asl.Child; 415 Next = Prev; 416 continue; 417 } 418 else 419 { 420 Prev->Asl.Next = Next->Asl.Next; 421 Next->Asl.Next = NULL; 422 Next = Prev->Asl.Next; 423 continue; 424 } 425 } 426 427 Prev = Next; 428 Next = Next->Asl.Next; 429 } 430 431 /* If list is now empty, don't bother to make If (0) block */ 432 433 if (!Gbl_ExternalsListHead->Asl.Child) 434 { 435 return; 436 } 437 438 /* Convert Gbl_ExternalsListHead parent to If(). */ 439 440 Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF; 441 Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP; 442 Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE; 443 UtSetParseOpName (Gbl_ExternalsListHead); 444 445 /* Create a Zero op for the If predicate */ 446 447 PredicateOp = TrAllocateNode (PARSEOP_ZERO); 448 PredicateOp->Asl.AmlOpcode = AML_ZERO_OP; 449 450 PredicateOp->Asl.Parent = Gbl_ExternalsListHead; 451 PredicateOp->Asl.Child = NULL; 452 PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child; 453 Gbl_ExternalsListHead->Asl.Child = PredicateOp; 454 455 /* Set line numbers (for listings, etc.) */ 456 457 Gbl_ExternalsListHead->Asl.LineNumber = 0; 458 Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0; 459 460 PredicateOp->Asl.LineNumber = 0; 461 PredicateOp->Asl.LogicalLineNumber = 0; 462 463 /* Insert block back in the list */ 464 465 Prev = DefinitionBlockOp->Asl.Child; 466 Next = Prev; 467 468 /* Find last default arg */ 469 470 for (i = 0; i < 6; i++) 471 { 472 Prev = Next; 473 Next = Prev->Asl.Next; 474 } 475 476 if (Next) 477 { 478 /* Definition Block is not empty */ 479 480 Gbl_ExternalsListHead->Asl.Next = Next; 481 } 482 else 483 { 484 /* Definition Block is empty. */ 485 486 Gbl_ExternalsListHead->Asl.Next = NULL; 487 } 488 489 Prev->Asl.Next = Gbl_ExternalsListHead; 490 Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent; 491 } 492