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