1 /****************************************************************************** 2 * 3 * Module Name: dmextern - Support for External() ASL statements 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 "acpi.h" 45 #include "accommon.h" 46 #include "amlcode.h" 47 #include "acnamesp.h" 48 #include "acdisasm.h" 49 #include "aslcompiler.h" 50 #include <stdio.h> 51 #include <errno.h> 52 53 54 /* 55 * This module is used for application-level code (iASL disassembler) only. 56 * 57 * It contains the code to create and emit any necessary External() ASL 58 * statements for the module being disassembled. 59 */ 60 #define _COMPONENT ACPI_CA_DISASSEMBLER 61 ACPI_MODULE_NAME ("dmextern") 62 63 64 /* 65 * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL 66 * ObjectTypeKeyword. Used to generate typed external declarations 67 */ 68 static const char *AcpiGbl_DmTypeNames[] = 69 { 70 /* 00 */ ", UnknownObj", /* Type ANY */ 71 /* 01 */ ", IntObj", 72 /* 02 */ ", StrObj", 73 /* 03 */ ", BuffObj", 74 /* 04 */ ", PkgObj", 75 /* 05 */ ", FieldUnitObj", 76 /* 06 */ ", DeviceObj", 77 /* 07 */ ", EventObj", 78 /* 08 */ ", MethodObj", 79 /* 09 */ ", MutexObj", 80 /* 10 */ ", OpRegionObj", 81 /* 11 */ ", PowerResObj", 82 /* 12 */ ", ProcessorObj", 83 /* 13 */ ", ThermalZoneObj", 84 /* 14 */ ", BuffFieldObj", 85 /* 15 */ ", DDBHandleObj", 86 /* 16 */ "", /* Debug object */ 87 /* 17 */ ", FieldUnitObj", 88 /* 18 */ ", FieldUnitObj", 89 /* 19 */ ", FieldUnitObj" 90 }; 91 92 #define METHOD_SEPARATORS " \t,()\n" 93 94 95 /* Local prototypes */ 96 97 static const char * 98 AcpiDmGetObjectTypeName ( 99 ACPI_OBJECT_TYPE Type); 100 101 static char * 102 AcpiDmNormalizeParentPrefix ( 103 ACPI_PARSE_OBJECT *Op, 104 char *Path); 105 106 static void 107 AcpiDmAddPathToExternalList ( 108 char *Path, 109 UINT8 Type, 110 UINT32 Value, 111 UINT16 Flags); 112 113 static ACPI_STATUS 114 AcpiDmCreateNewExternal ( 115 char *ExternalPath, 116 char *InternalPath, 117 UINT8 Type, 118 UINT32 Value, 119 UINT16 Flags); 120 121 122 /******************************************************************************* 123 * 124 * FUNCTION: AcpiDmGetObjectTypeName 125 * 126 * PARAMETERS: Type - An ACPI_OBJECT_TYPE 127 * 128 * RETURN: Pointer to a string 129 * 130 * DESCRIPTION: Map an object type to the ASL object type string. 131 * 132 ******************************************************************************/ 133 134 static const char * 135 AcpiDmGetObjectTypeName ( 136 ACPI_OBJECT_TYPE Type) 137 { 138 139 if (Type == ACPI_TYPE_LOCAL_SCOPE) 140 { 141 Type = ACPI_TYPE_DEVICE; 142 } 143 else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD) 144 { 145 return (""); 146 } 147 148 return (AcpiGbl_DmTypeNames[Type]); 149 } 150 151 152 /******************************************************************************* 153 * 154 * FUNCTION: AcpiDmNormalizeParentPrefix 155 * 156 * PARAMETERS: Op - Parse op 157 * Path - Path with parent prefix 158 * 159 * RETURN: The full pathname to the object (from the namespace root) 160 * 161 * DESCRIPTION: Returns the full pathname of a path with parent prefix 162 * The caller must free the fullpath returned. 163 * 164 ******************************************************************************/ 165 166 static char * 167 AcpiDmNormalizeParentPrefix ( 168 ACPI_PARSE_OBJECT *Op, 169 char *Path) 170 { 171 ACPI_NAMESPACE_NODE *Node; 172 char *Fullpath; 173 char *ParentPath; 174 ACPI_SIZE Length; 175 UINT32 Index = 0; 176 177 178 if (!Op) 179 { 180 return (NULL); 181 } 182 183 /* Search upwards in the parse tree until we reach the next namespace node */ 184 185 Op = Op->Common.Parent; 186 while (Op) 187 { 188 if (Op->Common.Node) 189 { 190 break; 191 } 192 193 Op = Op->Common.Parent; 194 } 195 196 if (!Op) 197 { 198 return (NULL); 199 } 200 201 /* 202 * Find the actual parent node for the reference: 203 * Remove all carat prefixes from the input path. 204 * There may be multiple parent prefixes (For example, ^^^M000) 205 */ 206 Node = Op->Common.Node; 207 while (Node && (*Path == (UINT8) AML_PARENT_PREFIX)) 208 { 209 Node = Node->Parent; 210 Path++; 211 } 212 213 if (!Node) 214 { 215 return (NULL); 216 } 217 218 /* Get the full pathname for the parent node */ 219 220 ParentPath = AcpiNsGetExternalPathname (Node); 221 if (!ParentPath) 222 { 223 return (NULL); 224 } 225 226 Length = (strlen (ParentPath) + strlen (Path) + 1); 227 if (ParentPath[1]) 228 { 229 /* 230 * If ParentPath is not just a simple '\', increment the length 231 * for the required dot separator (ParentPath.Path) 232 */ 233 Length++; 234 235 /* For External() statements, we do not want a leading '\' */ 236 237 if (*ParentPath == AML_ROOT_PREFIX) 238 { 239 Index = 1; 240 } 241 } 242 243 Fullpath = ACPI_ALLOCATE_ZEROED (Length); 244 if (!Fullpath) 245 { 246 goto Cleanup; 247 } 248 249 /* 250 * Concatenate parent fullpath and path. For example, 251 * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT" 252 * 253 * Copy the parent path 254 */ 255 strcpy (Fullpath, &ParentPath[Index]); 256 257 /* 258 * Add dot separator 259 * (don't need dot if parent fullpath is a single backslash) 260 */ 261 if (ParentPath[1]) 262 { 263 strcat (Fullpath, "."); 264 } 265 266 /* Copy child path (carat parent prefix(es) were skipped above) */ 267 268 strcat (Fullpath, Path); 269 270 Cleanup: 271 ACPI_FREE (ParentPath); 272 return (Fullpath); 273 } 274 275 276 /******************************************************************************* 277 * 278 * FUNCTION: AcpiDmAddToExternalFileList 279 * 280 * PARAMETERS: PathList - Single path or list separated by comma 281 * 282 * RETURN: None 283 * 284 * DESCRIPTION: Add external files to global list 285 * 286 ******************************************************************************/ 287 288 ACPI_STATUS 289 AcpiDmAddToExternalFileList ( 290 char *Pathname) 291 { 292 ACPI_EXTERNAL_FILE *ExternalFile; 293 char *LocalPathname; 294 295 296 if (!Pathname) 297 { 298 return (AE_OK); 299 } 300 301 LocalPathname = ACPI_ALLOCATE (strlen (Pathname) + 1); 302 if (!LocalPathname) 303 { 304 return (AE_NO_MEMORY); 305 } 306 307 ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE)); 308 if (!ExternalFile) 309 { 310 ACPI_FREE (LocalPathname); 311 return (AE_NO_MEMORY); 312 } 313 314 /* Take a copy of the file pathname */ 315 316 strcpy (LocalPathname, Pathname); 317 ExternalFile->Path = LocalPathname; 318 319 if (AcpiGbl_ExternalFileList) 320 { 321 ExternalFile->Next = AcpiGbl_ExternalFileList; 322 } 323 324 AcpiGbl_ExternalFileList = ExternalFile; 325 return (AE_OK); 326 } 327 328 329 /******************************************************************************* 330 * 331 * FUNCTION: AcpiDmClearExternalFileList 332 * 333 * PARAMETERS: None 334 * 335 * RETURN: None 336 * 337 * DESCRIPTION: Clear the external file list 338 * 339 ******************************************************************************/ 340 341 void 342 AcpiDmClearExternalFileList ( 343 void) 344 { 345 ACPI_EXTERNAL_FILE *NextExternal; 346 347 348 while (AcpiGbl_ExternalFileList) 349 { 350 NextExternal = AcpiGbl_ExternalFileList->Next; 351 ACPI_FREE (AcpiGbl_ExternalFileList->Path); 352 ACPI_FREE (AcpiGbl_ExternalFileList); 353 AcpiGbl_ExternalFileList = NextExternal; 354 } 355 } 356 357 358 /******************************************************************************* 359 * 360 * FUNCTION: AcpiDmGetExternalsFromFile 361 * 362 * PARAMETERS: None 363 * 364 * RETURN: None 365 * 366 * DESCRIPTION: Process the optional external reference file. 367 * 368 * Each line in the file should be of the form: 369 * External (<Method namepath>, MethodObj, <ArgCount>) 370 * 371 * Example: 372 * External (_SB_.PCI0.XHC_.PS0X, MethodObj, 4) 373 * 374 ******************************************************************************/ 375 376 void 377 AcpiDmGetExternalsFromFile ( 378 void) 379 { 380 FILE *ExternalRefFile; 381 char *Token; 382 char *MethodName; 383 UINT32 ArgCount; 384 UINT32 ImportCount = 0; 385 386 387 if (!Gbl_ExternalRefFilename) 388 { 389 return; 390 } 391 392 /* Open the file */ 393 394 ExternalRefFile = fopen (Gbl_ExternalRefFilename, "r"); 395 if (!ExternalRefFile) 396 { 397 fprintf (stderr, "Could not open external reference file \"%s\"\n", 398 Gbl_ExternalRefFilename); 399 AslAbort (); 400 return; 401 } 402 403 /* Each line defines a method */ 404 405 while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ExternalRefFile)) 406 { 407 Token = strtok (StringBuffer, METHOD_SEPARATORS); /* "External" */ 408 if (!Token) 409 { 410 continue; 411 } 412 413 if (strcmp (Token, "External")) 414 { 415 continue; 416 } 417 418 MethodName = strtok (NULL, METHOD_SEPARATORS); /* Method namepath */ 419 if (!MethodName) 420 { 421 continue; 422 } 423 424 Token = strtok (NULL, METHOD_SEPARATORS); /* "MethodObj" */ 425 if (!Token) 426 { 427 continue; 428 } 429 430 if (strcmp (Token, "MethodObj")) 431 { 432 continue; 433 } 434 435 Token = strtok (NULL, METHOD_SEPARATORS); /* Arg count */ 436 if (!Token) 437 { 438 continue; 439 } 440 441 /* Convert arg count string to an integer */ 442 443 errno = 0; 444 ArgCount = strtoul (Token, NULL, 0); 445 if (errno) 446 { 447 fprintf (stderr, "Invalid argument count (%s)\n", Token); 448 continue; 449 } 450 451 if (ArgCount > 7) 452 { 453 fprintf (stderr, "Invalid argument count (%u)\n", ArgCount); 454 continue; 455 } 456 457 /* Add this external to the global list */ 458 459 AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n", 460 Gbl_ExternalRefFilename, ArgCount, MethodName); 461 462 AcpiDmAddPathToExternalList (MethodName, ACPI_TYPE_METHOD, 463 ArgCount, (ACPI_EXT_RESOLVED_REFERENCE | ACPI_EXT_ORIGIN_FROM_FILE)); 464 ImportCount++; 465 } 466 467 if (!ImportCount) 468 { 469 fprintf (stderr, 470 "Did not find any external methods in reference file \"%s\"\n", 471 Gbl_ExternalRefFilename); 472 } 473 else 474 { 475 /* Add the external(s) to the namespace */ 476 477 AcpiDmAddExternalsToNamespace (); 478 479 AcpiOsPrintf ("%s: Imported %u external method definitions\n", 480 Gbl_ExternalRefFilename, ImportCount); 481 } 482 483 fclose (ExternalRefFile); 484 } 485 486 487 /******************************************************************************* 488 * 489 * FUNCTION: AcpiDmAddOpToExternalList 490 * 491 * PARAMETERS: Op - Current parser Op 492 * Path - Internal (AML) path to the object 493 * Type - ACPI object type to be added 494 * Value - Arg count if adding a Method object 495 * Flags - To be passed to the external object 496 * 497 * RETURN: None 498 * 499 * DESCRIPTION: Insert a new name into the global list of Externals which 500 * will in turn be later emitted as an External() declaration 501 * in the disassembled output. 502 * 503 * This function handles the most common case where the referenced 504 * name is simply not found in the constructed namespace. 505 * 506 ******************************************************************************/ 507 508 void 509 AcpiDmAddOpToExternalList ( 510 ACPI_PARSE_OBJECT *Op, 511 char *Path, 512 UINT8 Type, 513 UINT32 Value, 514 UINT16 Flags) 515 { 516 char *ExternalPath; 517 char *InternalPath = Path; 518 char *Temp; 519 ACPI_STATUS Status; 520 521 522 ACPI_FUNCTION_TRACE (DmAddOpToExternalList); 523 524 525 if (!Path) 526 { 527 return_VOID; 528 } 529 530 /* Remove a root backslash if present */ 531 532 if ((*Path == AML_ROOT_PREFIX) && (Path[1])) 533 { 534 Path++; 535 } 536 537 /* Externalize the pathname */ 538 539 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path, 540 NULL, &ExternalPath); 541 if (ACPI_FAILURE (Status)) 542 { 543 return_VOID; 544 } 545 546 /* 547 * Get the full pathname from the root if "Path" has one or more 548 * parent prefixes (^). Note: path will not contain a leading '\'. 549 */ 550 if (*Path == (UINT8) AML_PARENT_PREFIX) 551 { 552 Temp = AcpiDmNormalizeParentPrefix (Op, ExternalPath); 553 554 /* Set new external path */ 555 556 ACPI_FREE (ExternalPath); 557 ExternalPath = Temp; 558 if (!Temp) 559 { 560 return_VOID; 561 } 562 563 /* Create the new internal pathname */ 564 565 Flags |= ACPI_EXT_INTERNAL_PATH_ALLOCATED; 566 Status = AcpiNsInternalizeName (ExternalPath, &InternalPath); 567 if (ACPI_FAILURE (Status)) 568 { 569 ACPI_FREE (ExternalPath); 570 return_VOID; 571 } 572 } 573 574 /* Create the new External() declaration node */ 575 576 Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, 577 Type, Value, Flags); 578 if (ACPI_FAILURE (Status)) 579 { 580 ACPI_FREE (ExternalPath); 581 if (Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED) 582 { 583 ACPI_FREE (InternalPath); 584 } 585 } 586 587 return_VOID; 588 } 589 590 591 /******************************************************************************* 592 * 593 * FUNCTION: AcpiDmAddNodeToExternalList 594 * 595 * PARAMETERS: Node - Namespace node for object to be added 596 * Type - ACPI object type to be added 597 * Value - Arg count if adding a Method object 598 * Flags - To be passed to the external object 599 * 600 * RETURN: None 601 * 602 * DESCRIPTION: Insert a new name into the global list of Externals which 603 * will in turn be later emitted as an External() declaration 604 * in the disassembled output. 605 * 606 * This function handles the case where the referenced name has 607 * been found in the namespace, but the name originated in a 608 * table other than the one that is being disassembled (such 609 * as a table that is added via the iASL -e option). 610 * 611 ******************************************************************************/ 612 613 void 614 AcpiDmAddNodeToExternalList ( 615 ACPI_NAMESPACE_NODE *Node, 616 UINT8 Type, 617 UINT32 Value, 618 UINT16 Flags) 619 { 620 char *ExternalPath; 621 char *InternalPath; 622 char *Temp; 623 ACPI_STATUS Status; 624 625 626 ACPI_FUNCTION_TRACE (DmAddNodeToExternalList); 627 628 629 if (!Node) 630 { 631 return_VOID; 632 } 633 634 /* Get the full external and internal pathnames to the node */ 635 636 ExternalPath = AcpiNsGetExternalPathname (Node); 637 if (!ExternalPath) 638 { 639 return_VOID; 640 } 641 642 Status = AcpiNsInternalizeName (ExternalPath, &InternalPath); 643 if (ACPI_FAILURE (Status)) 644 { 645 ACPI_FREE (ExternalPath); 646 return_VOID; 647 } 648 649 /* Remove the root backslash */ 650 651 if ((*ExternalPath == AML_ROOT_PREFIX) && (ExternalPath[1])) 652 { 653 Temp = ACPI_ALLOCATE_ZEROED (strlen (ExternalPath) + 1); 654 if (!Temp) 655 { 656 return_VOID; 657 } 658 659 strcpy (Temp, &ExternalPath[1]); 660 ACPI_FREE (ExternalPath); 661 ExternalPath = Temp; 662 } 663 664 /* Create the new External() declaration node */ 665 666 Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, Type, 667 Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED)); 668 if (ACPI_FAILURE (Status)) 669 { 670 ACPI_FREE (ExternalPath); 671 ACPI_FREE (InternalPath); 672 } 673 674 return_VOID; 675 } 676 677 678 /******************************************************************************* 679 * 680 * FUNCTION: AcpiDmAddPathToExternalList 681 * 682 * PARAMETERS: Path - External name of the object to be added 683 * Type - ACPI object type to be added 684 * Value - Arg count if adding a Method object 685 * Flags - To be passed to the external object 686 * 687 * RETURN: None 688 * 689 * DESCRIPTION: Insert a new name into the global list of Externals which 690 * will in turn be later emitted as an External() declaration 691 * in the disassembled output. 692 * 693 * This function currently is used to add externals via a 694 * reference file (via the -fe iASL option). 695 * 696 ******************************************************************************/ 697 698 static void 699 AcpiDmAddPathToExternalList ( 700 char *Path, 701 UINT8 Type, 702 UINT32 Value, 703 UINT16 Flags) 704 { 705 char *InternalPath; 706 char *ExternalPath; 707 ACPI_STATUS Status; 708 709 710 ACPI_FUNCTION_TRACE (DmAddPathToExternalList); 711 712 713 if (!Path) 714 { 715 return_VOID; 716 } 717 718 /* Remove a root backslash if present */ 719 720 if ((*Path == AML_ROOT_PREFIX) && (Path[1])) 721 { 722 Path++; 723 } 724 725 /* Create the internal and external pathnames */ 726 727 Status = AcpiNsInternalizeName (Path, &InternalPath); 728 if (ACPI_FAILURE (Status)) 729 { 730 return_VOID; 731 } 732 733 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath, 734 NULL, &ExternalPath); 735 if (ACPI_FAILURE (Status)) 736 { 737 ACPI_FREE (InternalPath); 738 return_VOID; 739 } 740 741 /* Create the new External() declaration node */ 742 743 Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, 744 Type, Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED)); 745 if (ACPI_FAILURE (Status)) 746 { 747 ACPI_FREE (ExternalPath); 748 ACPI_FREE (InternalPath); 749 } 750 751 return_VOID; 752 } 753 754 755 /******************************************************************************* 756 * 757 * FUNCTION: AcpiDmEternalIsMatch 758 * 759 * PARAMETERS: NamePath - Path to match to External Name 760 * ExternalPath - External NamePath to be matched 761 * 762 * RETURN: BOOLEAN 763 * 764 * DESCRIPTION: Returns TRUE if NamePath matches the last NamePath-length 765 * characters of ExternalPath. 766 * 767 * External (_SB_.DEV0.ABCD) will match: 768 * _SB_.DEV0.ABCD 769 * DEV0.ABCD 770 * ABCD 771 * 772 ******************************************************************************/ 773 774 static BOOLEAN 775 AcpiDmExternalIsMatch ( 776 const char * NamePath, 777 const char * ListNamePath) 778 { 779 BOOLEAN Match = FALSE; 780 781 782 if (strlen (ListNamePath) >= strlen (NamePath)) 783 { 784 if (!strcmp (ListNamePath + 785 (strlen (ListNamePath) - strlen (NamePath)), NamePath)) 786 { 787 return (TRUE); 788 } 789 } 790 791 return (Match); 792 } 793 794 795 /******************************************************************************* 796 * 797 * FUNCTION: AcpiDmCreateNewExternal 798 * 799 * PARAMETERS: ExternalPath - External path to the object 800 * InternalPath - Internal (AML) path to the object 801 * Type - ACPI object type to be added 802 * Value - Arg count if adding a Method object 803 * Flags - To be passed to the external object 804 * 805 * RETURN: Status 806 * 807 * DESCRIPTION: Common low-level function to insert a new name into the global 808 * list of Externals which will in turn be later emitted as 809 * External() declarations in the disassembled output. 810 * 811 * Note: The external name should not include a root prefix 812 * (backslash). We do not want External() statements to contain 813 * a leading '\', as this prevents duplicate external statements 814 * of the form: 815 * 816 * External (\ABCD) 817 * External (ABCD) 818 * 819 * This would cause a compile time error when the disassembled 820 * output file is recompiled. 821 * 822 * There are two cases that are handled here. For both, we emit 823 * an External() statement: 824 * 1) The name was simply not found in the namespace. 825 * 2) The name was found, but it originated in a table other than 826 * the table that is being disassembled. 827 * 828 ******************************************************************************/ 829 830 static ACPI_STATUS 831 AcpiDmCreateNewExternal ( 832 char *ExternalPath, 833 char *InternalPath, 834 UINT8 Type, 835 UINT32 Value, 836 UINT16 Flags) 837 { 838 ACPI_EXTERNAL_LIST *NewExternal; 839 ACPI_EXTERNAL_LIST *NextExternal; 840 ACPI_EXTERNAL_LIST *PrevExternal = NULL; 841 842 843 ACPI_FUNCTION_TRACE (DmCreateNewExternal); 844 845 846 /* Check all existing externals to ensure no duplicates */ 847 848 NextExternal = AcpiGbl_ExternalList; 849 while (NextExternal) 850 { 851 /* Check for duplicates */ 852 853 if (AcpiDmExternalIsMatch (ExternalPath, NextExternal->Path)) 854 { 855 /* Duplicate method, check that the Value (ArgCount) is the same */ 856 857 if ((NextExternal->Type == ACPI_TYPE_METHOD) && 858 (NextExternal->Flags & ANOBJ_IS_EXTERNAL) && 859 (NextExternal->Value != Value) && 860 (Value > 0)) 861 { 862 ACPI_ERROR ((AE_INFO, 863 "External method arg count mismatch %s: " 864 "Current %u, attempted %u", 865 NextExternal->Path, NextExternal->Value, Value)); 866 } 867 868 /* Allow upgrade of type from ANY */ 869 870 else if (NextExternal->Type == ACPI_TYPE_ANY) 871 { 872 NextExternal->Type = Type; 873 NextExternal->Value = Value; 874 } 875 876 /* Update flags. */ 877 878 NextExternal->Flags |= Flags; 879 NextExternal->Flags &= ~ACPI_EXT_INTERNAL_PATH_ALLOCATED; 880 881 return_ACPI_STATUS (AE_ALREADY_EXISTS); 882 } 883 884 NextExternal = NextExternal->Next; 885 } 886 887 /* Allocate and init a new External() descriptor */ 888 889 NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST)); 890 if (!NewExternal) 891 { 892 return_ACPI_STATUS (AE_NO_MEMORY); 893 } 894 895 ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, 896 "Adding external reference node (%s) type [%s]\n", 897 ExternalPath, AcpiUtGetTypeName (Type))); 898 899 NewExternal->Flags = Flags; 900 NewExternal->Value = Value; 901 NewExternal->Path = ExternalPath; 902 NewExternal->Type = Type; 903 NewExternal->Length = (UINT16) strlen (ExternalPath); 904 NewExternal->InternalPath = InternalPath; 905 906 /* Link the new descriptor into the global list, alphabetically ordered */ 907 908 NextExternal = AcpiGbl_ExternalList; 909 while (NextExternal) 910 { 911 if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0) 912 { 913 if (PrevExternal) 914 { 915 PrevExternal->Next = NewExternal; 916 } 917 else 918 { 919 AcpiGbl_ExternalList = NewExternal; 920 } 921 922 NewExternal->Next = NextExternal; 923 return_ACPI_STATUS (AE_OK); 924 } 925 926 PrevExternal = NextExternal; 927 NextExternal = NextExternal->Next; 928 } 929 930 if (PrevExternal) 931 { 932 PrevExternal->Next = NewExternal; 933 } 934 else 935 { 936 AcpiGbl_ExternalList = NewExternal; 937 } 938 939 return_ACPI_STATUS (AE_OK); 940 } 941 942 943 /******************************************************************************* 944 * 945 * FUNCTION: AcpiDmAddExternalsToNamespace 946 * 947 * PARAMETERS: None 948 * 949 * RETURN: None 950 * 951 * DESCRIPTION: Add all externals to the namespace. Allows externals to be 952 * "resolved". 953 * 954 ******************************************************************************/ 955 956 void 957 AcpiDmAddExternalsToNamespace ( 958 void) 959 { 960 ACPI_STATUS Status; 961 ACPI_NAMESPACE_NODE *Node; 962 ACPI_OPERAND_OBJECT *ObjDesc; 963 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 964 965 966 while (External) 967 { 968 /* Add the external name (object) into the namespace */ 969 970 Status = AcpiNsLookup (NULL, External->InternalPath, External->Type, 971 ACPI_IMODE_LOAD_PASS1, 972 ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE, 973 NULL, &Node); 974 975 if (ACPI_FAILURE (Status)) 976 { 977 ACPI_EXCEPTION ((AE_INFO, Status, 978 "while adding external to namespace [%s]", 979 External->Path)); 980 } 981 982 else switch (External->Type) 983 { 984 case ACPI_TYPE_METHOD: 985 986 /* For methods, we need to save the argument count */ 987 988 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); 989 ObjDesc->Method.ParamCount = (UINT8) External->Value; 990 Node->Object = ObjDesc; 991 break; 992 993 case ACPI_TYPE_REGION: 994 995 /* Regions require a region sub-object */ 996 997 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION); 998 ObjDesc->Region.Node = Node; 999 Node->Object = ObjDesc; 1000 break; 1001 1002 default: 1003 1004 break; 1005 } 1006 1007 External = External->Next; 1008 } 1009 } 1010 1011 1012 /******************************************************************************* 1013 * 1014 * FUNCTION: AcpiDmGetExternalMethodCount 1015 * 1016 * PARAMETERS: None 1017 * 1018 * RETURN: The number of control method externals in the external list 1019 * 1020 * DESCRIPTION: Return the number of method externals that have been generated. 1021 * If any control method externals have been found, we must 1022 * re-parse the entire definition block with the new information 1023 * (number of arguments for the methods.) This is limitation of 1024 * AML, we don't know the number of arguments from the control 1025 * method invocation itself. 1026 * 1027 ******************************************************************************/ 1028 1029 UINT32 1030 AcpiDmGetExternalMethodCount ( 1031 void) 1032 { 1033 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 1034 UINT32 Count = 0; 1035 1036 1037 while (External) 1038 { 1039 if (External->Type == ACPI_TYPE_METHOD) 1040 { 1041 Count++; 1042 } 1043 1044 External = External->Next; 1045 } 1046 1047 return (Count); 1048 } 1049 1050 1051 /******************************************************************************* 1052 * 1053 * FUNCTION: AcpiDmClearExternalList 1054 * 1055 * PARAMETERS: None 1056 * 1057 * RETURN: None 1058 * 1059 * DESCRIPTION: Free the entire External info list 1060 * 1061 ******************************************************************************/ 1062 1063 void 1064 AcpiDmClearExternalList ( 1065 void) 1066 { 1067 ACPI_EXTERNAL_LIST *NextExternal; 1068 1069 1070 while (AcpiGbl_ExternalList) 1071 { 1072 NextExternal = AcpiGbl_ExternalList->Next; 1073 ACPI_FREE (AcpiGbl_ExternalList->Path); 1074 ACPI_FREE (AcpiGbl_ExternalList); 1075 AcpiGbl_ExternalList = NextExternal; 1076 } 1077 } 1078 1079 1080 /******************************************************************************* 1081 * 1082 * FUNCTION: AcpiDmEmitExternals 1083 * 1084 * PARAMETERS: None 1085 * 1086 * RETURN: None 1087 * 1088 * DESCRIPTION: Emit an External() ASL statement for each of the externals in 1089 * the global external info list. 1090 * 1091 ******************************************************************************/ 1092 1093 void 1094 AcpiDmEmitExternals ( 1095 void) 1096 { 1097 ACPI_EXTERNAL_LIST *NextExternal; 1098 1099 1100 if (!AcpiGbl_ExternalList) 1101 { 1102 return; 1103 } 1104 1105 /* 1106 * Determine the number of control methods in the external list, and 1107 * also how many of those externals were resolved via the namespace. 1108 */ 1109 NextExternal = AcpiGbl_ExternalList; 1110 while (NextExternal) 1111 { 1112 if (NextExternal->Type == ACPI_TYPE_METHOD) 1113 { 1114 AcpiGbl_NumExternalMethods++; 1115 if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE) 1116 { 1117 AcpiGbl_ResolvedExternalMethods++; 1118 } 1119 } 1120 1121 NextExternal = NextExternal->Next; 1122 } 1123 1124 /* Check if any control methods were unresolved */ 1125 1126 AcpiDmUnresolvedWarning (1); 1127 1128 /* Emit any unresolved method externals in a single text block */ 1129 1130 NextExternal = AcpiGbl_ExternalList; 1131 while (NextExternal) 1132 { 1133 if ((NextExternal->Type == ACPI_TYPE_METHOD) && 1134 (!(NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE))) 1135 { 1136 AcpiOsPrintf (" External (%s%s", 1137 NextExternal->Path, 1138 AcpiDmGetObjectTypeName (NextExternal->Type)); 1139 1140 AcpiOsPrintf (") // Warning: Unresolved method, " 1141 "guessing %u arguments\n", 1142 NextExternal->Value); 1143 1144 NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED; 1145 } 1146 1147 NextExternal = NextExternal->Next; 1148 } 1149 1150 AcpiOsPrintf ("\n"); 1151 1152 1153 /* Emit externals that were imported from a file */ 1154 1155 if (Gbl_ExternalRefFilename) 1156 { 1157 AcpiOsPrintf ( 1158 " /*\n * External declarations that were imported from\n" 1159 " * the reference file [%s]\n */\n", 1160 Gbl_ExternalRefFilename); 1161 1162 NextExternal = AcpiGbl_ExternalList; 1163 while (NextExternal) 1164 { 1165 if (!(NextExternal->Flags & ACPI_EXT_EXTERNAL_EMITTED) && 1166 (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_FILE)) 1167 { 1168 AcpiOsPrintf (" External (%s%s", 1169 NextExternal->Path, 1170 AcpiDmGetObjectTypeName (NextExternal->Type)); 1171 1172 if (NextExternal->Type == ACPI_TYPE_METHOD) 1173 { 1174 AcpiOsPrintf (") // %u Arguments\n", 1175 NextExternal->Value); 1176 } 1177 else 1178 { 1179 AcpiOsPrintf (")\n"); 1180 } 1181 NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED; 1182 } 1183 1184 NextExternal = NextExternal->Next; 1185 } 1186 1187 AcpiOsPrintf ("\n"); 1188 } 1189 1190 /* 1191 * Walk the list of externals found during the AML parsing 1192 */ 1193 while (AcpiGbl_ExternalList) 1194 { 1195 if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED)) 1196 { 1197 AcpiOsPrintf (" External (%s%s", 1198 AcpiGbl_ExternalList->Path, 1199 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type)); 1200 1201 /* For methods, add a comment with the number of arguments */ 1202 1203 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) 1204 { 1205 AcpiOsPrintf (") // %u Arguments\n", 1206 AcpiGbl_ExternalList->Value); 1207 } 1208 else 1209 { 1210 AcpiOsPrintf (")\n"); 1211 } 1212 } 1213 1214 /* Free this external info block and move on to next external */ 1215 1216 NextExternal = AcpiGbl_ExternalList->Next; 1217 if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED) 1218 { 1219 ACPI_FREE (AcpiGbl_ExternalList->InternalPath); 1220 } 1221 1222 ACPI_FREE (AcpiGbl_ExternalList->Path); 1223 ACPI_FREE (AcpiGbl_ExternalList); 1224 AcpiGbl_ExternalList = NextExternal; 1225 } 1226 1227 AcpiOsPrintf ("\n"); 1228 } 1229 1230 1231 /******************************************************************************* 1232 * 1233 * FUNCTION: AcpiDmUnresolvedWarning 1234 * 1235 * PARAMETERS: Type - Where to output the warning. 1236 * 0 means write to stderr 1237 * 1 means write to AcpiOsPrintf 1238 * 1239 * RETURN: None 1240 * 1241 * DESCRIPTION: Issue warning message if there are unresolved external control 1242 * methods within the disassembly. 1243 * 1244 ******************************************************************************/ 1245 1246 #if 0 1247 Summary of the external control method problem: 1248 1249 When the -e option is used with disassembly, the various SSDTs are simply 1250 loaded into a global namespace for the disassembler to use in order to 1251 resolve control method references (invocations). 1252 1253 The disassembler tracks any such references, and will emit an External() 1254 statement for these types of methods, with the proper number of arguments . 1255 1256 Without the SSDTs, the AML does not contain enough information to properly 1257 disassemble the control method invocation -- because the disassembler does 1258 not know how many arguments to parse. 1259 1260 An example: Assume we have two control methods. ABCD has one argument, and 1261 EFGH has zero arguments. Further, we have two additional control methods 1262 that invoke ABCD and EFGH, named T1 and T2: 1263 1264 Method (ABCD, 1) 1265 { 1266 } 1267 Method (EFGH, 0) 1268 { 1269 } 1270 Method (T1) 1271 { 1272 ABCD (Add (2, 7, Local0)) 1273 } 1274 Method (T2) 1275 { 1276 EFGH () 1277 Add (2, 7, Local0) 1278 } 1279 1280 Here is the AML code that is generated for T1 and T2: 1281 1282 185: Method (T1) 1283 1284 0000034C: 14 10 54 31 5F 5F 00 ... "..T1__." 1285 1286 186: { 1287 187: ABCD (Add (2, 7, Local0)) 1288 1289 00000353: 41 42 43 44 ............ "ABCD" 1290 00000357: 72 0A 02 0A 07 60 ...... "r....`" 1291 1292 188: } 1293 1294 190: Method (T2) 1295 1296 0000035D: 14 10 54 32 5F 5F 00 ... "..T2__." 1297 1298 191: { 1299 192: EFGH () 1300 1301 00000364: 45 46 47 48 ............ "EFGH" 1302 1303 193: Add (2, 7, Local0) 1304 1305 00000368: 72 0A 02 0A 07 60 ...... "r....`" 1306 194: } 1307 1308 Note that the AML code for T1 and T2 is essentially identical. When 1309 disassembling this code, the methods ABCD and EFGH must be known to the 1310 disassembler, otherwise it does not know how to handle the method invocations. 1311 1312 In other words, if ABCD and EFGH are actually external control methods 1313 appearing in an SSDT, the disassembler does not know what to do unless 1314 the owning SSDT has been loaded via the -e option. 1315 #endif 1316 1317 static char ExternalWarningPart1[600]; 1318 static char ExternalWarningPart2[400]; 1319 static char ExternalWarningPart3[400]; 1320 static char ExternalWarningPart4[200]; 1321 1322 void 1323 AcpiDmUnresolvedWarning ( 1324 UINT8 Type) 1325 { 1326 char *Format; 1327 char Pad[] = " *"; 1328 char NoPad[] = ""; 1329 1330 1331 if (!AcpiGbl_NumExternalMethods) 1332 { 1333 return; 1334 } 1335 1336 if (AcpiGbl_NumExternalMethods == AcpiGbl_ResolvedExternalMethods) 1337 { 1338 return; 1339 } 1340 1341 Format = Type ? Pad : NoPad; 1342 1343 sprintf (ExternalWarningPart1, 1344 "%s iASL Warning: There were %u external control methods found during\n" 1345 "%s disassembly, but only %u %s resolved (%u unresolved). Additional\n" 1346 "%s ACPI tables may be required to properly disassemble the code. This\n" 1347 "%s resulting disassembler output file may not compile because the\n" 1348 "%s disassembler did not know how many arguments to assign to the\n" 1349 "%s unresolved methods. Note: SSDTs can be dynamically loaded at\n" 1350 "%s runtime and may or may not be available via the host OS.\n", 1351 Format, AcpiGbl_NumExternalMethods, Format, AcpiGbl_ResolvedExternalMethods, 1352 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"), 1353 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods), 1354 Format, Format, Format, Format, Format); 1355 1356 sprintf (ExternalWarningPart2, 1357 "%s To specify the tables needed to resolve external control method\n" 1358 "%s references, the -e option can be used to specify the filenames.\n" 1359 "%s Example iASL invocations:\n" 1360 "%s iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n" 1361 "%s iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n" 1362 "%s iasl -e ssdt*.aml -d dsdt.aml\n", 1363 Format, Format, Format, Format, Format, Format); 1364 1365 sprintf (ExternalWarningPart3, 1366 "%s In addition, the -fe option can be used to specify a file containing\n" 1367 "%s control method external declarations with the associated method\n" 1368 "%s argument counts. Each line of the file must be of the form:\n" 1369 "%s External (<method pathname>, MethodObj, <argument count>)\n" 1370 "%s Invocation:\n" 1371 "%s iasl -fe refs.txt -d dsdt.aml\n", 1372 Format, Format, Format, Format, Format, Format); 1373 1374 sprintf (ExternalWarningPart4, 1375 "%s The following methods were unresolved and many not compile properly\n" 1376 "%s because the disassembler had to guess at the number of arguments\n" 1377 "%s required for each:\n", 1378 Format, Format, Format); 1379 1380 if (Type) 1381 { 1382 if (!AcpiGbl_ExternalFileList) 1383 { 1384 /* The -e option was not specified */ 1385 1386 AcpiOsPrintf (" /*\n%s *\n%s *\n%s *\n%s */\n", 1387 ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3, 1388 ExternalWarningPart4); 1389 } 1390 else 1391 { 1392 /* The -e option was specified, but there are still some unresolved externals */ 1393 1394 AcpiOsPrintf (" /*\n%s *\n *\n */\n", 1395 ExternalWarningPart1, ExternalWarningPart3, ExternalWarningPart4); 1396 } 1397 } 1398 else 1399 { 1400 if (!AcpiGbl_ExternalFileList) 1401 { 1402 /* The -e option was not specified */ 1403 1404 fprintf (stderr, "\n%s\n%s\n%s\n", 1405 ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3); 1406 } 1407 else 1408 { 1409 /* The -e option was specified, but there are still some unresolved externals */ 1410 1411 fprintf (stderr, "\n%s\n%s\n", 1412 ExternalWarningPart1, ExternalWarningPart3); 1413 } 1414 } 1415 } 1416