1 /****************************************************************************** 2 * 3 * Module Name: dmextern - Support for External() ASL statements 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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: AcpiDmCreateNewExternal 758 * 759 * PARAMETERS: ExternalPath - External path to the object 760 * InternalPath - Internal (AML) path to the object 761 * Type - ACPI object type to be added 762 * Value - Arg count if adding a Method object 763 * Flags - To be passed to the external object 764 * 765 * RETURN: Status 766 * 767 * DESCRIPTION: Common low-level function to insert a new name into the global 768 * list of Externals which will in turn be later emitted as 769 * External() declarations in the disassembled output. 770 * 771 * Note: The external name should not include a root prefix 772 * (backslash). We do not want External() statements to contain 773 * a leading '\', as this prevents duplicate external statements 774 * of the form: 775 * 776 * External (\ABCD) 777 * External (ABCD) 778 * 779 * This would cause a compile time error when the disassembled 780 * output file is recompiled. 781 * 782 * There are two cases that are handled here. For both, we emit 783 * an External() statement: 784 * 1) The name was simply not found in the namespace. 785 * 2) The name was found, but it originated in a table other than 786 * the table that is being disassembled. 787 * 788 ******************************************************************************/ 789 790 static ACPI_STATUS 791 AcpiDmCreateNewExternal ( 792 char *ExternalPath, 793 char *InternalPath, 794 UINT8 Type, 795 UINT32 Value, 796 UINT16 Flags) 797 { 798 ACPI_EXTERNAL_LIST *NewExternal; 799 ACPI_EXTERNAL_LIST *NextExternal; 800 ACPI_EXTERNAL_LIST *PrevExternal = NULL; 801 802 803 ACPI_FUNCTION_TRACE (DmCreateNewExternal); 804 805 806 /* Check all existing externals to ensure no duplicates */ 807 808 NextExternal = AcpiGbl_ExternalList; 809 while (NextExternal) 810 { 811 if (!strcmp (ExternalPath, NextExternal->Path)) 812 { 813 /* Duplicate method, check that the Value (ArgCount) is the same */ 814 815 if ((NextExternal->Type == ACPI_TYPE_METHOD) && 816 (NextExternal->Value != Value) && 817 (Value > 0)) 818 { 819 ACPI_ERROR ((AE_INFO, 820 "External method arg count mismatch %s: " 821 "Current %u, attempted %u", 822 NextExternal->Path, NextExternal->Value, Value)); 823 } 824 825 /* Allow upgrade of type from ANY */ 826 827 else if (NextExternal->Type == ACPI_TYPE_ANY) 828 { 829 NextExternal->Type = Type; 830 NextExternal->Value = Value; 831 } 832 833 return_ACPI_STATUS (AE_ALREADY_EXISTS); 834 } 835 836 NextExternal = NextExternal->Next; 837 } 838 839 /* Allocate and init a new External() descriptor */ 840 841 NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST)); 842 if (!NewExternal) 843 { 844 return_ACPI_STATUS (AE_NO_MEMORY); 845 } 846 847 ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, 848 "Adding external reference node (%s) type [%s]\n", 849 ExternalPath, AcpiUtGetTypeName (Type))); 850 851 NewExternal->Flags = Flags; 852 NewExternal->Value = Value; 853 NewExternal->Path = ExternalPath; 854 NewExternal->Type = Type; 855 NewExternal->Length = (UINT16) strlen (ExternalPath); 856 NewExternal->InternalPath = InternalPath; 857 858 /* Link the new descriptor into the global list, alphabetically ordered */ 859 860 NextExternal = AcpiGbl_ExternalList; 861 while (NextExternal) 862 { 863 if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0) 864 { 865 if (PrevExternal) 866 { 867 PrevExternal->Next = NewExternal; 868 } 869 else 870 { 871 AcpiGbl_ExternalList = NewExternal; 872 } 873 874 NewExternal->Next = NextExternal; 875 return_ACPI_STATUS (AE_OK); 876 } 877 878 PrevExternal = NextExternal; 879 NextExternal = NextExternal->Next; 880 } 881 882 if (PrevExternal) 883 { 884 PrevExternal->Next = NewExternal; 885 } 886 else 887 { 888 AcpiGbl_ExternalList = NewExternal; 889 } 890 891 return_ACPI_STATUS (AE_OK); 892 } 893 894 895 /******************************************************************************* 896 * 897 * FUNCTION: AcpiDmAddExternalsToNamespace 898 * 899 * PARAMETERS: None 900 * 901 * RETURN: None 902 * 903 * DESCRIPTION: Add all externals to the namespace. Allows externals to be 904 * "resolved". 905 * 906 ******************************************************************************/ 907 908 void 909 AcpiDmAddExternalsToNamespace ( 910 void) 911 { 912 ACPI_STATUS Status; 913 ACPI_NAMESPACE_NODE *Node; 914 ACPI_OPERAND_OBJECT *ObjDesc; 915 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 916 917 918 while (External) 919 { 920 /* Add the external name (object) into the namespace */ 921 922 Status = AcpiNsLookup (NULL, External->InternalPath, External->Type, 923 ACPI_IMODE_LOAD_PASS1, 924 ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE, 925 NULL, &Node); 926 927 if (ACPI_FAILURE (Status)) 928 { 929 ACPI_EXCEPTION ((AE_INFO, Status, 930 "while adding external to namespace [%s]", 931 External->Path)); 932 } 933 934 else switch (External->Type) 935 { 936 case ACPI_TYPE_METHOD: 937 938 /* For methods, we need to save the argument count */ 939 940 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); 941 ObjDesc->Method.ParamCount = (UINT8) External->Value; 942 Node->Object = ObjDesc; 943 break; 944 945 case ACPI_TYPE_REGION: 946 947 /* Regions require a region sub-object */ 948 949 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION); 950 ObjDesc->Region.Node = Node; 951 Node->Object = ObjDesc; 952 break; 953 954 default: 955 956 break; 957 } 958 959 External = External->Next; 960 } 961 } 962 963 964 /******************************************************************************* 965 * 966 * FUNCTION: AcpiDmGetExternalMethodCount 967 * 968 * PARAMETERS: None 969 * 970 * RETURN: The number of control method externals in the external list 971 * 972 * DESCRIPTION: Return the number of method externals that have been generated. 973 * If any control method externals have been found, we must 974 * re-parse the entire definition block with the new information 975 * (number of arguments for the methods.) This is limitation of 976 * AML, we don't know the number of arguments from the control 977 * method invocation itself. 978 * 979 ******************************************************************************/ 980 981 UINT32 982 AcpiDmGetExternalMethodCount ( 983 void) 984 { 985 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 986 UINT32 Count = 0; 987 988 989 while (External) 990 { 991 if (External->Type == ACPI_TYPE_METHOD) 992 { 993 Count++; 994 } 995 996 External = External->Next; 997 } 998 999 return (Count); 1000 } 1001 1002 1003 /******************************************************************************* 1004 * 1005 * FUNCTION: AcpiDmClearExternalList 1006 * 1007 * PARAMETERS: None 1008 * 1009 * RETURN: None 1010 * 1011 * DESCRIPTION: Free the entire External info list 1012 * 1013 ******************************************************************************/ 1014 1015 void 1016 AcpiDmClearExternalList ( 1017 void) 1018 { 1019 ACPI_EXTERNAL_LIST *NextExternal; 1020 1021 1022 while (AcpiGbl_ExternalList) 1023 { 1024 NextExternal = AcpiGbl_ExternalList->Next; 1025 ACPI_FREE (AcpiGbl_ExternalList->Path); 1026 ACPI_FREE (AcpiGbl_ExternalList); 1027 AcpiGbl_ExternalList = NextExternal; 1028 } 1029 } 1030 1031 1032 /******************************************************************************* 1033 * 1034 * FUNCTION: AcpiDmEmitExternals 1035 * 1036 * PARAMETERS: None 1037 * 1038 * RETURN: None 1039 * 1040 * DESCRIPTION: Emit an External() ASL statement for each of the externals in 1041 * the global external info list. 1042 * 1043 ******************************************************************************/ 1044 1045 void 1046 AcpiDmEmitExternals ( 1047 void) 1048 { 1049 ACPI_EXTERNAL_LIST *NextExternal; 1050 1051 1052 if (!AcpiGbl_ExternalList) 1053 { 1054 return; 1055 } 1056 1057 /* 1058 * Determine the number of control methods in the external list, and 1059 * also how many of those externals were resolved via the namespace. 1060 */ 1061 NextExternal = AcpiGbl_ExternalList; 1062 while (NextExternal) 1063 { 1064 if (NextExternal->Type == ACPI_TYPE_METHOD) 1065 { 1066 AcpiGbl_NumExternalMethods++; 1067 if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE) 1068 { 1069 AcpiGbl_ResolvedExternalMethods++; 1070 } 1071 } 1072 1073 NextExternal = NextExternal->Next; 1074 } 1075 1076 /* Check if any control methods were unresolved */ 1077 1078 AcpiDmUnresolvedWarning (1); 1079 1080 /* Emit any unresolved method externals in a single text block */ 1081 1082 NextExternal = AcpiGbl_ExternalList; 1083 while (NextExternal) 1084 { 1085 if ((NextExternal->Type == ACPI_TYPE_METHOD) && 1086 (!(NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE))) 1087 { 1088 AcpiOsPrintf (" External (%s%s", 1089 NextExternal->Path, 1090 AcpiDmGetObjectTypeName (NextExternal->Type)); 1091 1092 AcpiOsPrintf (") // Warning: Unresolved method, " 1093 "guessing %u arguments\n", 1094 NextExternal->Value); 1095 1096 NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED; 1097 } 1098 1099 NextExternal = NextExternal->Next; 1100 } 1101 1102 AcpiOsPrintf ("\n"); 1103 1104 1105 /* Emit externals that were imported from a file */ 1106 1107 if (Gbl_ExternalRefFilename) 1108 { 1109 AcpiOsPrintf ( 1110 " /*\n * External declarations that were imported from\n" 1111 " * the reference file [%s]\n */\n", 1112 Gbl_ExternalRefFilename); 1113 1114 NextExternal = AcpiGbl_ExternalList; 1115 while (NextExternal) 1116 { 1117 if (!(NextExternal->Flags & ACPI_EXT_EXTERNAL_EMITTED) && 1118 (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_FILE)) 1119 { 1120 AcpiOsPrintf (" External (%s%s", 1121 NextExternal->Path, 1122 AcpiDmGetObjectTypeName (NextExternal->Type)); 1123 1124 if (NextExternal->Type == ACPI_TYPE_METHOD) 1125 { 1126 AcpiOsPrintf (") // %u Arguments\n", 1127 NextExternal->Value); 1128 } 1129 else 1130 { 1131 AcpiOsPrintf (")\n"); 1132 } 1133 NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED; 1134 } 1135 1136 NextExternal = NextExternal->Next; 1137 } 1138 1139 AcpiOsPrintf ("\n"); 1140 } 1141 1142 /* 1143 * Walk the list of externals found during the AML parsing 1144 */ 1145 while (AcpiGbl_ExternalList) 1146 { 1147 if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED)) 1148 { 1149 AcpiOsPrintf (" External (%s%s", 1150 AcpiGbl_ExternalList->Path, 1151 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type)); 1152 1153 /* For methods, add a comment with the number of arguments */ 1154 1155 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) 1156 { 1157 AcpiOsPrintf (") // %u Arguments\n", 1158 AcpiGbl_ExternalList->Value); 1159 } 1160 else 1161 { 1162 AcpiOsPrintf (")\n"); 1163 } 1164 } 1165 1166 /* Free this external info block and move on to next external */ 1167 1168 NextExternal = AcpiGbl_ExternalList->Next; 1169 if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED) 1170 { 1171 ACPI_FREE (AcpiGbl_ExternalList->InternalPath); 1172 } 1173 1174 ACPI_FREE (AcpiGbl_ExternalList->Path); 1175 ACPI_FREE (AcpiGbl_ExternalList); 1176 AcpiGbl_ExternalList = NextExternal; 1177 } 1178 1179 AcpiOsPrintf ("\n"); 1180 } 1181 1182 1183 /******************************************************************************* 1184 * 1185 * FUNCTION: AcpiDmUnresolvedWarning 1186 * 1187 * PARAMETERS: Type - Where to output the warning. 1188 * 0 means write to stderr 1189 * 1 means write to AcpiOsPrintf 1190 * 1191 * RETURN: None 1192 * 1193 * DESCRIPTION: Issue warning message if there are unresolved external control 1194 * methods within the disassembly. 1195 * 1196 ******************************************************************************/ 1197 1198 #if 0 1199 Summary of the external control method problem: 1200 1201 When the -e option is used with disassembly, the various SSDTs are simply 1202 loaded into a global namespace for the disassembler to use in order to 1203 resolve control method references (invocations). 1204 1205 The disassembler tracks any such references, and will emit an External() 1206 statement for these types of methods, with the proper number of arguments . 1207 1208 Without the SSDTs, the AML does not contain enough information to properly 1209 disassemble the control method invocation -- because the disassembler does 1210 not know how many arguments to parse. 1211 1212 An example: Assume we have two control methods. ABCD has one argument, and 1213 EFGH has zero arguments. Further, we have two additional control methods 1214 that invoke ABCD and EFGH, named T1 and T2: 1215 1216 Method (ABCD, 1) 1217 { 1218 } 1219 Method (EFGH, 0) 1220 { 1221 } 1222 Method (T1) 1223 { 1224 ABCD (Add (2, 7, Local0)) 1225 } 1226 Method (T2) 1227 { 1228 EFGH () 1229 Add (2, 7, Local0) 1230 } 1231 1232 Here is the AML code that is generated for T1 and T2: 1233 1234 185: Method (T1) 1235 1236 0000034C: 14 10 54 31 5F 5F 00 ... "..T1__." 1237 1238 186: { 1239 187: ABCD (Add (2, 7, Local0)) 1240 1241 00000353: 41 42 43 44 ............ "ABCD" 1242 00000357: 72 0A 02 0A 07 60 ...... "r....`" 1243 1244 188: } 1245 1246 190: Method (T2) 1247 1248 0000035D: 14 10 54 32 5F 5F 00 ... "..T2__." 1249 1250 191: { 1251 192: EFGH () 1252 1253 00000364: 45 46 47 48 ............ "EFGH" 1254 1255 193: Add (2, 7, Local0) 1256 1257 00000368: 72 0A 02 0A 07 60 ...... "r....`" 1258 194: } 1259 1260 Note that the AML code for T1 and T2 is essentially identical. When 1261 disassembling this code, the methods ABCD and EFGH must be known to the 1262 disassembler, otherwise it does not know how to handle the method invocations. 1263 1264 In other words, if ABCD and EFGH are actually external control methods 1265 appearing in an SSDT, the disassembler does not know what to do unless 1266 the owning SSDT has been loaded via the -e option. 1267 #endif 1268 1269 void 1270 AcpiDmUnresolvedWarning ( 1271 UINT8 Type) 1272 { 1273 1274 if (!AcpiGbl_NumExternalMethods) 1275 { 1276 return; 1277 } 1278 1279 if (Type) 1280 { 1281 if (!AcpiGbl_ExternalFileList) 1282 { 1283 /* The -e option was not specified */ 1284 1285 AcpiOsPrintf (" /*\n" 1286 " * iASL Warning: There were %u external control methods found during\n" 1287 " * disassembly, but additional ACPI tables to resolve these externals\n" 1288 " * were not specified. This resulting disassembler output file may not\n" 1289 " * compile because the disassembler did not know how many arguments\n" 1290 " * to assign to these methods. To specify the tables needed to resolve\n" 1291 " * external control method references, the -e option can be used to\n" 1292 " * specify the filenames. Note: SSDTs can be dynamically loaded at\n" 1293 " * runtime and may or may not be available via the host OS.\n" 1294 " * Example iASL invocations:\n" 1295 " * iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n" 1296 " * iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n" 1297 " * iasl -e ssdt*.aml -d dsdt.aml\n" 1298 " *\n" 1299 " * In addition, the -fe option can be used to specify a file containing\n" 1300 " * control method external declarations with the associated method\n" 1301 " * argument counts. Each line of the file must be of the form:\n" 1302 " * External (<method pathname>, MethodObj, <argument count>)\n" 1303 " * Invocation:\n" 1304 " * iasl -fe refs.txt -d dsdt.aml\n" 1305 " *\n" 1306 " * The following methods were unresolved and many not compile properly\n" 1307 " * because the disassembler had to guess at the number of arguments\n" 1308 " * required for each:\n" 1309 " */\n", 1310 AcpiGbl_NumExternalMethods); 1311 } 1312 else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods) 1313 { 1314 /* The -e option was specified, but there are still some unresolved externals */ 1315 1316 AcpiOsPrintf (" /*\n" 1317 " * iASL Warning: There were %u external control methods found during\n" 1318 " * disassembly, but only %u %s resolved (%u unresolved). Additional\n" 1319 " * ACPI tables may be required to properly disassemble the code. This\n" 1320 " * resulting disassembler output file may not compile because the\n" 1321 " * disassembler did not know how many arguments to assign to the\n" 1322 " * unresolved methods. Note: SSDTs can be dynamically loaded at\n" 1323 " * runtime and may or may not be available via the host OS.\n" 1324 " *\n" 1325 " * If necessary, the -fe option can be used to specify a file containing\n" 1326 " * control method external declarations with the associated method\n" 1327 " * argument counts. Each line of the file must be of the form:\n" 1328 " * External (<method pathname>, MethodObj, <argument count>)\n" 1329 " * Invocation:\n" 1330 " * iasl -fe refs.txt -d dsdt.aml\n" 1331 " *\n" 1332 " * The following methods were unresolved and many not compile properly\n" 1333 " * because the disassembler had to guess at the number of arguments\n" 1334 " * required for each:\n" 1335 " */\n", 1336 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods, 1337 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"), 1338 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods)); 1339 } 1340 } 1341 else 1342 { 1343 if (!AcpiGbl_ExternalFileList) 1344 { 1345 /* The -e option was not specified */ 1346 1347 fprintf (stderr, "\n" 1348 "iASL Warning: There were %u external control methods found during\n" 1349 "disassembly, but additional ACPI tables to resolve these externals\n" 1350 "were not specified. The resulting disassembler output file may not\n" 1351 "compile because the disassembler did not know how many arguments\n" 1352 "to assign to these methods. To specify the tables needed to resolve\n" 1353 "external control method references, the -e option can be used to\n" 1354 "specify the filenames. Note: SSDTs can be dynamically loaded at\n" 1355 "runtime and may or may not be available via the host OS.\n" 1356 "Example iASL invocations:\n" 1357 " iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n" 1358 " iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n" 1359 " iasl -e ssdt*.aml -d dsdt.aml\n" 1360 "\n" 1361 "In addition, the -fe option can be used to specify a file containing\n" 1362 "control method external declarations with the associated method\n" 1363 "argument counts. Each line of the file must be of the form:\n" 1364 " External (<method pathname>, MethodObj, <argument count>)\n" 1365 "Invocation:\n" 1366 " iasl -fe refs.txt -d dsdt.aml\n", 1367 AcpiGbl_NumExternalMethods); 1368 } 1369 else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods) 1370 { 1371 /* The -e option was specified, but there are still some unresolved externals */ 1372 1373 fprintf (stderr, "\n" 1374 "iASL Warning: There were %u external control methods found during\n" 1375 "disassembly, but only %u %s resolved (%u unresolved). Additional\n" 1376 "ACPI tables may be required to properly disassemble the code. The\n" 1377 "resulting disassembler output file may not compile because the\n" 1378 "disassembler did not know how many arguments to assign to the\n" 1379 "unresolved methods. Note: SSDTs can be dynamically loaded at\n" 1380 "runtime and may or may not be available via the host OS.\n" 1381 "\n" 1382 "If necessary, the -fe option can be used to specify a file containing\n" 1383 "control method external declarations with the associated method\n" 1384 "argument counts. Each line of the file must be of the form:\n" 1385 " External (<method pathname>, MethodObj, <argument count>)\n" 1386 "Invocation:\n" 1387 " iasl -fe refs.txt -d dsdt.aml\n", 1388 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods, 1389 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"), 1390 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods)); 1391 } 1392 } 1393 } 1394