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