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