1 /****************************************************************************** 2 * 3 * Module Name: dmextern - Support for External() ASL statements 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, 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/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/amlcode.h> 47 #include <contrib/dev/acpica/include/acnamesp.h> 48 #include <contrib/dev/acpica/include/acdisasm.h> 49 50 51 /* 52 * This module is used for application-level code (iASL disassembler) only. 53 * 54 * It contains the code to create and emit any necessary External() ASL 55 * statements for the module being disassembled. 56 */ 57 #define _COMPONENT ACPI_CA_DISASSEMBLER 58 ACPI_MODULE_NAME ("dmextern") 59 60 61 /* 62 * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL 63 * ObjectTypeKeyword. Used to generate typed external declarations 64 */ 65 static const char *AcpiGbl_DmTypeNames[] = 66 { 67 /* 00 */ "", /* Type ANY */ 68 /* 01 */ ", IntObj", 69 /* 02 */ ", StrObj", 70 /* 03 */ ", BuffObj", 71 /* 04 */ ", PkgObj", 72 /* 05 */ ", FieldUnitObj", 73 /* 06 */ ", DeviceObj", 74 /* 07 */ ", EventObj", 75 /* 08 */ ", MethodObj", 76 /* 09 */ ", MutexObj", 77 /* 10 */ ", OpRegionObj", 78 /* 11 */ ", PowerResObj", 79 /* 12 */ ", ProcessorObj", 80 /* 13 */ ", ThermalZoneObj", 81 /* 14 */ ", BuffFieldObj", 82 /* 15 */ ", DDBHandleObj", 83 /* 16 */ "", /* Debug object */ 84 /* 17 */ ", FieldUnitObj", 85 /* 18 */ ", FieldUnitObj", 86 /* 19 */ ", FieldUnitObj" 87 }; 88 89 90 /* Local prototypes */ 91 92 static const char * 93 AcpiDmGetObjectTypeName ( 94 ACPI_OBJECT_TYPE Type); 95 96 static char * 97 AcpiDmNormalizeParentPrefix ( 98 ACPI_PARSE_OBJECT *Op, 99 char *Path); 100 101 102 /******************************************************************************* 103 * 104 * FUNCTION: AcpiDmGetObjectTypeName 105 * 106 * PARAMETERS: Type - An ACPI_OBJECT_TYPE 107 * 108 * RETURN: Pointer to a string 109 * 110 * DESCRIPTION: Map an object type to the ASL object type string. 111 * 112 ******************************************************************************/ 113 114 static const char * 115 AcpiDmGetObjectTypeName ( 116 ACPI_OBJECT_TYPE Type) 117 { 118 119 if (Type == ACPI_TYPE_LOCAL_SCOPE) 120 { 121 Type = ACPI_TYPE_DEVICE; 122 } 123 124 else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD) 125 { 126 return (""); 127 } 128 129 return (AcpiGbl_DmTypeNames[Type]); 130 } 131 132 133 /******************************************************************************* 134 * 135 * FUNCTION: AcpiDmNormalizeParentPrefix 136 * 137 * PARAMETERS: Op - Parse op 138 * Path - Path with parent prefix 139 * 140 * RETURN: The full pathname to the object (from the namespace root) 141 * 142 * DESCRIPTION: Returns the full pathname of a path with parent prefix 143 * The caller must free the fullpath returned. 144 * 145 ******************************************************************************/ 146 147 static char * 148 AcpiDmNormalizeParentPrefix ( 149 ACPI_PARSE_OBJECT *Op, 150 char *Path) 151 { 152 ACPI_NAMESPACE_NODE *Node; 153 char *Fullpath; 154 char *ParentPath; 155 ACPI_SIZE Length; 156 157 158 /* Search upwards in the parse tree until we reach a namespace node */ 159 160 while (Op) 161 { 162 if (Op->Common.Node) 163 { 164 break; 165 } 166 167 Op = Op->Common.Parent; 168 } 169 170 if (!Op) 171 { 172 return (NULL); 173 } 174 175 /* 176 * Find the actual parent node for the reference: 177 * Remove all carat prefixes from the input path. 178 * There may be multiple parent prefixes (For example, ^^^M000) 179 */ 180 Node = Op->Common.Node; 181 while (Node && (*Path == (UINT8) AML_PARENT_PREFIX)) 182 { 183 Node = Node->Parent; 184 Path++; 185 } 186 187 if (!Node) 188 { 189 return (NULL); 190 } 191 192 /* Get the full pathname for the parent node */ 193 194 ParentPath = AcpiNsGetExternalPathname (Node); 195 if (!ParentPath) 196 { 197 return (NULL); 198 } 199 200 Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1); 201 if (ParentPath[1]) 202 { 203 /* 204 * If ParentPath is not just a simple '\', increment the length 205 * for the required dot separator (ParentPath.Path) 206 */ 207 Length++; 208 } 209 210 Fullpath = ACPI_ALLOCATE_ZEROED (Length); 211 if (!Fullpath) 212 { 213 goto Cleanup; 214 } 215 216 /* 217 * Concatenate parent fullpath and path. For example, 218 * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT" 219 * 220 * Copy the parent path 221 */ 222 ACPI_STRCAT (Fullpath, ParentPath); 223 224 /* Add dot separator (don't need dot if parent fullpath is a single "\") */ 225 226 if (ParentPath[1]) 227 { 228 ACPI_STRCAT (Fullpath, "."); 229 } 230 231 /* Copy child path (carat parent prefix(es) were skipped above) */ 232 233 ACPI_STRCAT (Fullpath, Path); 234 235 Cleanup: 236 ACPI_FREE (ParentPath); 237 return (Fullpath); 238 } 239 240 241 /******************************************************************************* 242 * 243 * FUNCTION: AcpiDmAddToExternalFileList 244 * 245 * PARAMETERS: PathList - Single path or list separated by comma 246 * 247 * RETURN: None 248 * 249 * DESCRIPTION: Add external files to global list 250 * 251 ******************************************************************************/ 252 253 ACPI_STATUS 254 AcpiDmAddToExternalFileList ( 255 char *PathList) 256 { 257 ACPI_EXTERNAL_FILE *ExternalFile; 258 char *Path; 259 char *TmpPath; 260 261 262 if (!PathList) 263 { 264 return (AE_OK); 265 } 266 267 Path = strtok (PathList, ","); 268 269 while (Path) 270 { 271 TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1); 272 if (!TmpPath) 273 { 274 return (AE_NO_MEMORY); 275 } 276 277 ACPI_STRCPY (TmpPath, Path); 278 279 ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE)); 280 if (!ExternalFile) 281 { 282 ACPI_FREE (TmpPath); 283 return (AE_NO_MEMORY); 284 } 285 286 ExternalFile->Path = TmpPath; 287 288 if (AcpiGbl_ExternalFileList) 289 { 290 ExternalFile->Next = AcpiGbl_ExternalFileList; 291 } 292 293 AcpiGbl_ExternalFileList = ExternalFile; 294 Path = strtok (NULL, ","); 295 } 296 297 return (AE_OK); 298 } 299 300 301 /******************************************************************************* 302 * 303 * FUNCTION: AcpiDmClearExternalFileList 304 * 305 * PARAMETERS: None 306 * 307 * RETURN: None 308 * 309 * DESCRIPTION: Clear the external file list 310 * 311 ******************************************************************************/ 312 313 void 314 AcpiDmClearExternalFileList ( 315 void) 316 { 317 ACPI_EXTERNAL_FILE *NextExternal; 318 319 320 while (AcpiGbl_ExternalFileList) 321 { 322 NextExternal = AcpiGbl_ExternalFileList->Next; 323 ACPI_FREE (AcpiGbl_ExternalFileList->Path); 324 ACPI_FREE (AcpiGbl_ExternalFileList); 325 AcpiGbl_ExternalFileList = NextExternal; 326 } 327 } 328 329 330 /******************************************************************************* 331 * 332 * FUNCTION: AcpiDmAddToExternalList 333 * 334 * PARAMETERS: Op - Current parser Op 335 * Path - Internal (AML) path to the object 336 * Type - ACPI object type to be added 337 * Value - Arg count if adding a Method object 338 * 339 * RETURN: None 340 * 341 * DESCRIPTION: Insert a new name into the global list of Externals which 342 * will in turn be later emitted as an External() declaration 343 * in the disassembled output. 344 * 345 ******************************************************************************/ 346 347 void 348 AcpiDmAddToExternalList ( 349 ACPI_PARSE_OBJECT *Op, 350 char *Path, 351 UINT8 Type, 352 UINT32 Value) 353 { 354 char *ExternalPath; 355 char *Fullpath = NULL; 356 ACPI_EXTERNAL_LIST *NewExternal; 357 ACPI_EXTERNAL_LIST *NextExternal; 358 ACPI_EXTERNAL_LIST *PrevExternal = NULL; 359 ACPI_STATUS Status; 360 361 362 if (!Path) 363 { 364 return; 365 } 366 367 /* Externalize the ACPI path */ 368 369 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path, 370 NULL, &ExternalPath); 371 if (ACPI_FAILURE (Status)) 372 { 373 return; 374 } 375 376 /* Get the full pathname from root if "Path" has a parent prefix */ 377 378 if (*Path == (UINT8) AML_PARENT_PREFIX) 379 { 380 Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath); 381 if (Fullpath) 382 { 383 /* Set new external path */ 384 385 ACPI_FREE (ExternalPath); 386 ExternalPath = Fullpath; 387 } 388 } 389 390 /* Check all existing externals to ensure no duplicates */ 391 392 NextExternal = AcpiGbl_ExternalList; 393 while (NextExternal) 394 { 395 if (!ACPI_STRCMP (ExternalPath, NextExternal->Path)) 396 { 397 /* Duplicate method, check that the Value (ArgCount) is the same */ 398 399 if ((NextExternal->Type == ACPI_TYPE_METHOD) && 400 (NextExternal->Value != Value)) 401 { 402 ACPI_ERROR ((AE_INFO, 403 "Argument count mismatch for method %s %u %u", 404 NextExternal->Path, NextExternal->Value, Value)); 405 } 406 407 /* Allow upgrade of type from ANY */ 408 409 else if (NextExternal->Type == ACPI_TYPE_ANY) 410 { 411 NextExternal->Type = Type; 412 NextExternal->Value = Value; 413 } 414 415 ACPI_FREE (ExternalPath); 416 return; 417 } 418 419 NextExternal = NextExternal->Next; 420 } 421 422 /* Allocate and init a new External() descriptor */ 423 424 NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST)); 425 if (!NewExternal) 426 { 427 ACPI_FREE (ExternalPath); 428 return; 429 } 430 431 NewExternal->Path = ExternalPath; 432 NewExternal->Type = Type; 433 NewExternal->Value = Value; 434 NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath); 435 436 /* Was the external path with parent prefix normalized to a fullpath? */ 437 438 if (Fullpath == ExternalPath) 439 { 440 /* Get new internal path */ 441 442 Status = AcpiNsInternalizeName (ExternalPath, &Path); 443 if (ACPI_FAILURE (Status)) 444 { 445 ACPI_FREE (ExternalPath); 446 ACPI_FREE (NewExternal); 447 return; 448 } 449 450 /* Set flag to indicate External->InternalPath need to be freed */ 451 452 NewExternal->Flags |= ACPI_IPATH_ALLOCATED; 453 } 454 455 NewExternal->InternalPath = Path; 456 457 /* Link the new descriptor into the global list, ordered by string length */ 458 459 NextExternal = AcpiGbl_ExternalList; 460 while (NextExternal) 461 { 462 if (NewExternal->Length <= NextExternal->Length) 463 { 464 if (PrevExternal) 465 { 466 PrevExternal->Next = NewExternal; 467 } 468 else 469 { 470 AcpiGbl_ExternalList = NewExternal; 471 } 472 473 NewExternal->Next = NextExternal; 474 return; 475 } 476 477 PrevExternal = NextExternal; 478 NextExternal = NextExternal->Next; 479 } 480 481 if (PrevExternal) 482 { 483 PrevExternal->Next = NewExternal; 484 } 485 else 486 { 487 AcpiGbl_ExternalList = NewExternal; 488 } 489 } 490 491 492 /******************************************************************************* 493 * 494 * FUNCTION: AcpiDmAddExternalsToNamespace 495 * 496 * PARAMETERS: None 497 * 498 * RETURN: None 499 * 500 * DESCRIPTION: Add all externals to the namespace. Allows externals to be 501 * "resolved". 502 * 503 ******************************************************************************/ 504 505 void 506 AcpiDmAddExternalsToNamespace ( 507 void) 508 { 509 ACPI_STATUS Status; 510 ACPI_NAMESPACE_NODE *Node; 511 ACPI_OPERAND_OBJECT *MethodDesc; 512 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 513 514 515 while (External) 516 { 517 /* Add the external name (object) into the namespace */ 518 519 Status = AcpiNsLookup (NULL, External->InternalPath, External->Type, 520 ACPI_IMODE_LOAD_PASS1, 521 ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE, 522 NULL, &Node); 523 524 if (ACPI_FAILURE (Status)) 525 { 526 ACPI_EXCEPTION ((AE_INFO, Status, 527 "while adding external to namespace [%s]", 528 External->Path)); 529 } 530 else if (External->Type == ACPI_TYPE_METHOD) 531 { 532 /* For methods, we need to save the argument count */ 533 534 MethodDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); 535 MethodDesc->Method.ParamCount = (UINT8) External->Value; 536 Node->Object = MethodDesc; 537 } 538 539 External = External->Next; 540 } 541 } 542 543 544 /******************************************************************************* 545 * 546 * FUNCTION: AcpiDmGetExternalMethodCount 547 * 548 * PARAMETERS: None 549 * 550 * RETURN: The number of control method externals in the external list 551 * 552 * DESCRIPTION: Return the number of method externals that have been generated. 553 * If any control method externals have been found, we must 554 * re-parse the entire definition block with the new information 555 * (number of arguments for the methods.) This is limitation of 556 * AML, we don't know the number of arguments from the control 557 * method invocation itself. 558 * 559 ******************************************************************************/ 560 561 UINT32 562 AcpiDmGetExternalMethodCount ( 563 void) 564 { 565 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 566 UINT32 Count = 0; 567 568 569 while (External) 570 { 571 if (External->Type == ACPI_TYPE_METHOD) 572 { 573 Count++; 574 } 575 576 External = External->Next; 577 } 578 579 return (Count); 580 } 581 582 583 /******************************************************************************* 584 * 585 * FUNCTION: AcpiDmClearExternalList 586 * 587 * PARAMETERS: None 588 * 589 * RETURN: None 590 * 591 * DESCRIPTION: Free the entire External info list 592 * 593 ******************************************************************************/ 594 595 void 596 AcpiDmClearExternalList ( 597 void) 598 { 599 ACPI_EXTERNAL_LIST *NextExternal; 600 601 602 while (AcpiGbl_ExternalList) 603 { 604 NextExternal = AcpiGbl_ExternalList->Next; 605 ACPI_FREE (AcpiGbl_ExternalList->Path); 606 ACPI_FREE (AcpiGbl_ExternalList); 607 AcpiGbl_ExternalList = NextExternal; 608 } 609 } 610 611 612 /******************************************************************************* 613 * 614 * FUNCTION: AcpiDmEmitExternals 615 * 616 * PARAMETERS: None 617 * 618 * RETURN: None 619 * 620 * DESCRIPTION: Emit an External() ASL statement for each of the externals in 621 * the global external info list. 622 * 623 ******************************************************************************/ 624 625 void 626 AcpiDmEmitExternals ( 627 void) 628 { 629 ACPI_EXTERNAL_LIST *NextExternal; 630 631 632 if (!AcpiGbl_ExternalList) 633 { 634 return; 635 } 636 637 /* 638 * Walk the list of externals (unresolved references) 639 * found during the AML parsing 640 */ 641 while (AcpiGbl_ExternalList) 642 { 643 AcpiOsPrintf (" External (%s%s", 644 AcpiGbl_ExternalList->Path, 645 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type)); 646 647 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) 648 { 649 AcpiOsPrintf (") // %u Arguments\n", 650 AcpiGbl_ExternalList->Value); 651 } 652 else 653 { 654 AcpiOsPrintf (")\n"); 655 } 656 657 /* Free this external info block and move on to next external */ 658 659 NextExternal = AcpiGbl_ExternalList->Next; 660 if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED) 661 { 662 ACPI_FREE (AcpiGbl_ExternalList->InternalPath); 663 } 664 665 ACPI_FREE (AcpiGbl_ExternalList->Path); 666 ACPI_FREE (AcpiGbl_ExternalList); 667 AcpiGbl_ExternalList = NextExternal; 668 } 669 670 AcpiOsPrintf ("\n"); 671 } 672 673