1 /****************************************************************************** 2 * 3 * Module Name: aslexternal - ASL External opcode compiler support 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2019, 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 = TrAllocateOp (PARSEOP_DEFAULT_ARG); 98 99 /* Store External node as child */ 100 101 ListOp->Asl.Child = Op; 102 ListOp->Asl.Next = NULL; 103 104 if (AslGbl_ExternalsListHead) 105 { 106 /* Link new External to end of list */ 107 108 Prev = AslGbl_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 AslGbl_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 = AslGbl_ExternalsListHead; 155 while (Next) 156 { 157 ArgCount = 0; 158 159 /* Skip if External node already handled */ 160 161 if (Next->Asl.Child->Asl.CompileFlags & OP_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 |= OP_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 AslGbl_ExternalsListHead = Op->Asl.Value.Arg; 240 } 241 242 if (!AslGbl_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 AslGbl_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 ACPI_STATUS Status; 331 UINT32 i; 332 333 334 if (!AslGbl_ExternalsListHead) 335 { 336 return; 337 } 338 339 /* Remove the External nodes from the tree */ 340 341 NextOp = AslGbl_ExternalsListHead; 342 while (NextOp) 343 { 344 /* 345 * The External is stored in child pointer of each node in the 346 * list 347 */ 348 ExternalOp = NextOp->Asl.Child; 349 350 /* Get/set the fully qualified name */ 351 352 ExternalName = AcpiNsGetNormalizedPathname (ExternalOp->Asl.Node, TRUE); 353 ExternalOp->Asl.ExternalName = ExternalName; 354 ExternalOp->Asl.Namepath = ExternalName; 355 356 /* Set line numbers (for listings, etc.) */ 357 358 ExternalOp->Asl.LineNumber = 0; 359 ExternalOp->Asl.LogicalLineNumber = 0; 360 361 Next = ExternalOp->Asl.Child; 362 Next->Asl.LineNumber = 0; 363 Next->Asl.LogicalLineNumber = 0; 364 365 if (Next->Asl.ParseOpcode == PARSEOP_NAMESEG) 366 { 367 Next->Asl.ParseOpcode = PARSEOP_NAMESTRING; 368 } 369 370 Next->Asl.ExternalName = ExternalName; 371 Status = UtInternalizeName (ExternalName, &Next->Asl.Value.String); 372 if (ACPI_FAILURE (Status)) 373 { 374 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, 375 Next, "Could not internalize namestring"); 376 return; 377 } 378 379 Next->Asl.AmlLength = strlen (Next->Asl.Value.String); 380 381 Next = Next->Asl.Next; 382 Next->Asl.LineNumber = 0; 383 Next->Asl.LogicalLineNumber = 0; 384 385 Next = Next->Asl.Next; 386 Next->Asl.LineNumber = 0; 387 Next->Asl.LogicalLineNumber = 0; 388 389 Next = Next->Asl.Next; 390 Next->Asl.LineNumber = 0; 391 Next->Asl.LogicalLineNumber = 0; 392 393 ParentOp = ExternalOp->Asl.Parent; 394 Prev = Next = ParentOp->Asl.Child; 395 396 /* Now find the External node's position in parse tree */ 397 398 while (Next != ExternalOp) 399 { 400 Prev = Next; 401 Next = Next->Asl.Next; 402 } 403 404 /* Remove the External from the parse tree */ 405 406 if (Prev == ExternalOp) 407 { 408 /* External was the first child node */ 409 410 ParentOp->Asl.Child = ExternalOp->Asl.Next; 411 } 412 413 Prev->Asl.Next = ExternalOp->Asl.Next; 414 ExternalOp->Asl.Next = NULL; 415 ExternalOp->Asl.Parent = AslGbl_ExternalsListHead; 416 417 /* Point the External to the next in the list */ 418 419 if (NextOp->Asl.Next) 420 { 421 ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child; 422 } 423 424 NextOp = NextOp->Asl.Next; 425 } 426 427 /* 428 * Loop again to remove MethodObj Externals for which 429 * a MethodCall was not found (dead external reference) 430 */ 431 Prev = AslGbl_ExternalsListHead->Asl.Child; 432 Next = Prev; 433 while (Next) 434 { 435 ObjType = (ACPI_OBJECT_TYPE) 436 Next->Asl.Child->Asl.Next->Asl.Value.Integer; 437 438 if (ObjType == ACPI_TYPE_METHOD && 439 !(Next->Asl.CompileFlags & OP_VISITED)) 440 { 441 if (Next == Prev) 442 { 443 AslGbl_ExternalsListHead->Asl.Child = Next->Asl.Next; 444 Next->Asl.Next = NULL; 445 Prev = AslGbl_ExternalsListHead->Asl.Child; 446 Next = Prev; 447 continue; 448 } 449 else 450 { 451 Prev->Asl.Next = Next->Asl.Next; 452 Next->Asl.Next = NULL; 453 Next = Prev->Asl.Next; 454 continue; 455 } 456 } 457 458 Prev = Next; 459 Next = Next->Asl.Next; 460 } 461 462 /* If list is now empty, don't bother to make If (0) block */ 463 464 if (!AslGbl_ExternalsListHead->Asl.Child) 465 { 466 return; 467 } 468 469 /* Convert Gbl_ExternalsListHead parent to If(). */ 470 471 AslGbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF; 472 AslGbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP; 473 AslGbl_ExternalsListHead->Asl.CompileFlags = OP_AML_PACKAGE; 474 UtSetParseOpName (AslGbl_ExternalsListHead); 475 476 /* Create a Zero op for the If predicate */ 477 478 PredicateOp = TrAllocateOp (PARSEOP_ZERO); 479 PredicateOp->Asl.AmlOpcode = AML_ZERO_OP; 480 481 PredicateOp->Asl.Parent = AslGbl_ExternalsListHead; 482 PredicateOp->Asl.Child = NULL; 483 PredicateOp->Asl.Next = AslGbl_ExternalsListHead->Asl.Child; 484 AslGbl_ExternalsListHead->Asl.Child = PredicateOp; 485 486 /* Set line numbers (for listings, etc.) */ 487 488 AslGbl_ExternalsListHead->Asl.LineNumber = 0; 489 AslGbl_ExternalsListHead->Asl.LogicalLineNumber = 0; 490 491 PredicateOp->Asl.LineNumber = 0; 492 PredicateOp->Asl.LogicalLineNumber = 0; 493 494 /* Insert block back in the list */ 495 496 Prev = DefinitionBlockOp->Asl.Child; 497 Next = Prev; 498 499 /* Find last default arg */ 500 501 for (i = 0; i < 6; i++) 502 { 503 Prev = Next; 504 Next = Prev->Asl.Next; 505 } 506 507 if (Next) 508 { 509 /* Definition Block is not empty */ 510 511 AslGbl_ExternalsListHead->Asl.Next = Next; 512 } 513 else 514 { 515 /* Definition Block is empty. */ 516 517 AslGbl_ExternalsListHead->Asl.Next = NULL; 518 } 519 520 Prev->Asl.Next = AslGbl_ExternalsListHead; 521 AslGbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent; 522 } 523