3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 This module contains functionality to keep track of files destined for
19 multiple firmware volues. It saves them up, and when told to, dumps the
20 file names out to some files used as input to other utilities that
21 actually generate the FVs.
25 #include <windows.h> // for max_path definition
28 #include <stdlib.h> // for malloc()
33 #define FV_INF_DIR "FV_INF_DIR" // symbol for where we create the FV INF file
34 #define FV_FILENAME "FV_FILENAME" // symbol for the current FV.INF filename
35 #define EFI_BASE_ADDRESS "EFI_BASE_ADDRESS"
36 #define DEFAULT_FV_INF_DIR "FV" // default dir for where we create the FV INF file
37 #define DEFAULT_FV_DIR "$(BUILD_DIR)" // where the FV file comes from
42 } COMP_TYPE_EXTENSION
;
45 // Use a linked list of these to keep track of all the FV names used
47 typedef struct _FV_LIST
{
48 struct _FV_LIST
*Next
;
49 char FVFileName
[MAX_PATH
];
50 char BaseAddress
[MAX_LINE_LEN
];
51 SMART_FILE
*FVFilePtr
;
52 SMART_FILE
*AprioriFilePtr
;
54 int ComponentsInstance
; // highest [components.n] section with a file for this FV
58 // Use a linked list of these to keep track of all FFS files built. When
59 // we're done, we turn the info into the FV INF files used to build the
62 typedef struct _FILE_LIST
{
63 struct _FILE_LIST
*Next
;
66 char *FVs
; // from FV=x,y,z
67 char *BaseName
; // only needed for duplicate basename check
68 char *Processor
; // only needed for duplicate basename check
69 char Apriori
[100]; // of format "FVRecovery:1,FVMain:2" from APRIORI define
70 char *Guid
; // guid string
71 int ComponentsInstance
; // which [components.n] section it's in
74 typedef struct _LINKED_LIST
{
75 struct _LINKED_LIST
*Next
;
79 static FILE_LIST
*mFileList
;
80 static FILE_LIST
*mLastFile
;
81 static char *mXRefFileName
= NULL
;
82 static FV_LIST
*mNonFfsFVList
= NULL
;
85 // Whenever an FV name is referenced, then add it to our list of known
88 static FV_LIST
*mFVList
= NULL
;
89 static FV_LIST
*mFVListLast
= NULL
;
92 // We use this list so that from a given component type, we can determine
93 // the name of the file on disk. For example, if we're given a file's
94 // guid and base name, and we know it's a "bs_driver", then we can look
95 // up "bs_driver" in this array and know that the file (after it's built)
96 // name is GUID-BASENAME.DXE
98 static const COMP_TYPE_EXTENSION mCompTypeExtension
[] = {
156 "combined_peim_driver",
188 int ComponentsInstance
211 while (*Name
&& isspace (*Name
)) {
219 // Find the end of the name. Either space or a '='.
221 for (Value
= Name
; *Value
&& !isspace (*Value
) && (*Value
!= '='); Value
++)
230 while (*Value
&& (*Value
!= '=')) {
238 // Now truncate the name
242 if (_stricmp (Name
, EFI_BASE_ADDRESS
) != 0) {
248 // Skip over the = and then any spaces
251 while (*Value
&& isspace (*Value
)) {
255 // Find end of string, checking for quoted string
257 if (*Value
== '\"') {
259 for (Cptr
= Value
; *Cptr
&& *Cptr
!= '\"'; Cptr
++)
262 for (Cptr
= Value
; *Cptr
&& !isspace (*Cptr
); Cptr
++)
266 // Null terminate the value string
270 strcpy (BaseAddress
, Value
);
273 return STATUS_SUCCESS
;
281 int ComponentsInstance
,
292 Add a file to the list of files in one or more firmware volumes.
296 Name - $(FILE_GUID)-$(BASE_NAME), or filename
297 ComponentType - type of component being added. Required so we know the
298 resultant file name after it has been built
299 FVs - string of commma-separated FVs that the given file is
300 to be added to. For example, FVs="FV0001,FV0002"
301 FFSExt - FFS filename extension of the file after it has been built.
302 This is passed in to us in case we don't know the default
303 filename extension based on the component type.
304 Processor - the target processor which the FV is being built for
305 Apriori - pointer to the definition of APRIORI. For example APRIORI="FvRecovery:1,FvMain:4"
309 STATUS_SUCCESS if successful
314 char FileName
[MAX_PATH
];
319 // If they provided a filename extension for this type of file, then use it.
320 // If they did not provide a filename extension, search our list for a
321 // matching component type and use the extension appropriate for this
324 if (FFSExt
== NULL
) {
326 // They didn't give us a filename extension. Figure it out from the
329 for (i
= 0; mCompTypeExtension
[i
].ComponentType
!= NULL
; i
++) {
330 if (_stricmp (ComponentType
, mCompTypeExtension
[i
].ComponentType
) == 0) {
331 FFSExt
= mCompTypeExtension
[i
].Extension
;
336 // If we don't know the file extension, then error out. Just means
337 // the need to define "FFS_EXT = raw" in the component INF file.
339 if (mCompTypeExtension
[i
].ComponentType
== NULL
) {
345 "unknown component type - must define FFS_EXT for built filename extension in component INF file"
351 // We now have all the parts to the FFS filename. Prepend the path to it if
352 // it's not a full pathname.
353 // See if they overrode the default base directory for the FV files.
355 if (!IsAbsolutePath (Name
)) {
356 Sym
= GetSymbolValue (FV_DIR
);
358 Sym
= DEFAULT_FV_DIR
;
361 // Create the file path. Something like $(BUILD_DIR)\$(PROCESSOR)\$(GUID)-$(BASE_NAME).ext
362 // If the extension is non-zero length, then make sure there's a dot in it.
364 if ((strlen (FFSExt
) > 0) && (FFSExt
[0] != '.')) {
365 sprintf (Str
, "%s\\%s\\%s.%s", Sym
, Processor
, Name
, FFSExt
);
367 sprintf (Str
, "%s\\%s\\%s%s", Sym
, Processor
, Name
, FFSExt
);
370 ExpandSymbols (Str
, FileName
, sizeof (FileName
), EXPANDMODE_NO_UNDEFS
);
372 strcpy (FileName
, Name
);
375 // Traverse the list of files we have so far and make sure we don't have
376 // any duplicate basenames. If the base name and processor match, then we'll
377 // have build issues, so don't allow it. We also don't allow the same file GUID
378 // in the same FV which will cause boot time error if we allow this.
381 while (Ptr
!= NULL
) {
382 if ((Ptr
->BaseName
!= NULL
) && (BaseName
!= NULL
) && (_stricmp (BaseName
, Ptr
->BaseName
) == 0)) {
383 if ((Ptr
->Processor
!= NULL
) && (Processor
!= NULL
) && (_stricmp (Processor
, Ptr
->Processor
) == 0)) {
384 Error (NULL
, 0, 0, BaseName
, "duplicate base name specified");
389 if ((Ptr
->Guid
!= NULL
) && (Guid
!= NULL
) && (_stricmp (Guid
, Ptr
->Guid
) == 0)) {
390 if ((Ptr
->FVs
!= NULL
) && (FVs
!= NULL
) && (InSameFv (FVs
, Ptr
->FVs
))) {
391 Error (NULL
, 0, 0, Guid
, "duplicate Guid specified in the same FV for %s and %s",
392 (Ptr
->BaseName
==NULL
)?"Unknown":Ptr
->BaseName
,
393 (BaseName
==NULL
)?"Unknown":BaseName
);
401 // Allocate a new structure so we can add this file to the list of
404 Ptr
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
406 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
410 memset ((char *) Ptr
, 0, sizeof (FILE_LIST
));
411 Ptr
->FileName
= (char *) malloc (strlen (FileName
) + 1);
412 if (Ptr
->FileName
== NULL
) {
413 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
417 strcpy (Ptr
->FileName
, FileName
);
418 Ptr
->ComponentsInstance
= ComponentsInstance
;
420 // Allocate memory to save the FV list if it's going into an FV.
422 if ((FVs
!= NULL
) && (FVs
[0] != 0)) {
423 Ptr
->FVs
= (char *) malloc (strlen (FVs
) + 1);
424 if (Ptr
->FVs
== NULL
) {
425 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
429 strcpy (Ptr
->FVs
, FVs
);
432 Ptr
->BaseFileName
= (char *) malloc (strlen (Name
) + 1);
433 if (Ptr
->BaseFileName
== NULL
) {
434 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
438 strcpy (Ptr
->BaseFileName
, Name
);
440 // Allocate memory for the basename if they gave us one. May not have one
441 // if the user is simply adding pre-existing binary files to the image.
443 if (BaseName
!= NULL
) {
444 Ptr
->BaseName
= (char *) malloc (strlen (BaseName
) + 1);
445 if (Ptr
->BaseName
== NULL
) {
446 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
450 strcpy (Ptr
->BaseName
, BaseName
);
453 // Allocate memory for the processor name
455 if (Processor
!= NULL
) {
456 Ptr
->Processor
= (char *) malloc (strlen (Processor
) + 1);
457 if (Ptr
->Processor
== NULL
) {
458 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
462 strcpy (Ptr
->Processor
, Processor
);
465 // Allocate memory for the guid name
468 Ptr
->Guid
= (char *) malloc (strlen (Guid
) + 1);
469 if (Ptr
->Guid
== NULL
) {
470 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
474 strcpy (Ptr
->Guid
, Guid
);
477 // If non-null apriori symbol, then save the apriori list for this file
479 if (Apriori
!= NULL
) {
480 strcpy (Ptr
->Apriori
, Apriori
);
483 if (mFileList
== NULL
) {
486 mLastFile
->Next
= Ptr
;
491 // Add these firmware volumes to the list of known firmware
494 AddFirmwareVolumes (FVs
, ComponentsInstance
);
496 return STATUS_SUCCESS
;
515 // Free up our firmware volume list
517 while (mFVList
!= NULL
) {
518 mFVListLast
= mFVList
->Next
;
520 mFVList
= mFVListLast
;
531 while (mFileList
!= NULL
) {
532 if (mFileList
->FileName
!= NULL
) {
533 free (mFileList
->FileName
);
536 if (mFileList
->FVs
!= NULL
) {
537 free (mFileList
->FVs
);
540 free (mFileList
->BaseFileName
);
541 if (mFileList
->BaseName
!= NULL
) {
542 free (mFileList
->BaseName
);
545 if (mFileList
->Processor
!= NULL
) {
546 free (mFileList
->Processor
);
549 if (mFileList
->Guid
!= NULL
) {
550 free (mFileList
->Guid
);
553 Next
= mFileList
->Next
;
570 After processing all components in a DSC file, create the firmware
571 volume INF files. We actually do a lot more here.
573 * Create the FVxxx.inf file that is used by GenFvImage
574 * Create the Apriori files for each firmware volume that requires one
575 * Create makefile.out macros for FVxxx_FILES = FVxxx_FILES AnotherFile
576 so you can do incremental builds of firmware volumes.
577 * For each FV, emit its build commands to makefile.out
581 DSC - pointer to a DSC_FILE object to extract info from
582 MakeFptr - pointer to the output makefile
591 FILE_LIST
*FileListPtr
;
600 char Line
[MAX_LINE_LEN
];
601 char ExpandedLine
[MAX_LINE_LEN
];
602 char FVDir
[MAX_PATH
];
607 BOOLEAN AprioriFound
;
608 int ComponentsInstance
;
612 // Use this to keep track of all the firmware volume names
617 // See if they specified a FV directory to dump the FV files out to. If not,
618 // then use the default. Then create the output directory.
620 StartCptr
= GetSymbolValue (FV_INF_DIR
);
621 if (StartCptr
== NULL
) {
622 ExpandSymbols (DEFAULT_FV_INF_DIR
, FVDir
, sizeof (FVDir
), EXPANDMODE_NO_UNDEFS
);
624 strcpy (FVDir
, StartCptr
);
627 // Make sure the fv directory path ends in /
629 CSave
= FVDir
[strlen (FVDir
) - 1];
630 if ((CSave
!= '\\') && (CSave
!= '/')) {
631 strcat (FVDir
, "\\");
634 // Traverse the list of all files, determine which FV each is in, then
635 // write out the file's name to the output FVxxx.inf file.
637 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
639 // Parse all the "FV1,FV2..." in the FVs
641 if (FileListPtr
->FVs
!= NULL
) {
643 // Process each fv this file is in
645 StartCptr
= FileListPtr
->FVs
;
648 while (*EndCptr
&& (*EndCptr
!= ',')) {
655 // Ok, we have a fv name, now see if we've already opened
656 // an fv output file of this name.
658 for (FVPtr
= FVList
; FVPtr
!= NULL
; FVPtr
= FVPtr
->Next
) {
659 if (_stricmp (FVPtr
->FVFileName
, StartCptr
) == 0) {
664 // If we didn't find one, then create a new one
668 // Create a new one, add it to the list
670 FVPtr
= (FV_LIST
*) malloc (sizeof (FV_LIST
));
672 Error (NULL
, 0, 0, NULL
, "failed to allocate memory for FV");
676 memset ((char *) FVPtr
, 0, sizeof (FV_LIST
));
678 // Add it to the end of our list
680 if (FVList
== NULL
) {
683 LastFVList
->Next
= FVPtr
;
688 // Save the FV name in the FileName pointer so we can compare
689 // for any future FV names specified.
691 strcpy (FVPtr
->FVFileName
, StartCptr
);
694 // Add a symbol for the FV filename
696 UpperCaseString (FVPtr
->FVFileName
);
697 AddSymbol (FV_FILENAME
, FVPtr
->FVFileName
, SYM_LOCAL
| SYM_OVERWRITE
);
699 // Now create the FVx.inf filename from the fv name and
700 // default filename extension. Dump it in the FV directory
704 strcat (Str
, FVPtr
->FVFileName
);
705 strcat (Str
, ".inf");
707 // Create the directory path for our new fv.inf output file.
710 if ((FVPtr
->FVFilePtr
= SmartOpen (Str
)) == NULL
) {
711 Error (NULL
, 0, 0, Str
, "could not open FV output file");
715 // Now copy the [fv.$(FV).options] to the fv INF file
717 sprintf (Str
, "fv.%s.options", StartCptr
);
718 Section
= DSCFileFindSection (DSC
, Str
);
719 if (Section
!= NULL
) {
720 SmartWrite (FVPtr
->FVFilePtr
, "[options]\n");
721 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
722 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
723 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
724 GetBaseAddress (ExpandedLine
, FVPtr
->BaseAddress
);
727 Error (NULL
, 0, 0, Str
, "could not find FV section in description file");
730 // Copy the [fv.$(FV).attributes] to the fv INF file
732 sprintf (Str
, "fv.%s.attributes", StartCptr
);
733 Section
= DSCFileFindSection (DSC
, Str
);
734 if (Section
!= NULL
) {
735 SmartWrite (FVPtr
->FVFilePtr
, "[attributes]\n");
736 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
737 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
738 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
741 Error (NULL
, 0, 0, Str
, "Could not find FV section in description file");
744 // Start the files section
746 SmartWrite (FVPtr
->FVFilePtr
, "\n[files]\n");
749 // Now write the FV filename to the FV.inf file. Prepend $(PROCESSOR) on
752 sprintf (ExpandedLine
, "EFI_FILE_NAME = %s\n", FileListPtr
->FileName
);
753 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
756 // Next FV on the FV list
767 // Now we walk the list of firmware volumes and create the APRIORI list
770 for (FVPtr
= FVList
; FVPtr
!= NULL
; FVPtr
= FVPtr
->Next
) {
772 // Run through all the files and count up how many are to be
773 // added to the apriori list for this FV. Then when we're done
774 // we'll make sure we processed them all. We do this in case they
775 // skipped an apriori index for a given FV.
778 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
779 if (OrderInFvList (FileListPtr
->Apriori
, FVPtr
->FVFileName
, &AprioriPosition
)) {
781 // Emit an error if the index was 0, or they didn't give one.
783 if (AprioriPosition
== 0) {
785 GetSymbolValue (DSC_FILENAME
),
788 "apriori indexes are 1-based",
789 "component %s:APRIORI=%s",
790 FileListPtr
->BaseName
,
800 // Now scan the files as we increment our apriori index
806 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
808 // If in the apriori list for this fv, print the name. Open the
809 // file first if we have to.
811 if ((FileListPtr
->Apriori
[0] != 0) &&
812 (OrderInFvList (FileListPtr
->Apriori
, FVPtr
->FVFileName
, &AprioriPosition
))
814 if (AprioriPosition
== AprioriCounter
) {
816 // If we've already found one for this index, emit an error. Decrement the
817 // count of how files we are to process so we don't emit another error for
822 GetSymbolValue (DSC_FILENAME
),
825 "duplicate apriori index found",
835 // Open the apriori output file if we haven't already
837 if (FVPtr
->AprioriFilePtr
== NULL
) {
839 strcat (Str
, FVPtr
->FVFileName
);
840 strcat (Str
, ".apr");
841 if ((FVPtr
->AprioriFilePtr
= SmartOpen (Str
)) == NULL
) {
842 Error (NULL
, 0, 0, Str
, "could not open output Apriori file for writing");
847 sprintf (ExpandedLine
, "%s\n", FileListPtr
->BaseFileName
);
848 SmartWrite (FVPtr
->AprioriFilePtr
, ExpandedLine
);
852 } while (AprioriFound
);
854 // See if they skipped an apriori position for this FV
856 if (AprioriCount
!= (AprioriCounter
- 1)) {
858 GetSymbolValue (DSC_FILENAME
),
861 "apriori index skipped",
869 // Traverse the list of all files again, and create a macro in the output makefile
870 // that defines all the files in each fv. For example, for each FV file, create a line:
871 // FV0001_FILES = $(FV_0001_FILES) xxxx-yyy.dxe.
872 // This can then be used as a dependency in their makefile.
873 // Also if they wanted us to dump a cross-reference, do that now.
875 if (mXRefFileName
!= NULL
) {
876 if ((XRefFptr
= fopen (mXRefFileName
, "w")) == NULL
) {
879 "Failed to open cross-reference file '%s' for writing\n",
887 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
889 // Parse all the "FV1,FV2..." in the FV field that came from FV=FVa,FVb,... on the
890 // component line in the DSC file.
892 if (FileListPtr
->FVs
!= NULL
) {
894 // If generating a cross-reference file, dump the data
896 if (XRefFptr
!= NULL
) {
897 if ((FileListPtr
->Guid
!= NULL
) && (FileListPtr
->BaseName
!= NULL
) && (FileListPtr
->Processor
)) {
902 FileListPtr
->BaseName
,
903 FileListPtr
->Processor
908 // Convert to uppercase since we're going to use the name as a macro variable name
911 UpperCaseString (FileListPtr
->FVs
);
913 // Process each FV this file is in to write fvxxx_FILES = $(fvxxx_FILES) Guid-BaseName.ffs
915 StartCptr
= FileListPtr
->FVs
;
918 while (*EndCptr
&& (*EndCptr
!= ',')) {
926 "%s_FILES = $(%s_FILES) %s\n",
929 FileListPtr
->FileName
932 // Next FV on the FV list
943 fprintf (MakeFptr
, "\n");
946 // Now go through the list of all NonFFS FVs they specified and search for
947 // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the
948 // output makefile. Add them to the "fvs_0" target as well.
950 if (mNonFfsFVList
!= NULL
) {
951 fprintf (MakeFptr
, "fvs_0 ::");
952 FVPtr
= mNonFfsFVList
;
953 while (FVPtr
!= NULL
) {
954 fprintf (MakeFptr
, " %s%s.fv", FVDir
, FVPtr
->FVFileName
);
958 fprintf (MakeFptr
, "\n\n");
959 FVPtr
= mNonFfsFVList
;
960 while (FVPtr
!= NULL
) {
962 // Save the position in the file
964 DSCFileSavePosition (DSC
);
966 // first try to find a build section specific for this fv.
968 sprintf (Str
, "build.fv.%s", FVPtr
->FVFileName
);
969 Section
= DSCFileFindSection (DSC
, Str
);
970 if (Section
== NULL
) {
971 sprintf (Str
, "build.fv");
972 Section
= DSCFileFindSection (DSC
, Str
);
975 if (Section
== NULL
) {
981 "No [build.fv.%s] nor [%s] section found in description file for building %s",
988 // Add a symbol for the FV filename
990 UpperCaseString (FVPtr
->FVFileName
);
991 AddSymbol (FV_FILENAME
, FVPtr
->FVFileName
, SYM_LOCAL
| SYM_OVERWRITE
);
992 AddSymbol (EFI_BASE_ADDRESS
, FVPtr
->BaseAddress
, SYM_LOCAL
| SYM_OVERWRITE
);
995 // Now copy the build commands from the section to the makefile
997 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1001 sizeof (ExpandedLine
),
1002 EXPANDMODE_NO_DESTDIR
| EXPANDMODE_NO_SOURCEDIR
1005 fprintf (MakeFptr
, ExpandedLine
);
1009 FVPtr
= FVPtr
->Next
;
1010 DSCFileRestorePosition (DSC
);
1015 // Get the components count
1017 ComponentCount
= -1;
1018 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
1019 if (FileListPtr
->ComponentsInstance
> ComponentCount
) {
1020 ComponentCount
= FileListPtr
->ComponentsInstance
;
1026 // Now print firmware volumes build targets fvs_0, fvs_1 etc.
1028 for (ComponentsInstance
= 0; ComponentsInstance
< ComponentCount
; ComponentsInstance
++) {
1029 fprintf (MakeFptr
, "fvs_%d ::", ComponentsInstance
);
1030 for (FVPtr
= mFVList
; FVPtr
!= NULL
; FVPtr
= FVPtr
->Next
) {
1031 if (FVPtr
->ComponentsInstance
== ComponentsInstance
) {
1032 fprintf (MakeFptr
, " %s%s.fv", FVDir
, FVPtr
->FVFileName
);
1035 fprintf (MakeFptr
, "\n\n");
1039 // Create an "fvs" target that builds everything. It has to be a mix of
1040 // components and FV's in order. For example:
1041 // fvs :: components_0 fvs_0 components_1 fvs_1
1043 fprintf (MakeFptr
, "fvs ::");
1044 for (ComponentsInstance
= 0; ComponentsInstance
< ComponentCount
; ComponentsInstance
++) {
1045 fprintf (MakeFptr
, " components_%d fvs_%d", ComponentsInstance
, ComponentsInstance
);
1047 fprintf (MakeFptr
, "\n\n");
1050 // Create a "components" target for build convenience. It should
1051 // look something like:
1052 // components : components_0 components_1...
1054 if (ComponentCount
> 0) {
1055 fprintf (MakeFptr
, "components :");
1056 for (ComponentsInstance
= 0; ComponentsInstance
< ComponentCount
; ComponentsInstance
++) {
1057 fprintf (MakeFptr
, " components_%d", ComponentsInstance
);
1060 fprintf (MakeFptr
, "\n\n");
1063 // Now go through the list of all FV's defined and search for
1064 // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the
1068 while (FVPtr
!= NULL
) {
1069 if (FVPtr
->FVFileName
[0]) {
1071 // Save the position in the file
1073 DSCFileSavePosition (DSC
);
1075 // First try to find a build section specific for this FV.
1077 sprintf (Str
, "build.fv.%s", FVPtr
->FVFileName
);
1078 Section
= DSCFileFindSection (DSC
, Str
);
1079 if (Section
== NULL
) {
1080 sprintf (Str
, "build.fv");
1081 Section
= DSCFileFindSection (DSC
, Str
);
1084 if (Section
== NULL
) {
1090 "no [build.fv.%s] nor [%s] section found in description file for building %s",
1097 // Add a symbol for the FV filename
1099 UpperCaseString (FVPtr
->FVFileName
);
1100 AddSymbol (FV_FILENAME
, FVPtr
->FVFileName
, SYM_LOCAL
| SYM_OVERWRITE
);
1101 AddSymbol (EFI_BASE_ADDRESS
, FVPtr
->BaseAddress
, SYM_LOCAL
| SYM_OVERWRITE
);
1104 // Now copy the build commands from the section to the makefile
1106 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1110 sizeof (ExpandedLine
),
1111 EXPANDMODE_NO_DESTDIR
| EXPANDMODE_NO_SOURCEDIR
1113 fprintf (MakeFptr
, ExpandedLine
);
1117 DSCFileRestorePosition (DSC
);
1120 FVPtr
= FVPtr
->Next
;
1123 // Close all the files and free up the memory
1125 while (FVList
!= NULL
) {
1126 FVPtr
= FVList
->Next
;
1127 if (FVList
->FVFilePtr
!= NULL
) {
1128 SmartClose (FVList
->FVFilePtr
);
1131 if (FVList
->AprioriFilePtr
!= NULL
) {
1132 SmartClose (FVList
->AprioriFilePtr
);
1139 while (mNonFfsFVList
!= NULL
) {
1140 FVPtr
= mNonFfsFVList
->Next
;
1141 free (mNonFfsFVList
);
1142 mNonFfsFVList
= FVPtr
;
1145 if (XRefFptr
!= NULL
) {
1149 return STATUS_SUCCESS
;
1153 NonFFSFVWriteInfFiles (
1159 Routine Description:
1161 Generate a Non FFS fv file. It can only some variables,
1162 or simply contains nothing except header.
1166 DSC - pointer to a DSC_FILE object to extract info from
1167 FileName - pointer to the fv file
1171 STATUS_SUCCESS if successful
1172 non-STATUS_SUCCESS otherwise
1182 char Line
[MAX_LINE_LEN
];
1183 char ExpandedLine
[MAX_LINE_LEN
];
1184 char FVDir
[MAX_PATH
];
1187 // See if they specified a FV directory to dump the FV files out to. If not,
1188 // then use the default. Then create the output directory.
1190 DSCFileSavePosition (DSC
);
1191 StartCptr
= GetSymbolValue (FV_INF_DIR
);
1192 if (StartCptr
== NULL
) {
1193 ExpandSymbols (DEFAULT_FV_INF_DIR
, FVDir
, sizeof (FVDir
), EXPANDMODE_NO_UNDEFS
);
1195 strcpy (FVDir
, StartCptr
);
1199 // Make sure the fv directory path ends in /
1201 CSave
= FVDir
[strlen (FVDir
) - 1];
1202 if ((CSave
!= '\\') && (CSave
!= '/')) {
1203 strcat (FVDir
, "\\");
1206 StartCptr
= FileName
;
1207 while (*StartCptr
) {
1208 EndCptr
= StartCptr
;
1209 while (*EndCptr
&& (*EndCptr
!= ',')) {
1216 // Ok, we have a fv name, now see if we've already opened
1217 // an fv output file of this name.
1219 for (FVPtr
= mNonFfsFVList
; FVPtr
!= NULL
; FVPtr
= FVPtr
->Next
) {
1220 if (_stricmp (FVPtr
->FVFileName
, StartCptr
) == 0) {
1225 // If there is already one with the same name, wrong
1227 if (FVPtr
!= NULL
) {
1228 DSCFileRestorePosition (DSC
);
1229 return STATUS_ERROR
;
1232 // Create a new one, add it to the list
1234 FVPtr
= (FV_LIST
*) malloc (sizeof (FV_LIST
));
1235 if (FVPtr
== NULL
) {
1236 Error (__FILE__
, __LINE__
, 0, "failed to allocate memory", NULL
);
1237 DSCFileRestorePosition (DSC
);
1238 return STATUS_ERROR
;
1241 memset ((char *) FVPtr
, 0, sizeof (FV_LIST
));
1242 FVPtr
->Next
= mNonFfsFVList
;
1243 mNonFfsFVList
= FVPtr
;
1245 // Save the FV name in the FileName pointer so we can compare
1246 // for any future FV names specified.
1248 strcpy (FVPtr
->FVFileName
, StartCptr
);
1250 // Add a symbol for the FV filename
1252 UpperCaseString (FVPtr
->FVFileName
);
1253 AddSymbol (FV_FILENAME
, FVPtr
->FVFileName
, SYM_LOCAL
| SYM_OVERWRITE
);
1256 // Now create the FVx.inf filename from the fv name and
1257 // default filename extension. Dump it in the FV directory
1260 strcpy (Str
, FVDir
);
1261 strcat (Str
, FVPtr
->FVFileName
);
1262 strcat (Str
, ".inf");
1264 // Create the directory path for our new fv.inf output file.
1267 if ((FVPtr
->FVFilePtr
= SmartOpen (Str
)) == NULL
) {
1268 Error (NULL
, 0, 0, Str
, "could not open FV output file");
1269 DSCFileRestorePosition (DSC
);
1270 return STATUS_ERROR
;
1273 // Now copy the [fv.fvfile.options] to the fv file
1275 sprintf (Str
, "fv.%s.options", StartCptr
);
1276 Section
= DSCFileFindSection (DSC
, Str
);
1277 if (Section
!= NULL
) {
1278 SmartWrite (FVPtr
->FVFilePtr
, "[options]\n");
1279 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1280 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
1281 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
1282 GetBaseAddress (ExpandedLine
, FVPtr
->BaseAddress
);
1285 Warning (NULL
, 0, 0, NULL
, "Could not find FV section '%s' in description file", Str
);
1288 // Copy the [fv.fvfile.attributes] to the fv file
1290 sprintf (Str
, "fv.%s.attributes", StartCptr
);
1291 Section
= DSCFileFindSection (DSC
, Str
);
1292 if (Section
!= NULL
) {
1293 SmartWrite (FVPtr
->FVFilePtr
, "[attributes]\n");
1294 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1295 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
1296 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
1299 Warning (NULL
, 0, 0, NULL
, "Could not find FV section '%s' in description file", Str
);
1302 // Copy the [fv.fvfile.components] to the fv file
1304 sprintf (Str
, "fv.%s.components", StartCptr
);
1305 Section
= DSCFileFindSection (DSC
, Str
);
1306 if (Section
!= NULL
) {
1307 SmartWrite (FVPtr
->FVFilePtr
, "[components]\n");
1308 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1309 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
1310 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
1314 // An empty FV is allowed to contain nothing
1320 SmartClose (FVPtr
->FVFilePtr
);
1322 // Next FV in FileName
1325 StartCptr
= EndCptr
;
1331 DSCFileRestorePosition (DSC
);
1332 return STATUS_SUCCESS
;
1337 AddFirmwareVolumes (
1339 int ComponentsInstance
1347 if ((FVs
!= NULL
) && (FVs
[0] != 0)) {
1349 // Extract each FV name from the string. It's from the DSC file "FV=FvRecover,FvMain"
1352 while (*StartPtr
!= 0) {
1354 while (*EndPtr
&& (*EndPtr
!= ',')) {
1361 // Look through our list of known firmware volumes and see if we've
1362 // already added it.
1364 for (FvPtr
= mFVList
; FvPtr
!= NULL
; FvPtr
= FvPtr
->Next
) {
1365 if (_stricmp (FvPtr
->FVFileName
, StartPtr
) == 0) {
1370 // If we didn't find a match, then create a new one
1372 if (FvPtr
== NULL
) {
1373 FvPtr
= malloc (sizeof (FV_LIST
));
1374 if (FvPtr
== NULL
) {
1375 Error (__FILE__
, __LINE__
, 0, "application error", "memory allocation failed");
1379 memset (FvPtr
, 0, sizeof (FV_LIST
));
1380 strcpy (FvPtr
->FVFileName
, StartPtr
);
1381 if (mFVList
== NULL
) {
1384 mFVListLast
->Next
= FvPtr
;
1387 mFVListLast
= FvPtr
;
1390 // If this component's section number is higher than that of this
1391 // FV, then set the FV's to it.
1393 if (FvPtr
->ComponentsInstance
< ComponentsInstance
) {
1394 FvPtr
->ComponentsInstance
= ComponentsInstance
;
1397 // If we found then end of the FVs in the string, then we're done.
1398 // Always restore the original string's contents.
1400 if (SaveChar
!= 0) {
1402 StartPtr
= EndPtr
+ 1;
1419 // Given FvList of format "FV_a,FV_b,FV_c" or "FV_a:1,FV_b:2" and
1420 // FvName of format "FV_c", determine if FvName is in FvList. If
1421 // FV_a:1 format, then return the value after the colon.
1425 // If it matches for the length of FvName...
1427 if (_strnicmp (FvList
, FvName
, strlen (FvName
)) == 0) {
1429 // Then see if the match string in FvList is terminated at the
1432 if ((FvList
[strlen (FvName
)] == ',') || (FvList
[strlen (FvName
)] == 0)) {
1435 } else if (FvList
[strlen (FvName
)] == ':') {
1436 *Order
= atoi (FvList
+ strlen (FvName
) + 1);
1441 // Skip to next FV in the comma-separated list
1443 while ((*FvList
!= ',') && (*FvList
!= 0)) {
1449 if (*FvList
== ',') {
1465 for (Cptr
= Str
; *Cptr
; Cptr
++) {
1466 *Cptr
= (char) toupper (*Cptr
);
1487 // Process each FV in first FV list
1490 while (*StartCptr1
) {
1491 EndCptr1
= StartCptr1
;
1492 while (*EndCptr1
&& (*EndCptr1
!= ',')) {
1501 // Process each FV in second FV list
1504 while (*StartCptr2
) {
1505 EndCptr2
= StartCptr2
;
1506 while (*EndCptr2
&& (*EndCptr2
!= ',')) {
1513 if (_stricmp (StartCptr1
, StartCptr2
) == 0) {
1520 // Next FV on the second FV list
1523 StartCptr2
= EndCptr2
;
1531 // Next FV on the first FV list
1534 StartCptr1
= EndCptr1
;
1544 CFVSetXRefFileName (
1548 mXRefFileName
= FileName
;