1 /******************************************************************************
2 *
3 * Module Name: dmextern - Support for External() ASL statements
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2022, 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 MERCHANTABILITY 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 static const char *ExternalConflictMessage =
95 " // Conflicts with a later declaration";
96
97
98 /* Local prototypes */
99
100 static const char *
101 AcpiDmGetObjectTypeName (
102 ACPI_OBJECT_TYPE Type);
103
104 static char *
105 AcpiDmNormalizeParentPrefix (
106 ACPI_PARSE_OBJECT *Op,
107 char *Path);
108
109 static ACPI_STATUS
110 AcpiDmGetExternalAndInternalPath (
111 ACPI_NAMESPACE_NODE *Node,
112 char **ExternalPath,
113 char **InternalPath);
114
115 static ACPI_STATUS
116 AcpiDmRemoveRootPrefix (
117 char **Path);
118
119 static void
120 AcpiDmAddPathToExternalList (
121 char *Path,
122 UINT8 Type,
123 UINT32 Value,
124 UINT16 Flags);
125
126 static ACPI_STATUS
127 AcpiDmCreateNewExternal (
128 char *ExternalPath,
129 char *InternalPath,
130 UINT8 Type,
131 UINT32 Value,
132 UINT16 Flags);
133
134 static void
135 AcpiDmCheckForExternalConflict (
136 char *Path);
137
138 static ACPI_STATUS
139 AcpiDmResolveExternal (
140 char *Path,
141 UINT8 Type,
142 ACPI_NAMESPACE_NODE **Node);
143
144
145 static void
146 AcpiDmConflictingDeclaration (
147 char *Path);
148
149
150 /*******************************************************************************
151 *
152 * FUNCTION: AcpiDmGetObjectTypeName
153 *
154 * PARAMETERS: Type - An ACPI_OBJECT_TYPE
155 *
156 * RETURN: Pointer to a string
157 *
158 * DESCRIPTION: Map an object type to the ASL object type string.
159 *
160 ******************************************************************************/
161
162 static const char *
AcpiDmGetObjectTypeName(ACPI_OBJECT_TYPE Type)163 AcpiDmGetObjectTypeName (
164 ACPI_OBJECT_TYPE Type)
165 {
166
167 if (Type == ACPI_TYPE_LOCAL_SCOPE)
168 {
169 Type = ACPI_TYPE_DEVICE;
170 }
171 else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
172 {
173 return ("");
174 }
175
176 return (AcpiGbl_DmTypeNames[Type]);
177 }
178
179
180 /*******************************************************************************
181 *
182 * FUNCTION: AcpiDmNormalizeParentPrefix
183 *
184 * PARAMETERS: Op - Parse op
185 * Path - Path with parent prefix
186 *
187 * RETURN: The full pathname to the object (from the namespace root)
188 *
189 * DESCRIPTION: Returns the full pathname of a path with parent prefix
190 * The caller must free the fullpath returned.
191 *
192 ******************************************************************************/
193
194 static char *
AcpiDmNormalizeParentPrefix(ACPI_PARSE_OBJECT * Op,char * Path)195 AcpiDmNormalizeParentPrefix (
196 ACPI_PARSE_OBJECT *Op,
197 char *Path)
198 {
199 ACPI_NAMESPACE_NODE *Node;
200 char *Fullpath;
201 char *ParentPath;
202 ACPI_SIZE Length;
203 UINT32 Index = 0;
204
205
206 if (!Op)
207 {
208 return (NULL);
209 }
210
211 /* Search upwards in the parse tree until we reach the next namespace node */
212
213 Op = Op->Common.Parent;
214 while (Op)
215 {
216 if (Op->Common.Node)
217 {
218 break;
219 }
220
221 Op = Op->Common.Parent;
222 }
223
224 if (!Op)
225 {
226 return (NULL);
227 }
228
229 /*
230 * Find the actual parent node for the reference:
231 * Remove all carat prefixes from the input path.
232 * There may be multiple parent prefixes (For example, ^^^M000)
233 */
234 Node = Op->Common.Node;
235 while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
236 {
237 Node = Node->Parent;
238 Path++;
239 }
240
241 if (!Node)
242 {
243 return (NULL);
244 }
245
246 /* Get the full pathname for the parent node */
247
248 ParentPath = AcpiNsGetExternalPathname (Node);
249 if (!ParentPath)
250 {
251 return (NULL);
252 }
253
254 Length = (strlen (ParentPath) + strlen (Path) + 1);
255 if (ParentPath[1])
256 {
257 /*
258 * If ParentPath is not just a simple '\', increment the length
259 * for the required dot separator (ParentPath.Path)
260 */
261 Length++;
262
263 /* For External() statements, we do not want a leading '\' */
264
265 if (*ParentPath == AML_ROOT_PREFIX)
266 {
267 Index = 1;
268 }
269 }
270
271 Fullpath = ACPI_ALLOCATE_ZEROED (Length);
272 if (!Fullpath)
273 {
274 goto Cleanup;
275 }
276
277 /*
278 * Concatenate parent fullpath and path. For example,
279 * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
280 *
281 * Copy the parent path
282 */
283 strcpy (Fullpath, &ParentPath[Index]);
284
285 /*
286 * Add dot separator
287 * (don't need dot if parent fullpath is a single backslash)
288 */
289 if (ParentPath[1])
290 {
291 strcat (Fullpath, ".");
292 }
293
294 /* Copy child path (carat parent prefix(es) were skipped above) */
295
296 strcat (Fullpath, Path);
297
298 Cleanup:
299 ACPI_FREE (ParentPath);
300 return (Fullpath);
301 }
302
303
304 /*******************************************************************************
305 *
306 * FUNCTION: AcpiDmAddToExternalFileList
307 *
308 * PARAMETERS: PathList - Single path or list separated by comma
309 *
310 * RETURN: None
311 *
312 * DESCRIPTION: Add external files to global list
313 *
314 ******************************************************************************/
315
316 ACPI_STATUS
AcpiDmAddToExternalFileList(char * Pathname)317 AcpiDmAddToExternalFileList (
318 char *Pathname)
319 {
320 ACPI_EXTERNAL_FILE *ExternalFile;
321 char *LocalPathname;
322
323
324 if (!Pathname)
325 {
326 return (AE_OK);
327 }
328
329 LocalPathname = ACPI_ALLOCATE (strlen (Pathname) + 1);
330 if (!LocalPathname)
331 {
332 return (AE_NO_MEMORY);
333 }
334
335 ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
336 if (!ExternalFile)
337 {
338 ACPI_FREE (LocalPathname);
339 return (AE_NO_MEMORY);
340 }
341
342 /* Take a copy of the file pathname */
343
344 strcpy (LocalPathname, Pathname);
345 ExternalFile->Path = LocalPathname;
346
347 if (AcpiGbl_ExternalFileList)
348 {
349 ExternalFile->Next = AcpiGbl_ExternalFileList;
350 }
351
352 AcpiGbl_ExternalFileList = ExternalFile;
353 return (AE_OK);
354 }
355
356
357 /*******************************************************************************
358 *
359 * FUNCTION: AcpiDmClearExternalFileList
360 *
361 * PARAMETERS: None
362 *
363 * RETURN: None
364 *
365 * DESCRIPTION: Clear the external file list
366 *
367 ******************************************************************************/
368
369 void
AcpiDmClearExternalFileList(void)370 AcpiDmClearExternalFileList (
371 void)
372 {
373 ACPI_EXTERNAL_FILE *NextExternal;
374
375
376 while (AcpiGbl_ExternalFileList)
377 {
378 NextExternal = AcpiGbl_ExternalFileList->Next;
379 ACPI_FREE (AcpiGbl_ExternalFileList->Path);
380 ACPI_FREE (AcpiGbl_ExternalFileList);
381 AcpiGbl_ExternalFileList = NextExternal;
382 }
383 }
384
385
386 /*******************************************************************************
387 *
388 * FUNCTION: AcpiDmGetExternalsFromFile
389 *
390 * PARAMETERS: None
391 *
392 * RETURN: None
393 *
394 * DESCRIPTION: Process the optional external reference file.
395 *
396 * Each line in the file should be of the form:
397 * External (<Method namepath>, MethodObj, <ArgCount>)
398 *
399 * Example:
400 * External (_SB_.PCI0.XHC_.PS0X, MethodObj, 4)
401 *
402 ******************************************************************************/
403
404 void
AcpiDmGetExternalsFromFile(void)405 AcpiDmGetExternalsFromFile (
406 void)
407 {
408 FILE *ExternalRefFile;
409 char *Token;
410 char *MethodName;
411 UINT32 ArgCount;
412 UINT32 ImportCount = 0;
413
414
415 if (!AslGbl_ExternalRefFilename)
416 {
417 return;
418 }
419
420 /* Open the file */
421
422 ExternalRefFile = fopen (AslGbl_ExternalRefFilename, "r");
423 if (!ExternalRefFile)
424 {
425 fprintf (stderr, "Could not open external reference file \"%s\"\n",
426 AslGbl_ExternalRefFilename);
427 AslAbort ();
428 return;
429 }
430
431 /* Each line defines a method */
432
433 while (fgets (AslGbl_StringBuffer, ASL_STRING_BUFFER_SIZE, ExternalRefFile))
434 {
435 Token = strtok (AslGbl_StringBuffer, METHOD_SEPARATORS); /* "External" */
436 if (!Token)
437 {
438 continue;
439 }
440
441 if (strcmp (Token, "External"))
442 {
443 continue;
444 }
445
446 MethodName = strtok (NULL, METHOD_SEPARATORS); /* Method namepath */
447 if (!MethodName)
448 {
449 continue;
450 }
451
452 Token = strtok (NULL, METHOD_SEPARATORS); /* "MethodObj" */
453 if (!Token)
454 {
455 continue;
456 }
457
458 if (strcmp (Token, "MethodObj"))
459 {
460 continue;
461 }
462
463 Token = strtok (NULL, METHOD_SEPARATORS); /* Arg count */
464 if (!Token)
465 {
466 continue;
467 }
468
469 /* Convert arg count string to an integer */
470
471 errno = 0;
472 ArgCount = strtoul (Token, NULL, 0);
473 if (errno)
474 {
475 fprintf (stderr, "Invalid argument count (%s)\n", Token);
476 continue;
477 }
478
479 if (ArgCount > 7)
480 {
481 fprintf (stderr, "Invalid argument count (%u)\n", ArgCount);
482 continue;
483 }
484
485 /* Add this external to the global list */
486
487 AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n",
488 AslGbl_ExternalRefFilename, ArgCount, MethodName);
489
490 AcpiDmAddPathToExternalList (MethodName, ACPI_TYPE_METHOD,
491 ArgCount, (ACPI_EXT_RESOLVED_REFERENCE | ACPI_EXT_ORIGIN_FROM_FILE));
492 ImportCount++;
493 }
494
495 if (!ImportCount)
496 {
497 fprintf (stderr,
498 "Did not find any external methods in reference file \"%s\"\n",
499 AslGbl_ExternalRefFilename);
500 }
501 else
502 {
503 /* Add the external(s) to the namespace */
504
505 AcpiDmAddExternalListToNamespace ();
506
507 AcpiOsPrintf ("%s: Imported %u external method definitions\n",
508 AslGbl_ExternalRefFilename, ImportCount);
509 }
510
511 fclose (ExternalRefFile);
512 }
513
514
515 /*******************************************************************************
516 *
517 * FUNCTION: AcpiDmAddOpToExternalList
518 *
519 * PARAMETERS: Op - Current parser Op
520 * Path - Internal (AML) path to the object
521 * Type - ACPI object type to be added
522 * Value - Arg count if adding a Method object
523 * Flags - To be passed to the external object
524 *
525 * RETURN: None
526 *
527 * DESCRIPTION: Insert a new name into the global list of Externals which
528 * will in turn be later emitted as an External() declaration
529 * in the disassembled output.
530 *
531 * This function handles the most common case where the referenced
532 * name is simply not found in the constructed namespace.
533 *
534 ******************************************************************************/
535
536 void
AcpiDmAddOpToExternalList(ACPI_PARSE_OBJECT * Op,char * Path,UINT8 Type,UINT32 Value,UINT16 Flags)537 AcpiDmAddOpToExternalList (
538 ACPI_PARSE_OBJECT *Op,
539 char *Path,
540 UINT8 Type,
541 UINT32 Value,
542 UINT16 Flags)
543 {
544 char *ExternalPath;
545 char *InternalPath = Path;
546 char *Temp;
547 ACPI_STATUS Status;
548
549
550 ACPI_FUNCTION_TRACE (DmAddOpToExternalList);
551
552
553 if (!Path)
554 {
555 return_VOID;
556 }
557
558 /* Remove a root backslash if present */
559
560 if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
561 {
562 Path++;
563 }
564
565 /* Externalize the pathname */
566
567 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
568 NULL, &ExternalPath);
569 if (ACPI_FAILURE (Status))
570 {
571 return_VOID;
572 }
573
574 /*
575 * Get the full pathname from the root if "Path" has one or more
576 * parent prefixes (^). Note: path will not contain a leading '\'.
577 */
578 if (*Path == (UINT8) AML_PARENT_PREFIX)
579 {
580 Temp = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
581
582 /* Set new external path */
583
584 ACPI_FREE (ExternalPath);
585 ExternalPath = Temp;
586 if (!Temp)
587 {
588 return_VOID;
589 }
590
591 /* Create the new internal pathname */
592
593 Flags |= ACPI_EXT_INTERNAL_PATH_ALLOCATED;
594 Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
595 if (ACPI_FAILURE (Status))
596 {
597 ACPI_FREE (ExternalPath);
598 return_VOID;
599 }
600 }
601
602 /* Create the new External() declaration node */
603
604 Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
605 Type, Value, Flags);
606 if (ACPI_FAILURE (Status))
607 {
608 ACPI_FREE (ExternalPath);
609 if (Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
610 {
611 ACPI_FREE (InternalPath);
612 }
613 }
614
615 return_VOID;
616 }
617
618
619 /*******************************************************************************
620 *
621 * FUNCTION: AcpiDmGetExternalAndInternalPath
622 *
623 * PARAMETERS: Node - Namespace node for object to be added
624 * ExternalPath - Will contain the external path of the node
625 * InternalPath - Will contain the internal path of the node
626 *
627 * RETURN: None
628 *
629 * DESCRIPTION: Get the External and Internal path from the given node.
630 *
631 ******************************************************************************/
632
633 static ACPI_STATUS
AcpiDmGetExternalAndInternalPath(ACPI_NAMESPACE_NODE * Node,char ** ExternalPath,char ** InternalPath)634 AcpiDmGetExternalAndInternalPath (
635 ACPI_NAMESPACE_NODE *Node,
636 char **ExternalPath,
637 char **InternalPath)
638 {
639 ACPI_STATUS Status;
640
641
642 if (!Node)
643 {
644 return (AE_BAD_PARAMETER);
645 }
646
647 /* Get the full external and internal pathnames to the node */
648
649 *ExternalPath = AcpiNsGetExternalPathname (Node);
650 if (!*ExternalPath)
651 {
652 return (AE_BAD_PATHNAME);
653 }
654
655 Status = AcpiNsInternalizeName (*ExternalPath, InternalPath);
656 if (ACPI_FAILURE (Status))
657 {
658 ACPI_FREE (*ExternalPath);
659 return (Status);
660 }
661
662 return (AE_OK);
663 }
664
665
666 /*******************************************************************************
667 *
668 * FUNCTION: AcpiDmRemoveRootPrefix
669 *
670 * PARAMETERS: Path - Remove Root prefix from this Path
671 *
672 * RETURN: None
673 *
674 * DESCRIPTION: Remove the root prefix character '\' from Path.
675 *
676 ******************************************************************************/
677
678 static ACPI_STATUS
AcpiDmRemoveRootPrefix(char ** Path)679 AcpiDmRemoveRootPrefix (
680 char **Path)
681 {
682 char *InputPath = *Path;
683
684
685 if ((*InputPath == AML_ROOT_PREFIX) && (InputPath[1]))
686 {
687 if (!memmove(InputPath, InputPath+1, strlen(InputPath)))
688 {
689 return (AE_ERROR);
690 }
691
692 *Path = InputPath;
693 }
694
695 return (AE_OK);
696 }
697
698
699 /*******************************************************************************
700 *
701 * FUNCTION: AcpiDmAddNodeToExternalList
702 *
703 * PARAMETERS: Node - Namespace node for object to be added
704 * Type - ACPI object type to be added
705 * Value - Arg count if adding a Method object
706 * Flags - To be passed to the external object
707 *
708 * RETURN: None
709 *
710 * DESCRIPTION: Insert a new name into the global list of Externals which
711 * will in turn be later emitted as an External() declaration
712 * in the disassembled output.
713 *
714 * This function handles the case where the referenced name has
715 * been found in the namespace, but the name originated in a
716 * table other than the one that is being disassembled (such
717 * as a table that is added via the iASL -e option).
718 *
719 ******************************************************************************/
720
721 void
AcpiDmAddNodeToExternalList(ACPI_NAMESPACE_NODE * Node,UINT8 Type,UINT32 Value,UINT16 Flags)722 AcpiDmAddNodeToExternalList (
723 ACPI_NAMESPACE_NODE *Node,
724 UINT8 Type,
725 UINT32 Value,
726 UINT16 Flags)
727 {
728 char *ExternalPath;
729 char *InternalPath;
730 ACPI_STATUS Status;
731
732
733 ACPI_FUNCTION_TRACE (DmAddNodeToExternalList);
734
735 /* Get the full external and internal pathnames to the node */
736
737 Status = AcpiDmGetExternalAndInternalPath (Node, &ExternalPath, &InternalPath);
738 if (ACPI_FAILURE (Status))
739 {
740 return_VOID;
741 }
742
743 /* Remove the root backslash */
744
745 Status = AcpiDmRemoveRootPrefix (&ExternalPath);
746 if (ACPI_FAILURE (Status))
747 {
748 ACPI_FREE (ExternalPath);
749 ACPI_FREE (InternalPath);
750 return_VOID;
751 }
752
753 /* Create the new External() declaration node */
754
755 Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, Type,
756 Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
757 if (ACPI_FAILURE (Status))
758 {
759 ACPI_FREE (ExternalPath);
760 ACPI_FREE (InternalPath);
761 }
762
763 return_VOID;
764 }
765
766
767 /*******************************************************************************
768 *
769 * FUNCTION: AcpiDmAddPathToExternalList
770 *
771 * PARAMETERS: Path - External name of the object to be added
772 * Type - ACPI object type to be added
773 * Value - Arg count if adding a Method object
774 * Flags - To be passed to the external object
775 *
776 * RETURN: None
777 *
778 * DESCRIPTION: Insert a new name into the global list of Externals which
779 * will in turn be later emitted as an External() declaration
780 * in the disassembled output.
781 *
782 * This function currently is used to add externals via a
783 * reference file (via the -fe iASL option).
784 *
785 ******************************************************************************/
786
787 static void
AcpiDmAddPathToExternalList(char * Path,UINT8 Type,UINT32 Value,UINT16 Flags)788 AcpiDmAddPathToExternalList (
789 char *Path,
790 UINT8 Type,
791 UINT32 Value,
792 UINT16 Flags)
793 {
794 char *InternalPath;
795 char *ExternalPath;
796 ACPI_STATUS Status;
797
798
799 ACPI_FUNCTION_TRACE (DmAddPathToExternalList);
800
801
802 if (!Path)
803 {
804 return_VOID;
805 }
806
807 /* Remove a root backslash if present */
808
809 if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
810 {
811 Path++;
812 }
813
814 /* Create the internal and external pathnames */
815
816 Status = AcpiNsInternalizeName (Path, &InternalPath);
817 if (ACPI_FAILURE (Status))
818 {
819 return_VOID;
820 }
821
822 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath,
823 NULL, &ExternalPath);
824 if (ACPI_FAILURE (Status))
825 {
826 ACPI_FREE (InternalPath);
827 return_VOID;
828 }
829
830 /* Create the new External() declaration node */
831
832 Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
833 Type, Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
834 if (ACPI_FAILURE (Status))
835 {
836 ACPI_FREE (ExternalPath);
837 ACPI_FREE (InternalPath);
838 }
839
840 return_VOID;
841 }
842
843
844 /*******************************************************************************
845 *
846 * FUNCTION: AcpiDmCreateNewExternal
847 *
848 * PARAMETERS: ExternalPath - External path to the object
849 * InternalPath - Internal (AML) path to the object
850 * Type - ACPI object type to be added
851 * Value - Arg count if adding a Method object
852 * Flags - To be passed to the external object
853 *
854 * RETURN: Status
855 *
856 * DESCRIPTION: Common low-level function to insert a new name into the global
857 * list of Externals which will in turn be later emitted as
858 * External() declarations in the disassembled output.
859 *
860 * Note: The external name should not include a root prefix
861 * (backslash). We do not want External() statements to contain
862 * a leading '\', as this prevents duplicate external statements
863 * of the form:
864 *
865 * External (\ABCD)
866 * External (ABCD)
867 *
868 * This would cause a compile time error when the disassembled
869 * output file is recompiled.
870 *
871 * There are two cases that are handled here. For both, we emit
872 * an External() statement:
873 * 1) The name was simply not found in the namespace.
874 * 2) The name was found, but it originated in a table other than
875 * the table that is being disassembled.
876 *
877 ******************************************************************************/
878
879 static ACPI_STATUS
AcpiDmCreateNewExternal(char * ExternalPath,char * InternalPath,UINT8 Type,UINT32 Value,UINT16 Flags)880 AcpiDmCreateNewExternal (
881 char *ExternalPath,
882 char *InternalPath,
883 UINT8 Type,
884 UINT32 Value,
885 UINT16 Flags)
886 {
887 ACPI_EXTERNAL_LIST *NewExternal;
888 ACPI_EXTERNAL_LIST *NextExternal;
889 ACPI_EXTERNAL_LIST *PrevExternal = NULL;
890
891
892 ACPI_FUNCTION_TRACE (DmCreateNewExternal);
893
894
895 /* Check all existing externals to ensure no duplicates */
896
897 NextExternal = AcpiGbl_ExternalList;
898 while (NextExternal)
899 {
900 /* Check for duplicates */
901
902 if (!strcmp (ExternalPath, NextExternal->Path))
903 {
904 /*
905 * If this external came from an External() opcode, we are
906 * finished with this one. (No need to check any further).
907 */
908 if (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_OPCODE)
909 {
910 return_ACPI_STATUS (AE_ALREADY_EXISTS);
911 }
912
913 /* Allow upgrade of type from ANY */
914
915 else if ((NextExternal->Type == ACPI_TYPE_ANY) &&
916 (Type != ACPI_TYPE_ANY))
917 {
918 NextExternal->Type = Type;
919 }
920
921 /* Update the argument count as necessary */
922
923 if (Value < NextExternal->Value)
924 {
925 NextExternal->Value = Value;
926 }
927
928 /* Update flags. */
929
930 NextExternal->Flags |= Flags;
931 NextExternal->Flags &= ~ACPI_EXT_INTERNAL_PATH_ALLOCATED;
932
933 return_ACPI_STATUS (AE_ALREADY_EXISTS);
934 }
935
936 NextExternal = NextExternal->Next;
937 }
938
939 /* Allocate and init a new External() descriptor */
940
941 NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
942 if (!NewExternal)
943 {
944 return_ACPI_STATUS (AE_NO_MEMORY);
945 }
946
947 ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
948 "Adding external reference node (%s) type [%s]\n",
949 ExternalPath, AcpiUtGetTypeName (Type)));
950
951 NewExternal->Flags = Flags;
952 NewExternal->Value = Value;
953 NewExternal->Path = ExternalPath;
954 NewExternal->Type = Type;
955 NewExternal->Length = (UINT16) strlen (ExternalPath);
956 NewExternal->InternalPath = InternalPath;
957
958 /* Link the new descriptor into the global list, alphabetically ordered */
959
960 NextExternal = AcpiGbl_ExternalList;
961 while (NextExternal)
962 {
963 if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
964 {
965 if (PrevExternal)
966 {
967 PrevExternal->Next = NewExternal;
968 }
969 else
970 {
971 AcpiGbl_ExternalList = NewExternal;
972 }
973
974 NewExternal->Next = NextExternal;
975 return_ACPI_STATUS (AE_OK);
976 }
977
978 PrevExternal = NextExternal;
979 NextExternal = NextExternal->Next;
980 }
981
982 if (PrevExternal)
983 {
984 PrevExternal->Next = NewExternal;
985 }
986 else
987 {
988 AcpiGbl_ExternalList = NewExternal;
989 }
990
991 return_ACPI_STATUS (AE_OK);
992 }
993
994
995 /*******************************************************************************
996 *
997 * FUNCTION: AcpiDmResolveExternal
998 *
999 * PARAMETERS: Path - Path of the external
1000 * Type - Type of the external
1001 * Node - Input node for AcpiNsLookup
1002 *
1003 * RETURN: Status
1004 *
1005 * DESCRIPTION: Resolve the external within the namespace by AcpiNsLookup.
1006 * If the returned node is an external and has the same type
1007 * we assume that it was either an existing external or a
1008 *
1009 ******************************************************************************/
1010
1011 static ACPI_STATUS
AcpiDmResolveExternal(char * Path,UINT8 Type,ACPI_NAMESPACE_NODE ** Node)1012 AcpiDmResolveExternal (
1013 char *Path,
1014 UINT8 Type,
1015 ACPI_NAMESPACE_NODE **Node)
1016 {
1017 ACPI_STATUS Status;
1018
1019
1020 Status = AcpiNsLookup (NULL, Path, Type,
1021 ACPI_IMODE_LOAD_PASS1,
1022 ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
1023 NULL, Node);
1024
1025 if (!Node)
1026 {
1027 ACPI_EXCEPTION ((AE_INFO, Status,
1028 "while adding external to namespace [%s]", Path));
1029 }
1030
1031 /* Note the asl code "external(a) external(a)" is acceptable ASL */
1032
1033 else if ((*Node)->Type == Type &&
1034 (*Node)->Flags & ANOBJ_IS_EXTERNAL)
1035 {
1036 return (AE_OK);
1037 }
1038 else
1039 {
1040 ACPI_EXCEPTION ((AE_INFO, AE_ERROR,
1041 "[%s] has conflicting declarations", Path));
1042 }
1043
1044 return (AE_ERROR);
1045 }
1046
1047
1048 /*******************************************************************************
1049 *
1050 * FUNCTION: AcpiDmCreateSubobjectForExternal
1051 *
1052 * PARAMETERS: Type - Type of the external
1053 * Node - Namespace node from AcpiNsLookup
1054 * ParamCount - Value to be used for Method
1055 *
1056 * RETURN: None
1057 *
1058 * DESCRIPTION: Add one external to the namespace. Allows external to be
1059 * "resolved".
1060 *
1061 ******************************************************************************/
1062
1063 void
AcpiDmCreateSubobjectForExternal(UINT8 Type,ACPI_NAMESPACE_NODE ** Node,UINT32 ParamCount)1064 AcpiDmCreateSubobjectForExternal (
1065 UINT8 Type,
1066 ACPI_NAMESPACE_NODE **Node,
1067 UINT32 ParamCount)
1068 {
1069 ACPI_OPERAND_OBJECT *ObjDesc;
1070
1071
1072 switch (Type)
1073 {
1074 case ACPI_TYPE_METHOD:
1075
1076 /* For methods, we need to save the argument count */
1077
1078 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
1079 ObjDesc->Method.ParamCount = (UINT8) ParamCount;
1080 (*Node)->Object = ObjDesc;
1081 break;
1082
1083 case ACPI_TYPE_REGION:
1084
1085 /* Regions require a region sub-object */
1086
1087 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
1088 ObjDesc->Region.Node = *Node;
1089 (*Node)->Object = ObjDesc;
1090 break;
1091
1092 default:
1093
1094 break;
1095 }
1096 }
1097
1098
1099 /*******************************************************************************
1100 *
1101 * FUNCTION: AcpiDmAddOneExternalToNamespace
1102 *
1103 * PARAMETERS: Path - External parse object
1104 * Type - Type of parse object
1105 * ParamCount - External method parameter count
1106 *
1107 * RETURN: None
1108 *
1109 * DESCRIPTION: Add one external to the namespace by resolvign the external
1110 * (by performing a namespace lookup) and annotating the resulting
1111 * namespace node with the appropriate information if the type
1112 * is ACPI_TYPE_REGION or ACPI_TYPE_METHOD.
1113 *
1114 ******************************************************************************/
1115
1116 void
AcpiDmAddOneExternalToNamespace(char * Path,UINT8 Type,UINT32 ParamCount)1117 AcpiDmAddOneExternalToNamespace (
1118 char *Path,
1119 UINT8 Type,
1120 UINT32 ParamCount)
1121 {
1122 ACPI_STATUS Status;
1123 ACPI_NAMESPACE_NODE *Node;
1124
1125
1126 Status = AcpiDmResolveExternal (Path, Type, &Node);
1127
1128 if (ACPI_FAILURE (Status))
1129 {
1130 return;
1131 }
1132
1133 AcpiDmCreateSubobjectForExternal (Type, &Node, ParamCount);
1134
1135 }
1136
1137
1138 /*******************************************************************************
1139 *
1140 * FUNCTION: AcpiDmAddExternalListToNamespace
1141 *
1142 * PARAMETERS: None
1143 *
1144 * RETURN: None
1145 *
1146 * DESCRIPTION: Add all externals within AcpiGbl_ExternalList to the namespace.
1147 * Allows externals to be "resolved".
1148 *
1149 ******************************************************************************/
1150
1151 void
AcpiDmAddExternalListToNamespace(void)1152 AcpiDmAddExternalListToNamespace (
1153 void)
1154 {
1155 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList;
1156
1157
1158 while (External)
1159 {
1160 AcpiDmAddOneExternalToNamespace (External->InternalPath,
1161 External->Type, External->Value);
1162 External = External->Next;
1163 }
1164 }
1165
1166
1167 /*******************************************************************************
1168 *
1169 * FUNCTION: AcpiDmGetUnresolvedExternalMethodCount
1170 *
1171 * PARAMETERS: None
1172 *
1173 * RETURN: The number of unresolved control method externals in the
1174 * external list
1175 *
1176 * DESCRIPTION: Return the number of unresolved external methods that have been
1177 * generated. If any unresolved control method externals have been
1178 * found, we must re-parse the entire definition block with the new
1179 * information (number of arguments for the methods.)
1180 * This is limitation of AML, we don't know the number of arguments
1181 * from the control method invocation itself.
1182 *
1183 * Note: resolved external control methods are external control
1184 * methods encoded with the AML_EXTERNAL_OP bytecode within the
1185 * AML being disassembled.
1186 *
1187 ******************************************************************************/
1188
1189 UINT32
AcpiDmGetUnresolvedExternalMethodCount(void)1190 AcpiDmGetUnresolvedExternalMethodCount (
1191 void)
1192 {
1193 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList;
1194 UINT32 Count = 0;
1195
1196
1197 while (External)
1198 {
1199 if (External->Type == ACPI_TYPE_METHOD &&
1200 !(External->Flags & ACPI_EXT_ORIGIN_FROM_OPCODE))
1201 {
1202 Count++;
1203 }
1204
1205 External = External->Next;
1206 }
1207
1208 return (Count);
1209 }
1210
1211
1212 /*******************************************************************************
1213 *
1214 * FUNCTION: AcpiDmClearExternalList
1215 *
1216 * PARAMETERS: None
1217 *
1218 * RETURN: None
1219 *
1220 * DESCRIPTION: Free the entire External info list
1221 *
1222 ******************************************************************************/
1223
1224 void
AcpiDmClearExternalList(void)1225 AcpiDmClearExternalList (
1226 void)
1227 {
1228 ACPI_EXTERNAL_LIST *NextExternal;
1229
1230
1231 while (AcpiGbl_ExternalList)
1232 {
1233 NextExternal = AcpiGbl_ExternalList->Next;
1234 ACPI_FREE (AcpiGbl_ExternalList->Path);
1235 ACPI_FREE (AcpiGbl_ExternalList);
1236 AcpiGbl_ExternalList = NextExternal;
1237 }
1238 }
1239
1240
1241 /*******************************************************************************
1242 *
1243 * FUNCTION: AcpiDmEmitExternals
1244 *
1245 * PARAMETERS: None
1246 *
1247 * RETURN: None
1248 *
1249 * DESCRIPTION: Emit an External() ASL statement for each of the externals in
1250 * the global external info list.
1251 *
1252 ******************************************************************************/
1253
1254 void
AcpiDmEmitExternals(void)1255 AcpiDmEmitExternals (
1256 void)
1257 {
1258 ACPI_EXTERNAL_LIST *NextExternal;
1259
1260
1261 if (!AcpiGbl_ExternalList)
1262 {
1263 return;
1264 }
1265
1266 /*
1267 * Determine the number of control methods in the external list, and
1268 * also how many of those externals were resolved via the namespace.
1269 */
1270 NextExternal = AcpiGbl_ExternalList;
1271 while (NextExternal)
1272 {
1273 if (NextExternal->Type == ACPI_TYPE_METHOD)
1274 {
1275 AcpiGbl_NumExternalMethods++;
1276 if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)
1277 {
1278 AcpiGbl_ResolvedExternalMethods++;
1279 }
1280 }
1281
1282 NextExternal = NextExternal->Next;
1283 }
1284
1285 /* Check if any control methods were unresolved */
1286
1287 AcpiDmUnresolvedWarning (1);
1288
1289 if (AslGbl_ExternalRefFilename)
1290 {
1291 AcpiOsPrintf (
1292 " /*\n * External declarations were imported from\n"
1293 " * a reference file -- %s\n */\n\n",
1294 AslGbl_ExternalRefFilename);
1295 }
1296
1297 /*
1298 * Walk and emit the list of externals found during the AML parsing
1299 */
1300 while (AcpiGbl_ExternalList)
1301 {
1302 if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED))
1303 {
1304 AcpiOsPrintf (" External (%s%s)",
1305 AcpiGbl_ExternalList->Path,
1306 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
1307
1308 /* Check for "unresolved" method reference */
1309
1310 if ((AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) &&
1311 (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_RESOLVED_REFERENCE)))
1312 {
1313 AcpiOsPrintf (" // Warning: Unknown method, "
1314 "guessing %u arguments",
1315 AcpiGbl_ExternalList->Value);
1316 }
1317
1318 /* Check for external from a external references file */
1319
1320 else if (AcpiGbl_ExternalList->Flags & ACPI_EXT_ORIGIN_FROM_FILE)
1321 {
1322 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1323 {
1324 AcpiOsPrintf (" // %u Arguments",
1325 AcpiGbl_ExternalList->Value);
1326 }
1327
1328 AcpiOsPrintf (" // From external reference file");
1329 }
1330
1331 /* This is the normal external case */
1332
1333 else
1334 {
1335 /* For methods, add a comment with the number of arguments */
1336
1337 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1338 {
1339 AcpiOsPrintf (" // %u Arguments",
1340 AcpiGbl_ExternalList->Value);
1341 }
1342 }
1343
1344 if (AcpiGbl_ExternalList->Flags &= ACPI_EXT_CONFLICTING_DECLARATION)
1345 {
1346 AcpiOsPrintf ("%s", ExternalConflictMessage);
1347 AcpiDmConflictingDeclaration (AcpiGbl_ExternalList->Path);
1348 }
1349 AcpiOsPrintf ("\n");
1350 }
1351
1352 /* Free this external info block and move on to next external */
1353
1354 NextExternal = AcpiGbl_ExternalList->Next;
1355 if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
1356 {
1357 ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
1358 }
1359
1360 ACPI_FREE (AcpiGbl_ExternalList->Path);
1361 ACPI_FREE (AcpiGbl_ExternalList);
1362 AcpiGbl_ExternalList = NextExternal;
1363 }
1364
1365 AcpiOsPrintf ("\n");
1366 }
1367
1368
1369 /*******************************************************************************
1370 *
1371 * FUNCTION: AcpiDmMarkExternalConflict
1372 *
1373 * PARAMETERS: Path - Namepath to search
1374 *
1375 * RETURN: ExternalList
1376 *
1377 * DESCRIPTION: Search the AcpiGbl_ExternalList for a matching path
1378 *
1379 ******************************************************************************/
1380
1381 void
AcpiDmMarkExternalConflict(ACPI_NAMESPACE_NODE * Node)1382 AcpiDmMarkExternalConflict (
1383 ACPI_NAMESPACE_NODE *Node)
1384 {
1385 ACPI_EXTERNAL_LIST *ExternalList = AcpiGbl_ExternalList;
1386 char *ExternalPath;
1387 char *InternalPath;
1388 char *Temp;
1389 ACPI_STATUS Status;
1390
1391
1392 ACPI_FUNCTION_TRACE (DmMarkExternalConflict);
1393
1394
1395 if (Node->Flags & ANOBJ_IS_EXTERNAL)
1396 {
1397 return_VOID;
1398 }
1399
1400 /* Get the full external and internal pathnames to the node */
1401
1402 Status = AcpiDmGetExternalAndInternalPath (Node,
1403 &ExternalPath, &InternalPath);
1404 if (ACPI_FAILURE (Status))
1405 {
1406 return_VOID;
1407 }
1408
1409 /* Remove the root backslash */
1410
1411 Status = AcpiDmRemoveRootPrefix (&InternalPath);
1412 if (ACPI_FAILURE (Status))
1413 {
1414 ACPI_FREE (InternalPath);
1415 ACPI_FREE (ExternalPath);
1416 return_VOID;
1417 }
1418
1419 while (ExternalList)
1420 {
1421 Temp = ExternalList->InternalPath;
1422 if ((*ExternalList->InternalPath == AML_ROOT_PREFIX) &&
1423 (ExternalList->InternalPath[1]))
1424 {
1425 Temp++;
1426 }
1427
1428 if (!strcmp (ExternalList->InternalPath, InternalPath))
1429 {
1430 ExternalList->Flags |= ACPI_EXT_CONFLICTING_DECLARATION;
1431 }
1432 ExternalList = ExternalList->Next;
1433 }
1434
1435 ACPI_FREE (InternalPath);
1436 ACPI_FREE (ExternalPath);
1437
1438 return_VOID;
1439 }
1440
1441
1442 /*******************************************************************************
1443 *
1444 * FUNCTION: AcpiDmConflictingDeclaration
1445 *
1446 * PARAMETERS: Path - Path with conflicting declaration
1447 *
1448 * RETURN: None
1449 *
1450 * DESCRIPTION: Emit a warning when printing conflicting ASL external
1451 * declarations.
1452 *
1453 ******************************************************************************/
1454
1455 static void
AcpiDmConflictingDeclaration(char * Path)1456 AcpiDmConflictingDeclaration (
1457 char *Path)
1458 {
1459 fprintf (stderr,
1460 " Warning - Emitting ASL code \"External (%s)\"\n"
1461 " This is a conflicting declaration with some "
1462 "other declaration within the ASL code.\n"
1463 " This external declaration may need to be "
1464 "deleted in order to recompile the dsl file.\n\n",
1465 Path);
1466 }
1467
1468
1469 /*******************************************************************************
1470 *
1471 * FUNCTION: AcpiDmEmitExternal
1472 *
1473 * PARAMETERS: Op External Parse Object
1474 *
1475 * RETURN: None
1476 *
1477 * DESCRIPTION: Emit an External() ASL statement for the current External
1478 * parse object. Note: External Ops are named types so the
1479 * namepath is contained within NameOp->Name.Path.
1480 *
1481 ******************************************************************************/
1482
1483 void
AcpiDmEmitExternal(ACPI_PARSE_OBJECT * NameOp,ACPI_PARSE_OBJECT * TypeOp)1484 AcpiDmEmitExternal (
1485 ACPI_PARSE_OBJECT *NameOp,
1486 ACPI_PARSE_OBJECT *TypeOp)
1487 {
1488 AcpiOsPrintf ("External (");
1489 AcpiDmNamestring (NameOp->Named.Path);
1490 AcpiOsPrintf ("%s)",
1491 AcpiDmGetObjectTypeName ((ACPI_OBJECT_TYPE) TypeOp->Common.Value.Integer));
1492 AcpiDmCheckForExternalConflict (NameOp->Named.Path);
1493 AcpiOsPrintf ("\n");
1494 }
1495
1496
1497 /*******************************************************************************
1498 *
1499 * FUNCTION: AcpiDmCheckForExternalConflict
1500 *
1501 * PARAMETERS: Path - Path to check
1502 *
1503 * RETURN: None
1504 *
1505 * DESCRIPTION: Search the External List to see if the input Path has a
1506 * conflicting declaration.
1507 *
1508 ******************************************************************************/
1509
1510 static void
AcpiDmCheckForExternalConflict(char * Path)1511 AcpiDmCheckForExternalConflict (
1512 char *Path)
1513 {
1514 ACPI_EXTERNAL_LIST *ExternalList = AcpiGbl_ExternalList;
1515 char *ListItemPath;
1516 char *InputPath;
1517
1518
1519 if (!Path)
1520 {
1521 return;
1522 }
1523
1524 /* Move past the root prefix '\' */
1525
1526 InputPath = Path;
1527 if ((*InputPath == AML_ROOT_PREFIX) && InputPath[1])
1528 {
1529 InputPath++;
1530 }
1531
1532 while (ExternalList)
1533 {
1534 ListItemPath = ExternalList->Path;
1535 if (ListItemPath)
1536 {
1537 /* Move past the root prefix '\' */
1538
1539 if ((*ListItemPath == AML_ROOT_PREFIX) &&
1540 ListItemPath[1])
1541 {
1542 ListItemPath++;
1543 }
1544
1545 if (!strcmp (ListItemPath, InputPath) &&
1546 (ExternalList->Flags & ACPI_EXT_CONFLICTING_DECLARATION))
1547 {
1548 AcpiOsPrintf ("%s", ExternalConflictMessage);
1549 AcpiDmConflictingDeclaration (Path);
1550
1551 return;
1552 }
1553 }
1554 ExternalList = ExternalList->Next;
1555 }
1556 }
1557 /*******************************************************************************
1558 *
1559 * FUNCTION: AcpiDmUnresolvedWarning
1560 *
1561 * PARAMETERS: Type - Where to output the warning.
1562 * 0 means write to stderr
1563 * 1 means write to AcpiOsPrintf
1564 *
1565 * RETURN: None
1566 *
1567 * DESCRIPTION: Issue warning message if there are unresolved external control
1568 * methods within the disassembly.
1569 *
1570 ******************************************************************************/
1571
1572 /*
1573 Summary of the external control method problem:
1574
1575 When the -e option is used with disassembly, the various SSDTs are simply
1576 loaded into a global namespace for the disassembler to use in order to
1577 resolve control method references (invocations).
1578
1579 The disassembler tracks any such references, and will emit an External()
1580 statement for these types of methods, with the proper number of arguments .
1581
1582 Without the SSDTs, the AML does not contain enough information to properly
1583 disassemble the control method invocation -- because the disassembler does
1584 not know how many arguments to parse.
1585
1586 An example: Assume we have two control methods. ABCD has one argument, and
1587 EFGH has zero arguments. Further, we have two additional control methods
1588 that invoke ABCD and EFGH, named T1 and T2:
1589
1590 Method (ABCD, 1)
1591 {
1592 }
1593 Method (EFGH, 0)
1594 {
1595 }
1596 Method (T1)
1597 {
1598 ABCD (Add (2, 7, Local0))
1599 }
1600 Method (T2)
1601 {
1602 EFGH ()
1603 Add (2, 7, Local0)
1604 }
1605
1606 Here is the AML code that is generated for T1 and T2:
1607
1608 185: Method (T1)
1609
1610 0000034C: 14 10 54 31 5F 5F 00 ... "..T1__."
1611
1612 186: {
1613 187: ABCD (Add (2, 7, Local0))
1614
1615 00000353: 41 42 43 44 ............ "ABCD"
1616 00000357: 72 0A 02 0A 07 60 ...... "r....`"
1617
1618 188: }
1619
1620 190: Method (T2)
1621
1622 0000035D: 14 10 54 32 5F 5F 00 ... "..T2__."
1623
1624 191: {
1625 192: EFGH ()
1626
1627 00000364: 45 46 47 48 ............ "EFGH"
1628
1629 193: Add (2, 7, Local0)
1630
1631 00000368: 72 0A 02 0A 07 60 ...... "r....`"
1632 194: }
1633
1634 Note that the AML code for T1 and T2 is essentially identical. When
1635 disassembling this code, the methods ABCD and EFGH must be known to the
1636 disassembler, otherwise it does not know how to handle the method invocations.
1637
1638 In other words, if ABCD and EFGH are actually external control methods
1639 appearing in an SSDT, the disassembler does not know what to do unless
1640 the owning SSDT has been loaded via the -e option.
1641 */
1642
1643 static char ExternalWarningPart1[600];
1644 static char ExternalWarningPart2[400];
1645 static char ExternalWarningPart3[400];
1646 static char ExternalWarningPart4[200];
1647
1648 void
AcpiDmUnresolvedWarning(UINT8 Type)1649 AcpiDmUnresolvedWarning (
1650 UINT8 Type)
1651 {
1652 char *Format;
1653 char Pad[] = " *";
1654 char NoPad[] = "";
1655
1656
1657 if (!AcpiGbl_NumExternalMethods)
1658 {
1659 return;
1660 }
1661
1662 if (AcpiGbl_NumExternalMethods == AcpiGbl_ResolvedExternalMethods)
1663 {
1664 return;
1665 }
1666
1667 Format = Type ? Pad : NoPad;
1668
1669 sprintf (ExternalWarningPart1,
1670 "%s iASL Warning: There %s %u external control method%s found during\n"
1671 "%s disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1672 "%s ACPI tables may be required to properly disassemble the code. This\n"
1673 "%s resulting disassembler output file may not compile because the\n"
1674 "%s disassembler did not know how many arguments to assign to the\n"
1675 "%s unresolved methods. Note: SSDTs can be dynamically loaded at\n"
1676 "%s runtime and may or may not be available via the host OS.\n",
1677 Format, (AcpiGbl_NumExternalMethods != 1 ? "were" : "was"),
1678 AcpiGbl_NumExternalMethods, (AcpiGbl_NumExternalMethods != 1 ? "s" : ""),
1679 Format, AcpiGbl_ResolvedExternalMethods,
1680 (AcpiGbl_ResolvedExternalMethods != 1 ? "were" : "was"),
1681 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods),
1682 Format, Format, Format, Format, Format);
1683
1684 sprintf (ExternalWarningPart2,
1685 "%s To specify the tables needed to resolve external control method\n"
1686 "%s references, the -e option can be used to specify the filenames.\n"
1687 "%s Example iASL invocations:\n"
1688 "%s iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1689 "%s iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1690 "%s iasl -e ssdt*.aml -d dsdt.aml\n",
1691 Format, Format, Format, Format, Format, Format);
1692
1693 sprintf (ExternalWarningPart3,
1694 "%s In addition, the -fe option can be used to specify a file containing\n"
1695 "%s control method external declarations with the associated method\n"
1696 "%s argument counts. Each line of the file must be of the form:\n"
1697 "%s External (<method pathname>, MethodObj, <argument count>)\n"
1698 "%s Invocation:\n"
1699 "%s iasl -fe refs.txt -d dsdt.aml\n",
1700 Format, Format, Format, Format, Format, Format);
1701
1702 sprintf (ExternalWarningPart4,
1703 "%s The following methods were unresolved and many not compile properly\n"
1704 "%s because the disassembler had to guess at the number of arguments\n"
1705 "%s required for each:\n",
1706 Format, Format, Format);
1707
1708 if (Type)
1709 {
1710 if (!AcpiGbl_ExternalFileList)
1711 {
1712 /* The -e option was not specified */
1713
1714 AcpiOsPrintf (" /*\n%s *\n%s *\n%s *\n%s */\n",
1715 ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3,
1716 ExternalWarningPart4);
1717 }
1718 else
1719 {
1720 /* The -e option was specified, but there are still some unresolved externals */
1721
1722 AcpiOsPrintf (" /*\n%s *\n%s *\n%s */\n",
1723 ExternalWarningPart1, ExternalWarningPart3, ExternalWarningPart4);
1724 }
1725 }
1726 else
1727 {
1728 if (!AcpiGbl_ExternalFileList)
1729 {
1730 /* The -e option was not specified */
1731
1732 fprintf (stderr, "\n%s\n%s\n%s\n",
1733 ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3);
1734 }
1735 else
1736 {
1737 /* The -e option was specified, but there are still some unresolved externals */
1738
1739 fprintf (stderr, "\n%s\n%s\n",
1740 ExternalWarningPart1, ExternalWarningPart3);
1741 }
1742 }
1743 }
1744