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