dmextern.c revision 1.1.1.4.2.6 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 "acpi.h"
45 #include "accommon.h"
46 #include "amlcode.h"
47 #include "acnamesp.h"
48 #include "acdisasm.h"
49 #include "aslcompiler.h"
50 #include <stdio.h>
51 #include <errno.h>
52
53
54 /*
55 * This module is used for application-level code (iASL disassembler) only.
56 *
57 * It contains the code to create and emit any necessary External() ASL
58 * statements for the module being disassembled.
59 */
60 #define _COMPONENT ACPI_CA_DISASSEMBLER
61 ACPI_MODULE_NAME ("dmextern")
62
63
64 /*
65 * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL
66 * ObjectTypeKeyword. Used to generate typed external declarations
67 */
68 static const char *AcpiGbl_DmTypeNames[] =
69 {
70 /* 00 */ ", UnknownObj", /* Type ANY */
71 /* 01 */ ", IntObj",
72 /* 02 */ ", StrObj",
73 /* 03 */ ", BuffObj",
74 /* 04 */ ", PkgObj",
75 /* 05 */ ", FieldUnitObj",
76 /* 06 */ ", DeviceObj",
77 /* 07 */ ", EventObj",
78 /* 08 */ ", MethodObj",
79 /* 09 */ ", MutexObj",
80 /* 10 */ ", OpRegionObj",
81 /* 11 */ ", PowerResObj",
82 /* 12 */ ", ProcessorObj",
83 /* 13 */ ", ThermalZoneObj",
84 /* 14 */ ", BuffFieldObj",
85 /* 15 */ ", DDBHandleObj",
86 /* 16 */ "", /* Debug object */
87 /* 17 */ ", FieldUnitObj",
88 /* 18 */ ", FieldUnitObj",
89 /* 19 */ ", FieldUnitObj"
90 };
91
92 #define METHOD_SEPARATORS " \t,()\n"
93
94
95 /* Local prototypes */
96
97 static const char *
98 AcpiDmGetObjectTypeName (
99 ACPI_OBJECT_TYPE Type);
100
101 static char *
102 AcpiDmNormalizeParentPrefix (
103 ACPI_PARSE_OBJECT *Op,
104 char *Path);
105
106 static void
107 AcpiDmAddPathToExternalList (
108 char *Path,
109 UINT8 Type,
110 UINT32 Value,
111 UINT16 Flags);
112
113 static ACPI_STATUS
114 AcpiDmCreateNewExternal (
115 char *ExternalPath,
116 char *InternalPath,
117 UINT8 Type,
118 UINT32 Value,
119 UINT16 Flags);
120
121
122 /*******************************************************************************
123 *
124 * FUNCTION: AcpiDmGetObjectTypeName
125 *
126 * PARAMETERS: Type - An ACPI_OBJECT_TYPE
127 *
128 * RETURN: Pointer to a string
129 *
130 * DESCRIPTION: Map an object type to the ASL object type string.
131 *
132 ******************************************************************************/
133
134 static const char *
135 AcpiDmGetObjectTypeName (
136 ACPI_OBJECT_TYPE Type)
137 {
138
139 if (Type == ACPI_TYPE_LOCAL_SCOPE)
140 {
141 Type = ACPI_TYPE_DEVICE;
142 }
143 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: AcpiDmEmitExternal
1169 *
1170 * PARAMETERS: Op External Parse Object
1171 *
1172 * RETURN: None
1173 *
1174 * DESCRIPTION: Emit an External() ASL statement for the current External
1175 * parse object
1176 *
1177 ******************************************************************************/
1178
1179 void
1180 AcpiDmEmitExternal (
1181 ACPI_PARSE_OBJECT *NameOp,
1182 ACPI_PARSE_OBJECT *TypeOp)
1183 {
1184 AcpiOsPrintf ("External (");
1185 AcpiDmNamestring (NameOp->Common.Value.Name);
1186 AcpiOsPrintf ("%s)\n",
1187 AcpiDmGetObjectTypeName ((ACPI_OBJECT_TYPE) TypeOp->Common.Value.Integer));
1188 }
1189
1190
1191 /*******************************************************************************
1192 *
1193 * FUNCTION: AcpiDmUnresolvedWarning
1194 *
1195 * PARAMETERS: Type - Where to output the warning.
1196 * 0 means write to stderr
1197 * 1 means write to AcpiOsPrintf
1198 *
1199 * RETURN: None
1200 *
1201 * DESCRIPTION: Issue warning message if there are unresolved external control
1202 * methods within the disassembly.
1203 *
1204 ******************************************************************************/
1205
1206 #if 0
1207 Summary of the external control method problem:
1208
1209 When the -e option is used with disassembly, the various SSDTs are simply
1210 loaded into a global namespace for the disassembler to use in order to
1211 resolve control method references (invocations).
1212
1213 The disassembler tracks any such references, and will emit an External()
1214 statement for these types of methods, with the proper number of arguments .
1215
1216 Without the SSDTs, the AML does not contain enough information to properly
1217 disassemble the control method invocation -- because the disassembler does
1218 not know how many arguments to parse.
1219
1220 An example: Assume we have two control methods. ABCD has one argument, and
1221 EFGH has zero arguments. Further, we have two additional control methods
1222 that invoke ABCD and EFGH, named T1 and T2:
1223
1224 Method (ABCD, 1)
1225 {
1226 }
1227 Method (EFGH, 0)
1228 {
1229 }
1230 Method (T1)
1231 {
1232 ABCD (Add (2, 7, Local0))
1233 }
1234 Method (T2)
1235 {
1236 EFGH ()
1237 Add (2, 7, Local0)
1238 }
1239
1240 Here is the AML code that is generated for T1 and T2:
1241
1242 185: Method (T1)
1243
1244 0000034C: 14 10 54 31 5F 5F 00 ... "..T1__."
1245
1246 186: {
1247 187: ABCD (Add (2, 7, Local0))
1248
1249 00000353: 41 42 43 44 ............ "ABCD"
1250 00000357: 72 0A 02 0A 07 60 ...... "r....`"
1251
1252 188: }
1253
1254 190: Method (T2)
1255
1256 0000035D: 14 10 54 32 5F 5F 00 ... "..T2__."
1257
1258 191: {
1259 192: EFGH ()
1260
1261 00000364: 45 46 47 48 ............ "EFGH"
1262
1263 193: Add (2, 7, Local0)
1264
1265 00000368: 72 0A 02 0A 07 60 ...... "r....`"
1266 194: }
1267
1268 Note that the AML code for T1 and T2 is essentially identical. When
1269 disassembling this code, the methods ABCD and EFGH must be known to the
1270 disassembler, otherwise it does not know how to handle the method invocations.
1271
1272 In other words, if ABCD and EFGH are actually external control methods
1273 appearing in an SSDT, the disassembler does not know what to do unless
1274 the owning SSDT has been loaded via the -e option.
1275 #endif
1276
1277 static char ExternalWarningPart1[600];
1278 static char ExternalWarningPart2[400];
1279 static char ExternalWarningPart3[400];
1280 static char ExternalWarningPart4[200];
1281
1282 void
1283 AcpiDmUnresolvedWarning (
1284 UINT8 Type)
1285 {
1286 char *Format;
1287 char Pad[] = " *";
1288 char NoPad[] = "";
1289
1290
1291 if (!AcpiGbl_NumExternalMethods)
1292 {
1293 return;
1294 }
1295
1296 if (AcpiGbl_NumExternalMethods == AcpiGbl_ResolvedExternalMethods)
1297 {
1298 return;
1299 }
1300
1301 Format = Type ? Pad : NoPad;
1302
1303 sprintf (ExternalWarningPart1,
1304 "%s iASL Warning: There %s %u external control method%s found during\n"
1305 "%s disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1306 "%s ACPI tables may be required to properly disassemble the code. This\n"
1307 "%s resulting disassembler output file may not compile because the\n"
1308 "%s disassembler did not know how many arguments to assign to the\n"
1309 "%s unresolved methods. Note: SSDTs can be dynamically loaded at\n"
1310 "%s runtime and may or may not be available via the host OS.\n",
1311 Format, (AcpiGbl_NumExternalMethods != 1 ? "were" : "was"),
1312 AcpiGbl_NumExternalMethods, (AcpiGbl_NumExternalMethods != 1 ? "s" : ""),
1313 Format, AcpiGbl_ResolvedExternalMethods,
1314 (AcpiGbl_ResolvedExternalMethods != 1 ? "were" : "was"),
1315 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods),
1316 Format, Format, Format, Format, Format);
1317
1318 sprintf (ExternalWarningPart2,
1319 "%s To specify the tables needed to resolve external control method\n"
1320 "%s references, the -e option can be used to specify the filenames.\n"
1321 "%s Example iASL invocations:\n"
1322 "%s iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1323 "%s iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1324 "%s iasl -e ssdt*.aml -d dsdt.aml\n",
1325 Format, Format, Format, Format, Format, Format);
1326
1327 sprintf (ExternalWarningPart3,
1328 "%s In addition, the -fe option can be used to specify a file containing\n"
1329 "%s control method external declarations with the associated method\n"
1330 "%s argument counts. Each line of the file must be of the form:\n"
1331 "%s External (<method pathname>, MethodObj, <argument count>)\n"
1332 "%s Invocation:\n"
1333 "%s iasl -fe refs.txt -d dsdt.aml\n",
1334 Format, Format, Format, Format, Format, Format);
1335
1336 sprintf (ExternalWarningPart4,
1337 "%s The following methods were unresolved and many not compile properly\n"
1338 "%s because the disassembler had to guess at the number of arguments\n"
1339 "%s required for each:\n",
1340 Format, Format, Format);
1341
1342 if (Type)
1343 {
1344 if (!AcpiGbl_ExternalFileList)
1345 {
1346 /* The -e option was not specified */
1347
1348 AcpiOsPrintf (" /*\n%s *\n%s *\n%s *\n%s */\n",
1349 ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3,
1350 ExternalWarningPart4);
1351 }
1352 else
1353 {
1354 /* The -e option was specified, but there are still some unresolved externals */
1355
1356 AcpiOsPrintf (" /*\n%s *\n%s *\n%s */\n",
1357 ExternalWarningPart1, ExternalWarningPart3, ExternalWarningPart4);
1358 }
1359 }
1360 else
1361 {
1362 if (!AcpiGbl_ExternalFileList)
1363 {
1364 /* The -e option was not specified */
1365
1366 fprintf (stderr, "\n%s\n%s\n%s\n",
1367 ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3);
1368 }
1369 else
1370 {
1371 /* The -e option was specified, but there are still some unresolved externals */
1372
1373 fprintf (stderr, "\n%s\n%s\n",
1374 ExternalWarningPart1, ExternalWarningPart3);
1375 }
1376 }
1377 }
1378