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