1 /****************************************************************************** 2 * 3 * Module Name: dmextern - Support for External() ASL statements 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, 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 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 AslAbort (); 401 return; 402 } 403 404 /* Each line defines a method */ 405 406 while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ExternalRefFile)) 407 { 408 Token = strtok (StringBuffer, METHOD_SEPARATORS); /* "External" */ 409 if (!Token) continue; 410 if (strcmp (Token, "External")) continue; 411 412 MethodName = strtok (NULL, METHOD_SEPARATORS); /* Method namepath */ 413 if (!MethodName) continue; 414 415 Token = strtok (NULL, METHOD_SEPARATORS); /* "MethodObj" */ 416 if (!Token) continue; 417 if (strcmp (Token, "MethodObj")) continue; 418 419 Token = strtok (NULL, METHOD_SEPARATORS); /* Arg count */ 420 if (!Token) continue; 421 422 /* Convert arg count string to an integer */ 423 424 errno = 0; 425 ArgCount = strtoul (Token, NULL, 0); 426 if (errno) 427 { 428 fprintf (stderr, "Invalid argument count (%s)\n", Token); 429 continue; 430 } 431 if (ArgCount > 7) 432 { 433 fprintf (stderr, "Invalid argument count (%u)\n", ArgCount); 434 continue; 435 } 436 437 /* Add this external to the global list */ 438 439 AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n", 440 Gbl_ExternalRefFilename, ArgCount, MethodName); 441 442 AcpiDmAddPathToExternalList (MethodName, ACPI_TYPE_METHOD, 443 ArgCount, (ACPI_EXT_RESOLVED_REFERENCE | ACPI_EXT_ORIGIN_FROM_FILE)); 444 ImportCount++; 445 } 446 447 if (!ImportCount) 448 { 449 fprintf (stderr, "Did not find any external methods in reference file \"%s\"\n", 450 Gbl_ExternalRefFilename); 451 } 452 else 453 { 454 /* Add the external(s) to the namespace */ 455 456 AcpiDmAddExternalsToNamespace (); 457 458 AcpiOsPrintf ("%s: Imported %u external method definitions\n", 459 Gbl_ExternalRefFilename, ImportCount); 460 } 461 462 fclose (ExternalRefFile); 463 } 464 465 466 /******************************************************************************* 467 * 468 * FUNCTION: AcpiDmAddOpToExternalList 469 * 470 * PARAMETERS: Op - Current parser Op 471 * Path - Internal (AML) path to the object 472 * Type - ACPI object type to be added 473 * Value - Arg count if adding a Method object 474 * Flags - To be passed to the external object 475 * 476 * RETURN: None 477 * 478 * DESCRIPTION: Insert a new name into the global list of Externals which 479 * will in turn be later emitted as an External() declaration 480 * in the disassembled output. 481 * 482 * This function handles the most common case where the referenced 483 * name is simply not found in the constructed namespace. 484 * 485 ******************************************************************************/ 486 487 void 488 AcpiDmAddOpToExternalList ( 489 ACPI_PARSE_OBJECT *Op, 490 char *Path, 491 UINT8 Type, 492 UINT32 Value, 493 UINT16 Flags) 494 { 495 char *ExternalPath; 496 char *InternalPath = Path; 497 char *Temp; 498 ACPI_STATUS Status; 499 500 501 ACPI_FUNCTION_TRACE (DmAddOpToExternalList); 502 503 504 if (!Path) 505 { 506 return_VOID; 507 } 508 509 /* Remove a root backslash if present */ 510 511 if ((*Path == AML_ROOT_PREFIX) && (Path[1])) 512 { 513 Path++; 514 } 515 516 /* Externalize the pathname */ 517 518 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path, 519 NULL, &ExternalPath); 520 if (ACPI_FAILURE (Status)) 521 { 522 return_VOID; 523 } 524 525 /* 526 * Get the full pathname from the root if "Path" has one or more 527 * parent prefixes (^). Note: path will not contain a leading '\'. 528 */ 529 if (*Path == (UINT8) AML_PARENT_PREFIX) 530 { 531 Temp = AcpiDmNormalizeParentPrefix (Op, ExternalPath); 532 533 /* Set new external path */ 534 535 ACPI_FREE (ExternalPath); 536 ExternalPath = Temp; 537 if (!Temp) 538 { 539 return_VOID; 540 } 541 542 /* Create the new internal pathname */ 543 544 Flags |= ACPI_EXT_INTERNAL_PATH_ALLOCATED; 545 Status = AcpiNsInternalizeName (ExternalPath, &InternalPath); 546 if (ACPI_FAILURE (Status)) 547 { 548 ACPI_FREE (ExternalPath); 549 return_VOID; 550 } 551 } 552 553 /* Create the new External() declaration node */ 554 555 Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, 556 Type, Value, Flags); 557 if (ACPI_FAILURE (Status)) 558 { 559 ACPI_FREE (ExternalPath); 560 if (Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED) 561 { 562 ACPI_FREE (InternalPath); 563 } 564 } 565 566 return_VOID; 567 } 568 569 570 /******************************************************************************* 571 * 572 * FUNCTION: AcpiDmAddNodeToExternalList 573 * 574 * PARAMETERS: Node - Namespace node for object to be added 575 * Type - ACPI object type to be added 576 * Value - Arg count if adding a Method object 577 * Flags - To be passed to the external object 578 * 579 * RETURN: None 580 * 581 * DESCRIPTION: Insert a new name into the global list of Externals which 582 * will in turn be later emitted as an External() declaration 583 * in the disassembled output. 584 * 585 * This function handles the case where the referenced name has 586 * been found in the namespace, but the name originated in a 587 * table other than the one that is being disassembled (such 588 * as a table that is added via the iASL -e option). 589 * 590 ******************************************************************************/ 591 592 void 593 AcpiDmAddNodeToExternalList ( 594 ACPI_NAMESPACE_NODE *Node, 595 UINT8 Type, 596 UINT32 Value, 597 UINT16 Flags) 598 { 599 char *ExternalPath; 600 char *InternalPath; 601 char *Temp; 602 ACPI_STATUS Status; 603 604 605 ACPI_FUNCTION_TRACE (DmAddNodeToExternalList); 606 607 608 if (!Node) 609 { 610 return_VOID; 611 } 612 613 /* Get the full external and internal pathnames to the node */ 614 615 ExternalPath = AcpiNsGetExternalPathname (Node); 616 if (!ExternalPath) 617 { 618 return_VOID; 619 } 620 621 Status = AcpiNsInternalizeName (ExternalPath, &InternalPath); 622 if (ACPI_FAILURE (Status)) 623 { 624 ACPI_FREE (ExternalPath); 625 return_VOID; 626 } 627 628 /* Remove the root backslash */ 629 630 if ((*ExternalPath == AML_ROOT_PREFIX) && (ExternalPath[1])) 631 { 632 Temp = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (ExternalPath) + 1); 633 if (!Temp) 634 { 635 return_VOID; 636 } 637 638 ACPI_STRCPY (Temp, &ExternalPath[1]); 639 ACPI_FREE (ExternalPath); 640 ExternalPath = Temp; 641 } 642 643 /* Create the new External() declaration node */ 644 645 Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, Type, 646 Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED)); 647 if (ACPI_FAILURE (Status)) 648 { 649 ACPI_FREE (ExternalPath); 650 ACPI_FREE (InternalPath); 651 } 652 653 return_VOID; 654 } 655 656 657 /******************************************************************************* 658 * 659 * FUNCTION: AcpiDmAddPathToExternalList 660 * 661 * PARAMETERS: Path - External name of the object to be added 662 * Type - ACPI object type to be added 663 * Value - Arg count if adding a Method object 664 * Flags - To be passed to the external object 665 * 666 * RETURN: None 667 * 668 * DESCRIPTION: Insert a new name into the global list of Externals which 669 * will in turn be later emitted as an External() declaration 670 * in the disassembled output. 671 * 672 * This function currently is used to add externals via a 673 * reference file (via the -fe iASL option). 674 * 675 ******************************************************************************/ 676 677 static void 678 AcpiDmAddPathToExternalList ( 679 char *Path, 680 UINT8 Type, 681 UINT32 Value, 682 UINT16 Flags) 683 { 684 char *InternalPath; 685 char *ExternalPath; 686 ACPI_STATUS Status; 687 688 689 ACPI_FUNCTION_TRACE (DmAddPathToExternalList); 690 691 692 if (!Path) 693 { 694 return_VOID; 695 } 696 697 /* Remove a root backslash if present */ 698 699 if ((*Path == AML_ROOT_PREFIX) && (Path[1])) 700 { 701 Path++; 702 } 703 704 /* Create the internal and external pathnames */ 705 706 Status = AcpiNsInternalizeName (Path, &InternalPath); 707 if (ACPI_FAILURE (Status)) 708 { 709 return_VOID; 710 } 711 712 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath, 713 NULL, &ExternalPath); 714 if (ACPI_FAILURE (Status)) 715 { 716 ACPI_FREE (InternalPath); 717 return_VOID; 718 } 719 720 /* Create the new External() declaration node */ 721 722 Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, 723 Type, Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED)); 724 if (ACPI_FAILURE (Status)) 725 { 726 ACPI_FREE (ExternalPath); 727 ACPI_FREE (InternalPath); 728 } 729 730 return_VOID; 731 } 732 733 734 /******************************************************************************* 735 * 736 * FUNCTION: AcpiDmCreateNewExternal 737 * 738 * PARAMETERS: ExternalPath - External path to the object 739 * InternalPath - Internal (AML) path to the object 740 * Type - ACPI object type to be added 741 * Value - Arg count if adding a Method object 742 * Flags - To be passed to the external object 743 * 744 * RETURN: Status 745 * 746 * DESCRIPTION: Common low-level function to insert a new name into the global 747 * list of Externals which will in turn be later emitted as 748 * External() declarations in the disassembled output. 749 * 750 * Note: The external name should not include a root prefix 751 * (backslash). We do not want External() statements to contain 752 * a leading '\', as this prevents duplicate external statements 753 * of the form: 754 * 755 * External (\ABCD) 756 * External (ABCD) 757 * 758 * This would cause a compile time error when the disassembled 759 * output file is recompiled. 760 * 761 * There are two cases that are handled here. For both, we emit 762 * an External() statement: 763 * 1) The name was simply not found in the namespace. 764 * 2) The name was found, but it originated in a table other than 765 * the table that is being disassembled. 766 * 767 ******************************************************************************/ 768 769 static ACPI_STATUS 770 AcpiDmCreateNewExternal ( 771 char *ExternalPath, 772 char *InternalPath, 773 UINT8 Type, 774 UINT32 Value, 775 UINT16 Flags) 776 { 777 ACPI_EXTERNAL_LIST *NewExternal; 778 ACPI_EXTERNAL_LIST *NextExternal; 779 ACPI_EXTERNAL_LIST *PrevExternal = NULL; 780 781 782 ACPI_FUNCTION_TRACE (DmCreateNewExternal); 783 784 785 /* Check all existing externals to ensure no duplicates */ 786 787 NextExternal = AcpiGbl_ExternalList; 788 while (NextExternal) 789 { 790 if (!ACPI_STRCMP (ExternalPath, NextExternal->Path)) 791 { 792 /* Duplicate method, check that the Value (ArgCount) is the same */ 793 794 if ((NextExternal->Type == ACPI_TYPE_METHOD) && 795 (NextExternal->Value != Value) && 796 (Value > 0)) 797 { 798 ACPI_ERROR ((AE_INFO, 799 "External method arg count mismatch %s: Current %u, attempted %u", 800 NextExternal->Path, NextExternal->Value, Value)); 801 } 802 803 /* Allow upgrade of type from ANY */ 804 805 else if (NextExternal->Type == ACPI_TYPE_ANY) 806 { 807 NextExternal->Type = Type; 808 NextExternal->Value = Value; 809 } 810 811 return_ACPI_STATUS (AE_ALREADY_EXISTS); 812 } 813 814 NextExternal = NextExternal->Next; 815 } 816 817 /* Allocate and init a new External() descriptor */ 818 819 NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST)); 820 if (!NewExternal) 821 { 822 return_ACPI_STATUS (AE_NO_MEMORY); 823 } 824 825 ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, 826 "Adding external reference node (%s) type [%s]\n", 827 ExternalPath, AcpiUtGetTypeName (Type))); 828 829 NewExternal->Flags = Flags; 830 NewExternal->Value = Value; 831 NewExternal->Path = ExternalPath; 832 NewExternal->Type = Type; 833 NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath); 834 NewExternal->InternalPath = InternalPath; 835 836 /* Link the new descriptor into the global list, alphabetically ordered */ 837 838 NextExternal = AcpiGbl_ExternalList; 839 while (NextExternal) 840 { 841 if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0) 842 { 843 if (PrevExternal) 844 { 845 PrevExternal->Next = NewExternal; 846 } 847 else 848 { 849 AcpiGbl_ExternalList = NewExternal; 850 } 851 852 NewExternal->Next = NextExternal; 853 return_ACPI_STATUS (AE_OK); 854 } 855 856 PrevExternal = NextExternal; 857 NextExternal = NextExternal->Next; 858 } 859 860 if (PrevExternal) 861 { 862 PrevExternal->Next = NewExternal; 863 } 864 else 865 { 866 AcpiGbl_ExternalList = NewExternal; 867 } 868 869 return_ACPI_STATUS (AE_OK); 870 } 871 872 873 /******************************************************************************* 874 * 875 * FUNCTION: AcpiDmAddExternalsToNamespace 876 * 877 * PARAMETERS: None 878 * 879 * RETURN: None 880 * 881 * DESCRIPTION: Add all externals to the namespace. Allows externals to be 882 * "resolved". 883 * 884 ******************************************************************************/ 885 886 void 887 AcpiDmAddExternalsToNamespace ( 888 void) 889 { 890 ACPI_STATUS Status; 891 ACPI_NAMESPACE_NODE *Node; 892 ACPI_OPERAND_OBJECT *ObjDesc; 893 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 894 895 896 while (External) 897 { 898 /* Add the external name (object) into the namespace */ 899 900 Status = AcpiNsLookup (NULL, External->InternalPath, External->Type, 901 ACPI_IMODE_LOAD_PASS1, 902 ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE, 903 NULL, &Node); 904 905 if (ACPI_FAILURE (Status)) 906 { 907 ACPI_EXCEPTION ((AE_INFO, Status, 908 "while adding external to namespace [%s]", 909 External->Path)); 910 } 911 912 else switch (External->Type) 913 { 914 case ACPI_TYPE_METHOD: 915 916 /* For methods, we need to save the argument count */ 917 918 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); 919 ObjDesc->Method.ParamCount = (UINT8) External->Value; 920 Node->Object = ObjDesc; 921 break; 922 923 case ACPI_TYPE_REGION: 924 925 /* Regions require a region sub-object */ 926 927 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION); 928 ObjDesc->Region.Node = Node; 929 Node->Object = ObjDesc; 930 break; 931 932 default: 933 934 break; 935 } 936 937 External = External->Next; 938 } 939 } 940 941 942 /******************************************************************************* 943 * 944 * FUNCTION: AcpiDmGetExternalMethodCount 945 * 946 * PARAMETERS: None 947 * 948 * RETURN: The number of control method externals in the external list 949 * 950 * DESCRIPTION: Return the number of method externals that have been generated. 951 * If any control method externals have been found, we must 952 * re-parse the entire definition block with the new information 953 * (number of arguments for the methods.) This is limitation of 954 * AML, we don't know the number of arguments from the control 955 * method invocation itself. 956 * 957 ******************************************************************************/ 958 959 UINT32 960 AcpiDmGetExternalMethodCount ( 961 void) 962 { 963 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList; 964 UINT32 Count = 0; 965 966 967 while (External) 968 { 969 if (External->Type == ACPI_TYPE_METHOD) 970 { 971 Count++; 972 } 973 974 External = External->Next; 975 } 976 977 return (Count); 978 } 979 980 981 /******************************************************************************* 982 * 983 * FUNCTION: AcpiDmClearExternalList 984 * 985 * PARAMETERS: None 986 * 987 * RETURN: None 988 * 989 * DESCRIPTION: Free the entire External info list 990 * 991 ******************************************************************************/ 992 993 void 994 AcpiDmClearExternalList ( 995 void) 996 { 997 ACPI_EXTERNAL_LIST *NextExternal; 998 999 1000 while (AcpiGbl_ExternalList) 1001 { 1002 NextExternal = AcpiGbl_ExternalList->Next; 1003 ACPI_FREE (AcpiGbl_ExternalList->Path); 1004 ACPI_FREE (AcpiGbl_ExternalList); 1005 AcpiGbl_ExternalList = NextExternal; 1006 } 1007 } 1008 1009 1010 /******************************************************************************* 1011 * 1012 * FUNCTION: AcpiDmEmitExternals 1013 * 1014 * PARAMETERS: None 1015 * 1016 * RETURN: None 1017 * 1018 * DESCRIPTION: Emit an External() ASL statement for each of the externals in 1019 * the global external info list. 1020 * 1021 ******************************************************************************/ 1022 1023 void 1024 AcpiDmEmitExternals ( 1025 void) 1026 { 1027 ACPI_EXTERNAL_LIST *NextExternal; 1028 1029 1030 if (!AcpiGbl_ExternalList) 1031 { 1032 return; 1033 } 1034 1035 /* 1036 * Determine the number of control methods in the external list, and 1037 * also how many of those externals were resolved via the namespace. 1038 */ 1039 NextExternal = AcpiGbl_ExternalList; 1040 while (NextExternal) 1041 { 1042 if (NextExternal->Type == ACPI_TYPE_METHOD) 1043 { 1044 AcpiGbl_NumExternalMethods++; 1045 if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE) 1046 { 1047 AcpiGbl_ResolvedExternalMethods++; 1048 } 1049 } 1050 1051 NextExternal = NextExternal->Next; 1052 } 1053 1054 /* Check if any control methods were unresolved */ 1055 1056 AcpiDmUnresolvedWarning (1); 1057 1058 /* Emit any unresolved method externals in a single text block */ 1059 1060 NextExternal = AcpiGbl_ExternalList; 1061 while (NextExternal) 1062 { 1063 if ((NextExternal->Type == ACPI_TYPE_METHOD) && 1064 (!(NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE))) 1065 { 1066 AcpiOsPrintf (" External (%s%s", 1067 NextExternal->Path, 1068 AcpiDmGetObjectTypeName (NextExternal->Type)); 1069 1070 AcpiOsPrintf (") // Warning: Unresolved method, " 1071 "guessing %u arguments\n", 1072 NextExternal->Value); 1073 1074 NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED; 1075 } 1076 1077 NextExternal = NextExternal->Next; 1078 } 1079 1080 AcpiOsPrintf ("\n"); 1081 1082 1083 /* Emit externals that were imported from a file */ 1084 1085 if (Gbl_ExternalRefFilename) 1086 { 1087 AcpiOsPrintf ( 1088 " /*\n * External declarations that were imported from\n" 1089 " * the reference file [%s]\n */\n", 1090 Gbl_ExternalRefFilename); 1091 1092 NextExternal = AcpiGbl_ExternalList; 1093 while (NextExternal) 1094 { 1095 if (!(NextExternal->Flags & ACPI_EXT_EXTERNAL_EMITTED) && 1096 (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_FILE)) 1097 { 1098 AcpiOsPrintf (" External (%s%s", 1099 NextExternal->Path, 1100 AcpiDmGetObjectTypeName (NextExternal->Type)); 1101 1102 if (NextExternal->Type == ACPI_TYPE_METHOD) 1103 { 1104 AcpiOsPrintf (") // %u Arguments\n", 1105 NextExternal->Value); 1106 } 1107 else 1108 { 1109 AcpiOsPrintf (")\n"); 1110 } 1111 NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED; 1112 } 1113 1114 NextExternal = NextExternal->Next; 1115 } 1116 1117 AcpiOsPrintf ("\n"); 1118 } 1119 1120 /* 1121 * Walk the list of externals found during the AML parsing 1122 */ 1123 while (AcpiGbl_ExternalList) 1124 { 1125 if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED)) 1126 { 1127 AcpiOsPrintf (" External (%s%s", 1128 AcpiGbl_ExternalList->Path, 1129 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type)); 1130 1131 /* For methods, add a comment with the number of arguments */ 1132 1133 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) 1134 { 1135 AcpiOsPrintf (") // %u Arguments\n", 1136 AcpiGbl_ExternalList->Value); 1137 } 1138 else 1139 { 1140 AcpiOsPrintf (")\n"); 1141 } 1142 } 1143 1144 /* Free this external info block and move on to next external */ 1145 1146 NextExternal = AcpiGbl_ExternalList->Next; 1147 if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED) 1148 { 1149 ACPI_FREE (AcpiGbl_ExternalList->InternalPath); 1150 } 1151 1152 ACPI_FREE (AcpiGbl_ExternalList->Path); 1153 ACPI_FREE (AcpiGbl_ExternalList); 1154 AcpiGbl_ExternalList = NextExternal; 1155 } 1156 1157 AcpiOsPrintf ("\n"); 1158 } 1159 1160 1161 /******************************************************************************* 1162 * 1163 * FUNCTION: AcpiDmUnresolvedWarning 1164 * 1165 * PARAMETERS: Type - Where to output the warning. 1166 * 0 means write to stderr 1167 * 1 means write to AcpiOsPrintf 1168 * 1169 * RETURN: None 1170 * 1171 * DESCRIPTION: Issue warning message if there are unresolved external control 1172 * methods within the disassembly. 1173 * 1174 ******************************************************************************/ 1175 1176 #if 0 1177 Summary of the external control method problem: 1178 1179 When the -e option is used with disassembly, the various SSDTs are simply 1180 loaded into a global namespace for the disassembler to use in order to 1181 resolve control method references (invocations). 1182 1183 The disassembler tracks any such references, and will emit an External() 1184 statement for these types of methods, with the proper number of arguments . 1185 1186 Without the SSDTs, the AML does not contain enough information to properly 1187 disassemble the control method invocation -- because the disassembler does 1188 not know how many arguments to parse. 1189 1190 An example: Assume we have two control methods. ABCD has one argument, and 1191 EFGH has zero arguments. Further, we have two additional control methods 1192 that invoke ABCD and EFGH, named T1 and T2: 1193 1194 Method (ABCD, 1) 1195 { 1196 } 1197 Method (EFGH, 0) 1198 { 1199 } 1200 Method (T1) 1201 { 1202 ABCD (Add (2, 7, Local0)) 1203 } 1204 Method (T2) 1205 { 1206 EFGH () 1207 Add (2, 7, Local0) 1208 } 1209 1210 Here is the AML code that is generated for T1 and T2: 1211 1212 185: Method (T1) 1213 1214 0000034C: 14 10 54 31 5F 5F 00 ... "..T1__." 1215 1216 186: { 1217 187: ABCD (Add (2, 7, Local0)) 1218 1219 00000353: 41 42 43 44 ............ "ABCD" 1220 00000357: 72 0A 02 0A 07 60 ...... "r....`" 1221 1222 188: } 1223 1224 190: Method (T2) 1225 1226 0000035D: 14 10 54 32 5F 5F 00 ... "..T2__." 1227 1228 191: { 1229 192: EFGH () 1230 1231 00000364: 45 46 47 48 ............ "EFGH" 1232 1233 193: Add (2, 7, Local0) 1234 1235 00000368: 72 0A 02 0A 07 60 ...... "r....`" 1236 194: } 1237 1238 Note that the AML code for T1 and T2 is essentially identical. When 1239 disassembling this code, the methods ABCD and EFGH must be known to the 1240 disassembler, otherwise it does not know how to handle the method invocations. 1241 1242 In other words, if ABCD and EFGH are actually external control methods 1243 appearing in an SSDT, the disassembler does not know what to do unless 1244 the owning SSDT has been loaded via the -e option. 1245 #endif 1246 1247 void 1248 AcpiDmUnresolvedWarning ( 1249 UINT8 Type) 1250 { 1251 1252 if (!AcpiGbl_NumExternalMethods) 1253 { 1254 return; 1255 } 1256 1257 if (Type) 1258 { 1259 if (!AcpiGbl_ExternalFileList) 1260 { 1261 /* The -e option was not specified */ 1262 1263 AcpiOsPrintf (" /*\n" 1264 " * iASL Warning: There were %u external control methods found during\n" 1265 " * disassembly, but additional ACPI tables to resolve these externals\n" 1266 " * were not specified. This resulting disassembler output file may not\n" 1267 " * compile because the disassembler did not know how many arguments\n" 1268 " * to assign to these methods. To specify the tables needed to resolve\n" 1269 " * external control method references, the -e option can be used to\n" 1270 " * specify the filenames. Example iASL invocations:\n" 1271 " * iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n" 1272 " * iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n" 1273 " * iasl -e ssdt*.aml -d dsdt.aml\n" 1274 " *\n" 1275 " * In addition, the -fe option can be used to specify a file containing\n" 1276 " * control method external declarations with the associated method\n" 1277 " * argument counts. Each line of the file must be of the form:\n" 1278 " * External (<method pathname>, MethodObj, <argument count>)\n" 1279 " * Invocation:\n" 1280 " * iasl -fe refs.txt -d dsdt.aml\n" 1281 " *\n" 1282 " * The following methods were unresolved and many not compile properly\n" 1283 " * because the disassembler had to guess at the number of arguments\n" 1284 " * required for each:\n" 1285 " */\n", 1286 AcpiGbl_NumExternalMethods); 1287 } 1288 else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods) 1289 { 1290 /* The -e option was specified, but there are still some unresolved externals */ 1291 1292 AcpiOsPrintf (" /*\n" 1293 " * iASL Warning: There were %u external control methods found during\n" 1294 " * disassembly, but only %u %s resolved (%u unresolved). Additional\n" 1295 " * ACPI tables may be required to properly disassemble the code. This\n" 1296 " * resulting disassembler output file may not compile because the\n" 1297 " * disassembler did not know how many arguments to assign to the\n" 1298 " * unresolved methods.\n" 1299 " *\n" 1300 " * If necessary, the -fe option can be used to specify a file containing\n" 1301 " * control method external declarations with the associated method\n" 1302 " * argument counts. Each line of the file must be of the form:\n" 1303 " * External (<method pathname>, MethodObj, <argument count>)\n" 1304 " * Invocation:\n" 1305 " * iasl -fe refs.txt -d dsdt.aml\n" 1306 " *\n" 1307 " * The following methods were unresolved and many not compile properly\n" 1308 " * because the disassembler had to guess at the number of arguments\n" 1309 " * required for each:\n" 1310 " */\n", 1311 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods, 1312 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"), 1313 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods)); 1314 } 1315 } 1316 else 1317 { 1318 if (!AcpiGbl_ExternalFileList) 1319 { 1320 /* The -e option was not specified */ 1321 1322 fprintf (stderr, "\n" 1323 "iASL Warning: There were %u external control methods found during\n" 1324 "disassembly, but additional ACPI tables to resolve these externals\n" 1325 "were not specified. The resulting disassembler output file may not\n" 1326 "compile because the disassembler did not know how many arguments\n" 1327 "to assign to these methods. To specify the tables needed to resolve\n" 1328 "external control method references, the -e option can be used to\n" 1329 "specify the filenames. Example iASL invocations:\n" 1330 " iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n" 1331 " iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n" 1332 " iasl -e ssdt*.aml -d dsdt.aml\n" 1333 "\n" 1334 "In addition, the -fe option can be used to specify a file containing\n" 1335 "control method external declarations with the associated method\n" 1336 "argument counts. Each line of the file must be of the form:\n" 1337 " External (<method pathname>, MethodObj, <argument count>)\n" 1338 "Invocation:\n" 1339 " iasl -fe refs.txt -d dsdt.aml\n", 1340 AcpiGbl_NumExternalMethods); 1341 } 1342 else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods) 1343 { 1344 /* The -e option was specified, but there are still some unresolved externals */ 1345 1346 fprintf (stderr, "\n" 1347 "iASL Warning: There were %u external control methods found during\n" 1348 "disassembly, but only %u %s resolved (%u unresolved). Additional\n" 1349 "ACPI tables may be required to properly disassemble the code. The\n" 1350 "resulting disassembler output file may not compile because the\n" 1351 "disassembler did not know how many arguments to assign to the\n" 1352 "unresolved methods.\n" 1353 "\n" 1354 "If necessary, the -fe option can be used to specify a file containing\n" 1355 "control method external declarations with the associated method\n" 1356 "argument counts. Each line of the file must be of the form:\n" 1357 " External (<method pathname>, MethodObj, <argument count>)\n" 1358 "Invocation:\n" 1359 " iasl -fe refs.txt -d dsdt.aml\n", 1360 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods, 1361 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"), 1362 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods)); 1363 } 1364 } 1365 } 1366