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