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 char *ExternalName; 329 ACPI_OBJECT_TYPE ObjType; 330 UINT32 i; 331 332 333 if (!Gbl_ExternalsListHead) 334 { 335 return; 336 } 337 338 /* Remove the External nodes from the tree */ 339 340 NextOp = Gbl_ExternalsListHead; 341 while (NextOp) 342 { 343 /* 344 * The External is stored in child pointer of each node in the 345 * list 346 */ 347 ExternalOp = NextOp->Asl.Child; 348 349 /* Get/set the fully qualified name */ 350 351 ExternalName = AcpiNsGetNormalizedPathname (ExternalOp->Asl.Node, TRUE); 352 ExternalOp->Asl.ExternalName = ExternalName; 353 ExternalOp->Asl.Namepath = ExternalName; 354 355 /* Set line numbers (for listings, etc.) */ 356 357 ExternalOp->Asl.LineNumber = 0; 358 ExternalOp->Asl.LogicalLineNumber = 0; 359 360 Next = ExternalOp->Asl.Child; 361 Next->Asl.LineNumber = 0; 362 Next->Asl.LogicalLineNumber = 0; 363 364 if (Next->Asl.ParseOpcode == PARSEOP_NAMESEG) 365 { 366 Next->Asl.ParseOpcode = PARSEOP_NAMESTRING; 367 } 368 Next->Asl.ExternalName = ExternalName; 369 UtInternalizeName (ExternalName, &Next->Asl.Value.String); 370 Next->Asl.AmlLength = strlen (Next->Asl.Value.String); 371 372 Next = Next->Asl.Next; 373 Next->Asl.LineNumber = 0; 374 Next->Asl.LogicalLineNumber = 0; 375 376 Next = Next->Asl.Next; 377 Next->Asl.LineNumber = 0; 378 Next->Asl.LogicalLineNumber = 0; 379 380 Next = Next->Asl.Next; 381 Next->Asl.LineNumber = 0; 382 Next->Asl.LogicalLineNumber = 0; 383 384 ParentOp = ExternalOp->Asl.Parent; 385 Prev = Next = ParentOp->Asl.Child; 386 387 /* Now find the External node's position in parse tree */ 388 389 while (Next != ExternalOp) 390 { 391 Prev = Next; 392 Next = Next->Asl.Next; 393 } 394 395 /* Remove the External from the parse tree */ 396 397 if (Prev == ExternalOp) 398 { 399 /* External was the first child node */ 400 401 ParentOp->Asl.Child = ExternalOp->Asl.Next; 402 } 403 404 Prev->Asl.Next = ExternalOp->Asl.Next; 405 ExternalOp->Asl.Next = NULL; 406 ExternalOp->Asl.Parent = Gbl_ExternalsListHead; 407 408 /* Point the External to the next in the list */ 409 410 if (NextOp->Asl.Next) 411 { 412 ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child; 413 } 414 415 NextOp = NextOp->Asl.Next; 416 } 417 418 /* 419 * Loop again to remove MethodObj Externals for which 420 * a MethodCall was not found (dead external reference) 421 */ 422 Prev = Gbl_ExternalsListHead->Asl.Child; 423 Next = Prev; 424 while (Next) 425 { 426 ObjType = (ACPI_OBJECT_TYPE) 427 Next->Asl.Child->Asl.Next->Asl.Value.Integer; 428 429 if (ObjType == ACPI_TYPE_METHOD && 430 !(Next->Asl.CompileFlags & NODE_VISITED)) 431 { 432 if (Next == Prev) 433 { 434 Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next; 435 Next->Asl.Next = NULL; 436 Prev = Gbl_ExternalsListHead->Asl.Child; 437 Next = Prev; 438 continue; 439 } 440 else 441 { 442 Prev->Asl.Next = Next->Asl.Next; 443 Next->Asl.Next = NULL; 444 Next = Prev->Asl.Next; 445 continue; 446 } 447 } 448 449 Prev = Next; 450 Next = Next->Asl.Next; 451 } 452 453 /* If list is now empty, don't bother to make If (0) block */ 454 455 if (!Gbl_ExternalsListHead->Asl.Child) 456 { 457 return; 458 } 459 460 /* Convert Gbl_ExternalsListHead parent to If(). */ 461 462 Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF; 463 Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP; 464 Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE; 465 UtSetParseOpName (Gbl_ExternalsListHead); 466 467 /* Create a Zero op for the If predicate */ 468 469 PredicateOp = TrAllocateNode (PARSEOP_ZERO); 470 PredicateOp->Asl.AmlOpcode = AML_ZERO_OP; 471 472 PredicateOp->Asl.Parent = Gbl_ExternalsListHead; 473 PredicateOp->Asl.Child = NULL; 474 PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child; 475 Gbl_ExternalsListHead->Asl.Child = PredicateOp; 476 477 /* Set line numbers (for listings, etc.) */ 478 479 Gbl_ExternalsListHead->Asl.LineNumber = 0; 480 Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0; 481 482 PredicateOp->Asl.LineNumber = 0; 483 PredicateOp->Asl.LogicalLineNumber = 0; 484 485 /* Insert block back in the list */ 486 487 Prev = DefinitionBlockOp->Asl.Child; 488 Next = Prev; 489 490 /* Find last default arg */ 491 492 for (i = 0; i < 6; i++) 493 { 494 Prev = Next; 495 Next = Prev->Asl.Next; 496 } 497 498 if (Next) 499 { 500 /* Definition Block is not empty */ 501 502 Gbl_ExternalsListHead->Asl.Next = Next; 503 } 504 else 505 { 506 /* Definition Block is empty. */ 507 508 Gbl_ExternalsListHead->Asl.Next = NULL; 509 } 510 511 Prev->Asl.Next = Gbl_ExternalsListHead; 512 Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent; 513 } 514