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