1 /****************************************************************************** 2 * 3 * Module Name: aslexternal - ASL External opcode compiler support 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2020, 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 ACPI_PARSE_OBJECT *TypeOp; 88 ACPI_PARSE_OBJECT *ExternTypeOp = Op->Asl.Child->Asl.Next; 89 UINT32 ExternType; 90 UINT8 ParamCount = ASL_EXTERNAL_METHOD_UNKNOWN_PARAMS; 91 UINT32 ParamTypes[ACPI_METHOD_NUM_ARGS]; 92 93 94 ExternType = AnMapObjTypeToBtype (ExternTypeOp); 95 96 /* 97 * The parser allows optional parameter return types regardless of the 98 * type. Check object type keyword emit error if optional parameter/return 99 * types exist. 100 * 101 * Check the parameter return type 102 */ 103 TypeOp = ExternTypeOp->Asl.Next; 104 if (TypeOp->Asl.Child) 105 { 106 /* Ignore the return type for now. */ 107 108 (void) MtProcessTypeOp (TypeOp->Asl.Child); 109 if (ExternType != ACPI_BTYPE_METHOD) 110 { 111 sprintf (AslGbl_MsgBuffer, "Found type [%s]", AcpiUtGetTypeName(ExternType)); 112 AslError (ASL_ERROR, ASL_MSG_EXTERN_INVALID_RET_TYPE, TypeOp, 113 AslGbl_MsgBuffer); 114 } 115 } 116 117 /* Check the parameter types */ 118 119 TypeOp = TypeOp->Asl.Next; 120 if (TypeOp->Asl.Child) 121 { 122 ParamCount = MtProcessParameterTypeList (TypeOp->Asl.Child, ParamTypes); 123 if (ExternType != ACPI_BTYPE_METHOD) 124 { 125 sprintf (AslGbl_MsgBuffer, "Found type [%s]", AcpiUtGetTypeName(ExternType)); 126 AslError (ASL_ERROR, ASL_MSG_EXTERN_INVALID_PARAM_TYPE, TypeOp, 127 AslGbl_MsgBuffer); 128 } 129 } 130 131 ArgCountOp = Op->Asl.Child->Asl.Next->Asl.Next; 132 ArgCountOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE; 133 ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST; 134 ArgCountOp->Asl.Value.Integer = ParamCount; 135 UtSetParseOpName (ArgCountOp); 136 137 /* Create new list node of arbitrary type */ 138 139 ListOp = TrAllocateOp (PARSEOP_DEFAULT_ARG); 140 141 /* Store External node as child */ 142 143 ListOp->Asl.Child = Op; 144 ListOp->Asl.Next = NULL; 145 146 if (AslGbl_ExternalsListHead) 147 { 148 /* Link new External to end of list */ 149 150 Prev = AslGbl_ExternalsListHead; 151 Next = Prev; 152 while (Next) 153 { 154 Prev = Next; 155 Next = Next->Asl.Next; 156 } 157 158 Prev->Asl.Next = ListOp; 159 } 160 else 161 { 162 AslGbl_ExternalsListHead = ListOp; 163 } 164 } 165 166 167 /******************************************************************************* 168 * 169 * FUNCTION: ExInsertArgCount 170 * 171 * PARAMETERS: Op - Op for a method invocation 172 * 173 * RETURN: None 174 * 175 * DESCRIPTION: Obtain the number of arguments for a control method -- from 176 * the actual invocation. 177 * 178 ******************************************************************************/ 179 180 static void 181 ExInsertArgCount ( 182 ACPI_PARSE_OBJECT *Op) 183 { 184 ACPI_PARSE_OBJECT *Next; 185 ACPI_PARSE_OBJECT *NameOp; 186 ACPI_PARSE_OBJECT *Child; 187 ACPI_PARSE_OBJECT *ArgCountOp; 188 char * ExternalName; 189 char * CallName; 190 UINT16 ArgCount = 0; 191 ACPI_STATUS Status; 192 193 194 CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE); 195 196 Next = AslGbl_ExternalsListHead; 197 while (Next) 198 { 199 ArgCount = 0; 200 201 /* Skip if External node already handled */ 202 203 if (Next->Asl.Child->Asl.CompileFlags & OP_VISITED) 204 { 205 Next = Next->Asl.Next; 206 continue; 207 } 208 209 NameOp = Next->Asl.Child->Asl.Child; 210 ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE); 211 212 if (strcmp (CallName, ExternalName)) 213 { 214 ACPI_FREE (ExternalName); 215 Next = Next->Asl.Next; 216 continue; 217 } 218 219 Next->Asl.Child->Asl.CompileFlags |= OP_VISITED; 220 221 /* 222 * Since we will reposition Externals to the Root, set Namepath 223 * to the fully qualified name and recalculate the aml length 224 */ 225 Status = UtInternalizeName (ExternalName, 226 &NameOp->Asl.Value.String); 227 228 ACPI_FREE (ExternalName); 229 if (ACPI_FAILURE (Status)) 230 { 231 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, 232 NULL, "- Could not Internalize External"); 233 break; 234 } 235 236 NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String); 237 238 /* Get argument count */ 239 240 Child = Op->Asl.Child; 241 while (Child) 242 { 243 ArgCount++; 244 Child = Child->Asl.Next; 245 } 246 247 /* Setup ArgCount operand */ 248 249 ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next; 250 ArgCountOp->Asl.Value.Integer = ArgCount; 251 break; 252 } 253 254 ACPI_FREE (CallName); 255 } 256 257 258 /******************************************************************************* 259 * 260 * FUNCTION: ExAmlExternalWalkBegin 261 * 262 * PARAMETERS: ASL_WALK_CALLBACK 263 * 264 * RETURN: None 265 * 266 * DESCRIPTION: Parse tree walk to create external opcode list for methods. 267 * 268 ******************************************************************************/ 269 270 ACPI_STATUS 271 ExAmlExternalWalkBegin ( 272 ACPI_PARSE_OBJECT *Op, 273 UINT32 Level, 274 void *Context) 275 { 276 277 /* External list head saved in the definition block op */ 278 279 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 280 { 281 AslGbl_ExternalsListHead = Op->Asl.Value.Arg; 282 } 283 284 if (!AslGbl_ExternalsListHead) 285 { 286 return (AE_OK); 287 } 288 289 if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL) 290 { 291 return (AE_OK); 292 } 293 294 /* 295 * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL 296 * by XfNamespaceLocateBegin(). Ignore these. 297 */ 298 if (Op->Asl.Parent && 299 Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL) 300 { 301 return (AE_OK); 302 } 303 304 ExInsertArgCount (Op); 305 return (AE_OK); 306 } 307 308 309 /******************************************************************************* 310 * 311 * FUNCTION: ExAmlExternalWalkEnd 312 * 313 * PARAMETERS: ASL_WALK_CALLBACK 314 * 315 * RETURN: None 316 * 317 * DESCRIPTION: Parse tree walk to create external opcode list for methods. 318 * Here, we just want to catch the case where a definition block 319 * has been completed. Then we move all of the externals into 320 * a single block in the parse tree and thus the AML code. 321 * 322 ******************************************************************************/ 323 324 ACPI_STATUS 325 ExAmlExternalWalkEnd ( 326 ACPI_PARSE_OBJECT *Op, 327 UINT32 Level, 328 void *Context) 329 { 330 331 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 332 { 333 /* 334 * Process any existing external list. (Support for 335 * multiple definition blocks in a single file/compile) 336 */ 337 ExMoveExternals (Op); 338 AslGbl_ExternalsListHead = NULL; 339 } 340 341 return (AE_OK); 342 } 343 344 345 /******************************************************************************* 346 * 347 * FUNCTION: ExMoveExternals 348 * 349 * PARAMETERS: DefinitionBlockOp - Op for current definition block 350 * 351 * RETURN: None 352 * 353 * DESCRIPTION: Move all externals present in the source file into a single 354 * block of AML code, surrounded by an "If (0)" to prevent 355 * AML interpreters from attempting to execute the External 356 * opcodes. 357 * 358 ******************************************************************************/ 359 360 static void 361 ExMoveExternals ( 362 ACPI_PARSE_OBJECT *DefinitionBlockOp) 363 { 364 ACPI_PARSE_OBJECT *ParentOp; 365 ACPI_PARSE_OBJECT *ExternalOp; 366 ACPI_PARSE_OBJECT *PredicateOp; 367 ACPI_PARSE_OBJECT *NextOp; 368 ACPI_PARSE_OBJECT *Prev; 369 ACPI_PARSE_OBJECT *Next; 370 char *ExternalName; 371 ACPI_OBJECT_TYPE ObjType; 372 ACPI_STATUS Status; 373 UINT32 i; 374 375 376 if (!AslGbl_ExternalsListHead) 377 { 378 return; 379 } 380 381 /* Remove the External nodes from the tree */ 382 383 NextOp = AslGbl_ExternalsListHead; 384 while (NextOp) 385 { 386 /* 387 * The External is stored in child pointer of each node in the 388 * list 389 */ 390 ExternalOp = NextOp->Asl.Child; 391 392 /* Get/set the fully qualified name */ 393 394 ExternalName = AcpiNsGetNormalizedPathname (ExternalOp->Asl.Node, TRUE); 395 ExternalOp->Asl.ExternalName = ExternalName; 396 ExternalOp->Asl.Namepath = ExternalName; 397 398 /* Set line numbers (for listings, etc.) */ 399 400 ExternalOp->Asl.LineNumber = 0; 401 ExternalOp->Asl.LogicalLineNumber = 0; 402 403 Next = ExternalOp->Asl.Child; 404 Next->Asl.LineNumber = 0; 405 Next->Asl.LogicalLineNumber = 0; 406 407 if (Next->Asl.ParseOpcode == PARSEOP_NAMESEG) 408 { 409 Next->Asl.ParseOpcode = PARSEOP_NAMESTRING; 410 } 411 412 Next->Asl.ExternalName = ExternalName; 413 Status = UtInternalizeName (ExternalName, &Next->Asl.Value.String); 414 if (ACPI_FAILURE (Status)) 415 { 416 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, 417 Next, "Could not internalize namestring"); 418 return; 419 } 420 421 Next->Asl.AmlLength = strlen (Next->Asl.Value.String); 422 423 Next = Next->Asl.Next; 424 Next->Asl.LineNumber = 0; 425 Next->Asl.LogicalLineNumber = 0; 426 427 Next = Next->Asl.Next; 428 Next->Asl.LineNumber = 0; 429 Next->Asl.LogicalLineNumber = 0; 430 431 Next = Next->Asl.Next; 432 Next->Asl.LineNumber = 0; 433 Next->Asl.LogicalLineNumber = 0; 434 435 ParentOp = ExternalOp->Asl.Parent; 436 Prev = Next = ParentOp->Asl.Child; 437 438 /* Now find the External node's position in parse tree */ 439 440 while (Next != ExternalOp) 441 { 442 Prev = Next; 443 Next = Next->Asl.Next; 444 } 445 446 /* Remove the External from the parse tree */ 447 448 if (Prev == ExternalOp) 449 { 450 /* External was the first child node */ 451 452 ParentOp->Asl.Child = ExternalOp->Asl.Next; 453 } 454 455 Prev->Asl.Next = ExternalOp->Asl.Next; 456 ExternalOp->Asl.Next = NULL; 457 ExternalOp->Asl.Parent = AslGbl_ExternalsListHead; 458 459 /* Point the External to the next in the list */ 460 461 if (NextOp->Asl.Next) 462 { 463 ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child; 464 } 465 466 NextOp = NextOp->Asl.Next; 467 } 468 469 /* 470 * Loop again to remove MethodObj Externals for which 471 * a MethodCall was not found (dead external reference) 472 */ 473 Prev = AslGbl_ExternalsListHead->Asl.Child; 474 Next = Prev; 475 while (Next) 476 { 477 ObjType = (ACPI_OBJECT_TYPE) 478 Next->Asl.Child->Asl.Next->Asl.Value.Integer; 479 480 if (ObjType == ACPI_TYPE_METHOD && 481 !(Next->Asl.CompileFlags & OP_VISITED)) 482 { 483 if (Next == Prev) 484 { 485 AslGbl_ExternalsListHead->Asl.Child = Next->Asl.Next; 486 Next->Asl.Next = NULL; 487 Prev = AslGbl_ExternalsListHead->Asl.Child; 488 Next = Prev; 489 continue; 490 } 491 else 492 { 493 Prev->Asl.Next = Next->Asl.Next; 494 Next->Asl.Next = NULL; 495 Next = Prev->Asl.Next; 496 continue; 497 } 498 } 499 500 Prev = Next; 501 Next = Next->Asl.Next; 502 } 503 504 /* If list is now empty, don't bother to make If (0) block */ 505 506 if (!AslGbl_ExternalsListHead->Asl.Child) 507 { 508 return; 509 } 510 511 /* Convert Gbl_ExternalsListHead parent to If(). */ 512 513 AslGbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF; 514 AslGbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP; 515 AslGbl_ExternalsListHead->Asl.CompileFlags = OP_AML_PACKAGE; 516 UtSetParseOpName (AslGbl_ExternalsListHead); 517 518 /* Create a Zero op for the If predicate */ 519 520 PredicateOp = TrAllocateOp (PARSEOP_ZERO); 521 PredicateOp->Asl.AmlOpcode = AML_ZERO_OP; 522 523 PredicateOp->Asl.Parent = AslGbl_ExternalsListHead; 524 PredicateOp->Asl.Child = NULL; 525 PredicateOp->Asl.Next = AslGbl_ExternalsListHead->Asl.Child; 526 AslGbl_ExternalsListHead->Asl.Child = PredicateOp; 527 528 /* Set line numbers (for listings, etc.) */ 529 530 AslGbl_ExternalsListHead->Asl.LineNumber = 0; 531 AslGbl_ExternalsListHead->Asl.LogicalLineNumber = 0; 532 533 PredicateOp->Asl.LineNumber = 0; 534 PredicateOp->Asl.LogicalLineNumber = 0; 535 536 /* Insert block back in the list */ 537 538 Prev = DefinitionBlockOp->Asl.Child; 539 Next = Prev; 540 541 /* Find last default arg */ 542 543 for (i = 0; i < 6; i++) 544 { 545 Prev = Next; 546 Next = Prev->Asl.Next; 547 } 548 549 if (Next) 550 { 551 /* Definition Block is not empty */ 552 553 AslGbl_ExternalsListHead->Asl.Next = Next; 554 } 555 else 556 { 557 /* Definition Block is empty. */ 558 559 AslGbl_ExternalsListHead->Asl.Next = NULL; 560 } 561 562 Prev->Asl.Next = AslGbl_ExternalsListHead; 563 AslGbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent; 564 } 565