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 <contrib/dev/acpica/compiler/aslcompiler.h> 45 #include "aslcompiler.y.h" 46 #include <contrib/dev/acpica/include/acparser.h> 47 #include <contrib/dev/acpica/include/amlcode.h> 48 #include <contrib/dev/acpica/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 ACPI_STATUS Status; 150 151 152 CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE); 153 154 Next = Gbl_ExternalsListHead; 155 while (Next) 156 { 157 ArgCount = 0; 158 159 /* Skip if External node already handled */ 160 161 if (Next->Asl.Child->Asl.CompileFlags & NODE_VISITED) 162 { 163 Next = Next->Asl.Next; 164 continue; 165 } 166 167 NameOp = Next->Asl.Child->Asl.Child; 168 ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE); 169 170 if (strcmp (CallName, ExternalName)) 171 { 172 ACPI_FREE (ExternalName); 173 Next = Next->Asl.Next; 174 continue; 175 } 176 177 Next->Asl.Child->Asl.CompileFlags |= NODE_VISITED; 178 179 /* 180 * Since we will reposition Externals to the Root, set Namepath 181 * to the fully qualified name and recalculate the aml length 182 */ 183 Status = UtInternalizeName (ExternalName, 184 &NameOp->Asl.Value.String); 185 186 ACPI_FREE (ExternalName); 187 if (ACPI_FAILURE (Status)) 188 { 189 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, 190 NULL, "- Could not Internalize External"); 191 break; 192 } 193 194 NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String); 195 196 /* Get argument count */ 197 198 Child = Op->Asl.Child; 199 while (Child) 200 { 201 ArgCount++; 202 Child = Child->Asl.Next; 203 } 204 205 /* Setup ArgCount operand */ 206 207 ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next; 208 ArgCountOp->Asl.Value.Integer = ArgCount; 209 break; 210 } 211 212 ACPI_FREE (CallName); 213 } 214 215 216 /******************************************************************************* 217 * 218 * FUNCTION: ExAmlExternalWalkBegin 219 * 220 * PARAMETERS: ASL_WALK_CALLBACK 221 * 222 * RETURN: None 223 * 224 * DESCRIPTION: Parse tree walk to create external opcode list for methods. 225 * 226 ******************************************************************************/ 227 228 ACPI_STATUS 229 ExAmlExternalWalkBegin ( 230 ACPI_PARSE_OBJECT *Op, 231 UINT32 Level, 232 void *Context) 233 { 234 235 /* External list head saved in the definition block op */ 236 237 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 238 { 239 Gbl_ExternalsListHead = Op->Asl.Value.Arg; 240 } 241 242 if (!Gbl_ExternalsListHead) 243 { 244 return (AE_OK); 245 } 246 247 if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL) 248 { 249 return (AE_OK); 250 } 251 252 /* 253 * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL 254 * by XfNamespaceLocateBegin(). Ignore these. 255 */ 256 if (Op->Asl.Parent && 257 Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL) 258 { 259 return (AE_OK); 260 } 261 262 ExInsertArgCount (Op); 263 return (AE_OK); 264 } 265 266 267 /******************************************************************************* 268 * 269 * FUNCTION: ExAmlExternalWalkEnd 270 * 271 * PARAMETERS: ASL_WALK_CALLBACK 272 * 273 * RETURN: None 274 * 275 * DESCRIPTION: Parse tree walk to create external opcode list for methods. 276 * Here, we just want to catch the case where a definition block 277 * has been completed. Then we move all of the externals into 278 * a single block in the parse tree and thus the AML code. 279 * 280 ******************************************************************************/ 281 282 ACPI_STATUS 283 ExAmlExternalWalkEnd ( 284 ACPI_PARSE_OBJECT *Op, 285 UINT32 Level, 286 void *Context) 287 { 288 289 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 290 { 291 /* 292 * Process any existing external list. (Support for 293 * multiple definition blocks in a single file/compile) 294 */ 295 ExMoveExternals (Op); 296 Gbl_ExternalsListHead = NULL; 297 } 298 299 return (AE_OK); 300 } 301 302 303 /******************************************************************************* 304 * 305 * FUNCTION: ExMoveExternals 306 * 307 * PARAMETERS: DefinitionBlockOp - Op for current definition block 308 * 309 * RETURN: None 310 * 311 * DESCRIPTION: Move all externals present in the source file into a single 312 * block of AML code, surrounded by an "If (0)" to prevent 313 * AML interpreters from attempting to execute the External 314 * opcodes. 315 * 316 ******************************************************************************/ 317 318 static void 319 ExMoveExternals ( 320 ACPI_PARSE_OBJECT *DefinitionBlockOp) 321 { 322 ACPI_PARSE_OBJECT *ParentOp; 323 ACPI_PARSE_OBJECT *ExternalOp; 324 ACPI_PARSE_OBJECT *PredicateOp; 325 ACPI_PARSE_OBJECT *NextOp; 326 ACPI_PARSE_OBJECT *Prev; 327 ACPI_PARSE_OBJECT *Next; 328 ACPI_OBJECT_TYPE ObjType; 329 UINT32 i; 330 331 332 if (!Gbl_ExternalsListHead) 333 { 334 return; 335 } 336 337 /* Remove the External nodes from the tree */ 338 339 NextOp = Gbl_ExternalsListHead; 340 while (NextOp) 341 { 342 /* 343 * The External is stored in child pointer of each node in the 344 * list 345 */ 346 ExternalOp = NextOp->Asl.Child; 347 348 /* Set line numbers (for listings, etc.) */ 349 350 ExternalOp->Asl.LineNumber = 0; 351 ExternalOp->Asl.LogicalLineNumber = 0; 352 353 Next = ExternalOp->Asl.Child; 354 Next->Asl.LineNumber = 0; 355 Next->Asl.LogicalLineNumber = 0; 356 357 Next = Next->Asl.Next; 358 Next->Asl.LineNumber = 0; 359 Next->Asl.LogicalLineNumber = 0; 360 361 Next = Next->Asl.Next; 362 Next->Asl.LineNumber = 0; 363 Next->Asl.LogicalLineNumber = 0; 364 365 Next = Next->Asl.Next; 366 Next->Asl.LineNumber = 0; 367 Next->Asl.LogicalLineNumber = 0; 368 369 ParentOp = ExternalOp->Asl.Parent; 370 Prev = Next = ParentOp->Asl.Child; 371 372 /* Now find the External node's position in parse tree */ 373 374 while (Next != ExternalOp) 375 { 376 Prev = Next; 377 Next = Next->Asl.Next; 378 } 379 380 /* Remove the External from the parse tree */ 381 382 if (Prev == ExternalOp) 383 { 384 /* External was the first child node */ 385 386 ParentOp->Asl.Child = ExternalOp->Asl.Next; 387 } 388 389 Prev->Asl.Next = ExternalOp->Asl.Next; 390 ExternalOp->Asl.Next = NULL; 391 ExternalOp->Asl.Parent = Gbl_ExternalsListHead; 392 393 /* Point the External to the next in the list */ 394 395 if (NextOp->Asl.Next) 396 { 397 ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child; 398 } 399 400 NextOp = NextOp->Asl.Next; 401 } 402 403 /* 404 * Loop again to remove MethodObj Externals for which 405 * a MethodCall was not found (dead external reference) 406 */ 407 Prev = Gbl_ExternalsListHead->Asl.Child; 408 Next = Prev; 409 while (Next) 410 { 411 ObjType = (ACPI_OBJECT_TYPE) 412 Next->Asl.Child->Asl.Next->Asl.Value.Integer; 413 414 if (ObjType == ACPI_TYPE_METHOD && 415 !(Next->Asl.CompileFlags & NODE_VISITED)) 416 { 417 if (Next == Prev) 418 { 419 Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next; 420 Next->Asl.Next = NULL; 421 Prev = Gbl_ExternalsListHead->Asl.Child; 422 Next = Prev; 423 continue; 424 } 425 else 426 { 427 Prev->Asl.Next = Next->Asl.Next; 428 Next->Asl.Next = NULL; 429 Next = Prev->Asl.Next; 430 continue; 431 } 432 } 433 434 Prev = Next; 435 Next = Next->Asl.Next; 436 } 437 438 /* If list is now empty, don't bother to make If (0) block */ 439 440 if (!Gbl_ExternalsListHead->Asl.Child) 441 { 442 return; 443 } 444 445 /* Convert Gbl_ExternalsListHead parent to If(). */ 446 447 Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF; 448 Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP; 449 Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE; 450 UtSetParseOpName (Gbl_ExternalsListHead); 451 452 /* Create a Zero op for the If predicate */ 453 454 PredicateOp = TrAllocateNode (PARSEOP_ZERO); 455 PredicateOp->Asl.AmlOpcode = AML_ZERO_OP; 456 457 PredicateOp->Asl.Parent = Gbl_ExternalsListHead; 458 PredicateOp->Asl.Child = NULL; 459 PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child; 460 Gbl_ExternalsListHead->Asl.Child = PredicateOp; 461 462 /* Set line numbers (for listings, etc.) */ 463 464 Gbl_ExternalsListHead->Asl.LineNumber = 0; 465 Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0; 466 467 PredicateOp->Asl.LineNumber = 0; 468 PredicateOp->Asl.LogicalLineNumber = 0; 469 470 /* Insert block back in the list */ 471 472 Prev = DefinitionBlockOp->Asl.Child; 473 Next = Prev; 474 475 /* Find last default arg */ 476 477 for (i = 0; i < 6; i++) 478 { 479 Prev = Next; 480 Next = Prev->Asl.Next; 481 } 482 483 if (Next) 484 { 485 /* Definition Block is not empty */ 486 487 Gbl_ExternalsListHead->Asl.Next = Next; 488 } 489 else 490 { 491 /* Definition Block is empty. */ 492 493 Gbl_ExternalsListHead->Asl.Next = NULL; 494 } 495 496 Prev->Asl.Next = Gbl_ExternalsListHead; 497 Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent; 498 } 499