3 Copyright (c) 2004 - 2007, 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
38 #define MALLOC(size) malloc (size)
39 #define FREE(ptr) free (ptr)
42 // Disable warning for unused function arguments
44 #pragma warning(disable : 4100)
46 // Disable warning for while(1) code
48 // #pragma warning (disable : 4127)
53 } COMP_TYPE_EXTENSION
;
56 // Use a linked list of these to keep track of all the FV names used
58 typedef struct _FV_LIST
{
59 struct _FV_LIST
*Next
;
60 char FVFileName
[MAX_PATH
];
61 char BaseAddress
[MAX_LINE_LEN
];
62 SMART_FILE
*FVFilePtr
;
63 SMART_FILE
*AprioriFilePtr
;
65 int ComponentsInstance
; // highest [components.n] section with a file for this FV
69 // Use a linked list of these to keep track of all FFS files built. When
70 // we're done, we turn the info into the FV INF files used to build the
73 typedef struct _FILE_LIST
{
74 struct _FILE_LIST
*Next
;
77 char *FVs
; // from FV=x,y,z
78 char *BaseName
; // only needed for duplicate basename check
79 char *Processor
; // only needed for duplicate basename check
80 char Apriori
[100]; // of format "FVRecovery:1,FVMain:2" from APRIORI define
81 char *Guid
; // guid string
82 int ComponentsInstance
; // which [components.n] section it's in
85 typedef struct _LINKED_LIST
{
86 struct _LINKED_LIST
*Next
;
90 static FILE_LIST
*mFileList
;
91 static FILE_LIST
*mLastFile
;
92 static char *mXRefFileName
= NULL
;
93 static FV_LIST
*mNonFfsFVList
= NULL
;
96 // Whenever an FV name is referenced, then add it to our list of known
99 static FV_LIST
*mFVList
= NULL
;
100 static FV_LIST
*mFVListLast
= NULL
;
103 // We use this list so that from a given component type, we can determine
104 // the name of the file on disk. For example, if we're given a file's
105 // guid and base name, and we know it's a "bs_driver", then we can look
106 // up "bs_driver" in this array and know that the file (after it's built)
107 // name is GUID-BASENAME.DXE
109 static const COMP_TYPE_EXTENSION mCompTypeExtension
[] = {
167 "combined_peim_driver",
199 int ComponentsInstance
,
200 FILE_LIST
*FileListPtr
223 while (*Name
&& isspace (*Name
)) {
231 // Find the end of the name. Either space or a '='.
233 for (Value
= Name
; *Value
&& !isspace (*Value
) && (*Value
!= '='); Value
++)
242 while (*Value
&& (*Value
!= '=')) {
250 // Now truncate the name
254 if (_stricmp (Name
, EFI_BASE_ADDRESS
) != 0) {
260 // Skip over the = and then any spaces
263 while (*Value
&& isspace (*Value
)) {
267 // Find end of string, checking for quoted string
269 if (*Value
== '\"') {
271 for (Cptr
= Value
; *Cptr
&& *Cptr
!= '\"'; Cptr
++)
274 for (Cptr
= Value
; *Cptr
&& !isspace (*Cptr
); Cptr
++)
278 // Null terminate the value string
282 strcpy (BaseAddress
, Value
);
285 return STATUS_SUCCESS
;
293 int ComponentsInstance
,
304 Add a file to the list of files in one or more firmware volumes.
308 Name - $(FILE_GUID)-$(BASE_NAME), or filename
309 ComponentType - type of component being added. Required so we know the
310 resultant file name after it has been built
311 FVs - string of commma-separated FVs that the given file is
312 to be added to. For example, FVs="FV0001,FV0002"
313 FFSExt - FFS filename extension of the file after it has been built.
314 This is passed in to us in case we don't know the default
315 filename extension based on the component type.
316 Processor - the target processor which the FV is being built for
317 Apriori - pointer to the definition of APRIORI. For example APRIORI="FvRecovery:1,FvMain:4"
321 STATUS_SUCCESS if successful
326 char FileName
[MAX_PATH
];
331 // If they provided a filename extension for this type of file, then use it.
332 // If they did not provide a filename extension, search our list for a
333 // matching component type and use the extension appropriate for this
336 if (FFSExt
== NULL
) {
338 // They didn't give us a filename extension. Figure it out from the
341 for (i
= 0; mCompTypeExtension
[i
].ComponentType
!= NULL
; i
++) {
342 if (_stricmp (ComponentType
, mCompTypeExtension
[i
].ComponentType
) == 0) {
343 FFSExt
= mCompTypeExtension
[i
].Extension
;
348 // If we don't know the file extension, then error out. Just means
349 // the need to define "FFS_EXT = raw" in the component INF file.
351 if (mCompTypeExtension
[i
].ComponentType
== NULL
) {
357 "unknown component type - must define FFS_EXT for built filename extension in component INF file"
363 // We now have all the parts to the FFS filename. Prepend the path to it if
364 // it's not a full pathname.
365 // See if they overrode the default base directory for the FV files.
367 if (!IsAbsolutePath (Name
)) {
368 Sym
= GetSymbolValue (FV_DIR
);
370 Sym
= DEFAULT_FV_DIR
;
373 // Create the file path. Something like $(BUILD_DIR)\$(PROCESSOR)\$(GUID)-$(BASE_NAME).ext
374 // If the extension is non-zero length, then make sure there's a dot in it.
376 if ((strlen (FFSExt
) > 0) && (FFSExt
[0] != '.')) {
377 sprintf (Str
, "%s\\%s\\%s.%s", Sym
, Processor
, Name
, FFSExt
);
379 sprintf (Str
, "%s\\%s\\%s%s", Sym
, Processor
, Name
, FFSExt
);
382 ExpandSymbols (Str
, FileName
, sizeof (FileName
), EXPANDMODE_NO_UNDEFS
);
384 strcpy (FileName
, Name
);
387 // Traverse the list of files we have so far and make sure we don't have
388 // any duplicate basenames. If the base name and processor match, then we'll
389 // have build issues, so don't allow it. We also don't allow the same file GUID
390 // in the same FV which will cause boot time error if we allow this.
393 while (Ptr
!= NULL
) {
394 if ((Ptr
->BaseName
!= NULL
) && (BaseName
!= NULL
) && (_stricmp (BaseName
, Ptr
->BaseName
) == 0)) {
395 if ((Ptr
->Processor
!= NULL
) && (Processor
!= NULL
) && (_stricmp (Processor
, Ptr
->Processor
) == 0)) {
396 Error (NULL
, 0, 0, BaseName
, "duplicate base name specified");
401 if ((Ptr
->Guid
!= NULL
) && (Guid
!= NULL
) && (_stricmp (Guid
, Ptr
->Guid
) == 0)) {
402 if ((Ptr
->FVs
!= NULL
) && (FVs
!= NULL
) && (InSameFv (FVs
, Ptr
->FVs
))) {
403 Error (NULL
, 0, 0, Guid
, "duplicate Guid specified in the same FV for %s and %s",
404 (Ptr
->BaseName
==NULL
)?"Unknown":Ptr
->BaseName
,
405 (BaseName
==NULL
)?"Unknown":BaseName
);
413 // Allocate a new structure so we can add this file to the list of
416 Ptr
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
418 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
422 memset ((char *) Ptr
, 0, sizeof (FILE_LIST
));
423 Ptr
->FileName
= (char *) malloc (strlen (FileName
) + 1);
424 if (Ptr
->FileName
== NULL
) {
425 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
429 strcpy (Ptr
->FileName
, FileName
);
430 Ptr
->ComponentsInstance
= ComponentsInstance
;
432 // Allocate memory to save the FV list if it's going into an FV.
434 if ((FVs
!= NULL
) && (FVs
[0] != 0)) {
435 Ptr
->FVs
= (char *) malloc (strlen (FVs
) + 1);
436 if (Ptr
->FVs
== NULL
) {
437 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
441 strcpy (Ptr
->FVs
, FVs
);
444 Ptr
->BaseFileName
= (char *) malloc (strlen (Name
) + 1);
445 if (Ptr
->BaseFileName
== NULL
) {
446 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
450 strcpy (Ptr
->BaseFileName
, Name
);
452 // Allocate memory for the basename if they gave us one. May not have one
453 // if the user is simply adding pre-existing binary files to the image.
455 if (BaseName
!= NULL
) {
456 Ptr
->BaseName
= (char *) malloc (strlen (BaseName
) + 1);
457 if (Ptr
->BaseName
== NULL
) {
458 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
462 strcpy (Ptr
->BaseName
, BaseName
);
465 // Allocate memory for the processor name
467 if (Processor
!= NULL
) {
468 Ptr
->Processor
= (char *) malloc (strlen (Processor
) + 1);
469 if (Ptr
->Processor
== NULL
) {
470 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
474 strcpy (Ptr
->Processor
, Processor
);
477 // Allocate memory for the guid name
480 Ptr
->Guid
= (char *) malloc (strlen (Guid
) + 1);
481 if (Ptr
->Guid
== NULL
) {
482 Error (NULL
, 0, 0, NULL
, "failed to allocate memory");
486 strcpy (Ptr
->Guid
, Guid
);
489 // If non-null apriori symbol, then save the apriori list for this file
491 if (Apriori
!= NULL
) {
492 strcpy (Ptr
->Apriori
, Apriori
);
495 if (mFileList
== NULL
) {
498 mLastFile
->Next
= Ptr
;
503 // Add these firmware volumes to the list of known firmware
506 AddFirmwareVolumes (FVs
, ComponentsInstance
, Ptr
);
508 return STATUS_SUCCESS
;
527 // Free up our firmware volume list
529 while (mFVList
!= NULL
) {
530 mFVListLast
= mFVList
->Next
;
532 mFVList
= mFVListLast
;
543 while (mFileList
!= NULL
) {
544 if (mFileList
->FileName
!= NULL
) {
545 free (mFileList
->FileName
);
548 if (mFileList
->FVs
!= NULL
) {
549 free (mFileList
->FVs
);
552 free (mFileList
->BaseFileName
);
553 if (mFileList
->BaseName
!= NULL
) {
554 free (mFileList
->BaseName
);
557 if (mFileList
->Processor
!= NULL
) {
558 free (mFileList
->Processor
);
561 if (mFileList
->Guid
!= NULL
) {
562 free (mFileList
->Guid
);
565 Next
= mFileList
->Next
;
582 After processing all components in a DSC file, create the firmware
583 volume INF files. We actually do a lot more here.
585 * Create the FVxxx.inf file that is used by GenFvImage
586 * Create the Apriori files for each firmware volume that requires one
587 * Create makefile.out macros for FVxxx_FILES = FVxxx_FILES AnotherFile
588 so you can do incremental builds of firmware volumes.
589 * For each FV, emit its build commands to makefile.out
593 DSC - pointer to a DSC_FILE object to extract info from
594 MakeFptr - pointer to the output makefile
603 FILE_LIST
*FileListPtr
;
612 char Line
[MAX_LINE_LEN
];
613 char ExpandedLine
[MAX_LINE_LEN
];
614 char FVDir
[MAX_PATH
];
619 BOOLEAN AprioriFound
;
620 int ComponentsInstance
;
624 // Use this to keep track of all the firmware volume names
629 // See if they specified a FV directory to dump the FV files out to. If not,
630 // then use the default. Then create the output directory.
632 StartCptr
= GetSymbolValue (FV_INF_DIR
);
633 if (StartCptr
== NULL
) {
634 ExpandSymbols (DEFAULT_FV_INF_DIR
, FVDir
, sizeof (FVDir
), EXPANDMODE_NO_UNDEFS
);
636 strcpy (FVDir
, StartCptr
);
639 // Make sure the fv directory path ends in /
641 CSave
= FVDir
[strlen (FVDir
) - 1];
642 if ((CSave
!= '\\') && (CSave
!= '/')) {
643 strcat (FVDir
, "\\");
646 // Traverse the list of all files, determine which FV each is in, then
647 // write out the file's name to the output FVxxx.inf file.
649 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
651 // Parse all the "FV1,FV2..." in the FVs
653 if (FileListPtr
->FVs
!= NULL
) {
655 // Process each fv this file is in
657 StartCptr
= FileListPtr
->FVs
;
660 while (*EndCptr
&& (*EndCptr
!= ',')) {
667 // Ok, we have a fv name, now see if we've already opened
668 // an fv output file of this name.
670 for (FVPtr
= FVList
; FVPtr
!= NULL
; FVPtr
= FVPtr
->Next
) {
671 if (_stricmp (FVPtr
->FVFileName
, StartCptr
) == 0) {
676 // If we didn't find one, then create a new one
680 // Create a new one, add it to the list
682 FVPtr
= (FV_LIST
*) malloc (sizeof (FV_LIST
));
684 Error (NULL
, 0, 0, NULL
, "failed to allocate memory for FV");
688 memset ((char *) FVPtr
, 0, sizeof (FV_LIST
));
690 // Add it to the end of our list
692 if (FVList
== NULL
) {
695 LastFVList
->Next
= FVPtr
;
700 // Save the FV name in the FileName pointer so we can compare
701 // for any future FV names specified.
703 strcpy (FVPtr
->FVFileName
, StartCptr
);
706 // Add a symbol for the FV filename
708 UpperCaseString (FVPtr
->FVFileName
);
709 AddSymbol (FV_FILENAME
, FVPtr
->FVFileName
, SYM_LOCAL
| SYM_OVERWRITE
);
711 // Now create the FVx.inf filename from the fv name and
712 // default filename extension. Dump it in the FV directory
716 strcat (Str
, FVPtr
->FVFileName
);
717 strcat (Str
, ".inf");
719 // Create the directory path for our new fv.inf output file.
722 if ((FVPtr
->FVFilePtr
= SmartOpen (Str
)) == NULL
) {
723 Error (NULL
, 0, 0, Str
, "could not open FV output file");
727 // Now copy the [fv.$(FV).options] to the fv INF file
729 sprintf (Str
, "fv.%s.options", StartCptr
);
730 Section
= DSCFileFindSection (DSC
, Str
);
731 if (Section
!= NULL
) {
732 SmartWrite (FVPtr
->FVFilePtr
, "[options]\n");
733 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
734 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
735 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
736 GetBaseAddress (ExpandedLine
, FVPtr
->BaseAddress
);
739 Error (NULL
, 0, 0, Str
, "could not find FV section in description file");
742 // Copy the [fv.$(FV).attributes] to the fv INF file
744 sprintf (Str
, "fv.%s.attributes", StartCptr
);
745 Section
= DSCFileFindSection (DSC
, Str
);
746 if (Section
!= NULL
) {
747 SmartWrite (FVPtr
->FVFilePtr
, "[attributes]\n");
748 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
749 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
750 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
753 Error (NULL
, 0, 0, Str
, "Could not find FV section in description file");
756 // Start the files section
758 SmartWrite (FVPtr
->FVFilePtr
, "\n[files]\n");
761 // Now write the FV filename to the FV.inf file. Prepend $(PROCESSOR) on
764 sprintf (ExpandedLine
, "EFI_FILE_NAME = %s\n", FileListPtr
->FileName
);
765 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
768 // Next FV on the FV list
779 // Now we walk the list of firmware volumes and create the APRIORI list
782 for (FVPtr
= FVList
; FVPtr
!= NULL
; FVPtr
= FVPtr
->Next
) {
784 // Run through all the files and count up how many are to be
785 // added to the apriori list for this FV. Then when we're done
786 // we'll make sure we processed them all. We do this in case they
787 // skipped an apriori index for a given FV.
790 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
791 if (OrderInFvList (FileListPtr
->Apriori
, FVPtr
->FVFileName
, &AprioriPosition
)) {
793 // Emit an error if the index was 0, or they didn't give one.
795 if (AprioriPosition
== 0) {
797 GetSymbolValue (DSC_FILENAME
),
800 "apriori indexes are 1-based",
801 "component %s:APRIORI=%s",
802 FileListPtr
->BaseName
,
812 // Now scan the files as we increment our apriori index
818 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
820 // If in the apriori list for this fv, print the name. Open the
821 // file first if we have to.
823 if ((FileListPtr
->Apriori
[0] != 0) &&
824 (OrderInFvList (FileListPtr
->Apriori
, FVPtr
->FVFileName
, &AprioriPosition
))
826 if (AprioriPosition
== AprioriCounter
) {
828 // If we've already found one for this index, emit an error. Decrement the
829 // count of how files we are to process so we don't emit another error for
834 GetSymbolValue (DSC_FILENAME
),
837 "duplicate apriori index found",
847 // Open the apriori output file if we haven't already
849 if (FVPtr
->AprioriFilePtr
== NULL
) {
851 strcat (Str
, FVPtr
->FVFileName
);
852 strcat (Str
, ".apr");
853 if ((FVPtr
->AprioriFilePtr
= SmartOpen (Str
)) == NULL
) {
854 Error (NULL
, 0, 0, Str
, "could not open output Apriori file for writing");
859 sprintf (ExpandedLine
, "%s\n", FileListPtr
->BaseFileName
);
860 SmartWrite (FVPtr
->AprioriFilePtr
, ExpandedLine
);
864 } while (AprioriFound
);
866 // See if they skipped an apriori position for this FV
868 if (AprioriCount
!= (AprioriCounter
- 1)) {
870 GetSymbolValue (DSC_FILENAME
),
873 "apriori index skipped",
881 // Traverse the list of all files again, and create a macro in the output makefile
882 // that defines all the files in each fv. For example, for each FV file, create a line:
883 // FV0001_FILES = $(FV_0001_FILES) xxxx-yyy.dxe.
884 // This can then be used as a dependency in their makefile.
885 // Also if they wanted us to dump a cross-reference, do that now.
887 if (mXRefFileName
!= NULL
) {
888 if ((XRefFptr
= fopen (mXRefFileName
, "w")) == NULL
) {
891 "Failed to open cross-reference file '%s' for writing\n",
899 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
901 // Parse all the "FV1,FV2..." in the FV field that came from FV=FVa,FVb,... on the
902 // component line in the DSC file.
904 if (FileListPtr
->FVs
!= NULL
) {
906 // If generating a cross-reference file, dump the data
908 if (XRefFptr
!= NULL
) {
909 if ((FileListPtr
->Guid
!= NULL
) && (FileListPtr
->BaseName
!= NULL
) && (FileListPtr
->Processor
)) {
914 FileListPtr
->BaseName
,
915 FileListPtr
->Processor
920 // Convert to uppercase since we're going to use the name as a macro variable name
923 UpperCaseString (FileListPtr
->FVs
);
925 // Process each FV this file is in to write fvxxx_FILES = $(fvxxx_FILES) Guid-BaseName.ffs
927 StartCptr
= FileListPtr
->FVs
;
930 while (*EndCptr
&& (*EndCptr
!= ',')) {
938 "%s_FILES = $(%s_FILES) %s\n",
941 FileListPtr
->FileName
944 // Next FV on the FV list
955 fprintf (MakeFptr
, "\n");
958 // Now go through the list of all NonFFS FVs they specified and search for
959 // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the
960 // output makefile. Add them to the "fvs" target as well.
962 if (mNonFfsFVList
!= NULL
) {
963 fprintf (MakeFptr
, "fvs ::");
964 FVPtr
= mNonFfsFVList
;
965 while (FVPtr
!= NULL
) {
966 fprintf (MakeFptr
, " %s%s.fv", FVDir
, FVPtr
->FVFileName
);
970 fprintf (MakeFptr
, "\n\n");
971 FVPtr
= mNonFfsFVList
;
972 while (FVPtr
!= NULL
) {
974 // Save the position in the file
976 DSCFileSavePosition (DSC
);
978 // first try to find a build section specific for this fv.
980 sprintf (Str
, "build.fv.%s", FVPtr
->FVFileName
);
981 Section
= DSCFileFindSection (DSC
, Str
);
982 if (Section
== NULL
) {
983 sprintf (Str
, "build.fv");
984 Section
= DSCFileFindSection (DSC
, Str
);
987 if (Section
== NULL
) {
993 "No [build.fv.%s] nor [%s] section found in description file for building %s",
1000 // Add a symbol for the FV filename
1002 UpperCaseString (FVPtr
->FVFileName
);
1003 AddSymbol (FV_FILENAME
, FVPtr
->FVFileName
, SYM_LOCAL
| SYM_OVERWRITE
);
1004 AddSymbol (EFI_BASE_ADDRESS
, FVPtr
->BaseAddress
, SYM_LOCAL
| SYM_OVERWRITE
);
1007 // Now copy the build commands from the section to the makefile
1009 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1013 sizeof (ExpandedLine
),
1014 EXPANDMODE_NO_DESTDIR
| EXPANDMODE_NO_SOURCEDIR
1017 fprintf (MakeFptr
, ExpandedLine
);
1021 FVPtr
= FVPtr
->Next
;
1022 DSCFileRestorePosition (DSC
);
1026 // Go through our list of firmware volumes and create an "fvs" target that
1027 // builds everything. It has to be a mix of components and FV's in order.
1028 // For example: fvs : components_0 fv\fv001.fv fv\fv002.fv components_1 fv\fv003.fv
1030 ComponentsInstance
= 0;
1032 fprintf (MakeFptr
, "fvs ::");
1035 // First see if we have any components for this section. If we don't,
1038 for (FileListPtr
= mFileList
; FileListPtr
!= NULL
; FileListPtr
= FileListPtr
->Next
) {
1039 if (FileListPtr
->ComponentsInstance
== ComponentsInstance
) {
1044 if (FileListPtr
== NULL
) {
1048 fprintf (MakeFptr
, " components_%d", ComponentsInstance
);
1051 // Now print any firmware volumes that match this components instance
1053 for (FVPtr
= mFVList
; FVPtr
!= NULL
; FVPtr
= FVPtr
->Next
) {
1054 if (FVPtr
->ComponentsInstance
== ComponentsInstance
) {
1055 fprintf (MakeFptr
, " %s%s.fv", FVDir
, FVPtr
->FVFileName
);
1059 ComponentsInstance
++;
1062 fprintf (MakeFptr
, "\n\n");
1065 // Create a "components" target for build convenience. It should
1066 // look something like:
1067 // components : components_0 components_1...
1069 if (ComponentCount
> 0) {
1070 fprintf (MakeFptr
, "components :");
1071 for (ComponentsInstance
= 0; ComponentsInstance
< ComponentCount
; ComponentsInstance
++) {
1072 fprintf (MakeFptr
, " components_%d", ComponentsInstance
);
1075 fprintf (MakeFptr
, "\n\n");
1078 // Now go through the list of all FV's defined and search for
1079 // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the
1083 while (FVPtr
!= NULL
) {
1084 if (FVPtr
->FVFileName
[0]) {
1086 // Save the position in the file
1088 DSCFileSavePosition (DSC
);
1090 // First try to find a build section specific for this FV.
1092 sprintf (Str
, "build.fv.%s", FVPtr
->FVFileName
);
1093 Section
= DSCFileFindSection (DSC
, Str
);
1094 if (Section
== NULL
) {
1095 sprintf (Str
, "build.fv");
1096 Section
= DSCFileFindSection (DSC
, Str
);
1099 if (Section
== NULL
) {
1105 "no [build.fv.%s] nor [%s] section found in description file for building %s",
1112 // Add a symbol for the FV filename
1114 UpperCaseString (FVPtr
->FVFileName
);
1115 AddSymbol (FV_FILENAME
, FVPtr
->FVFileName
, SYM_LOCAL
| SYM_OVERWRITE
);
1116 AddSymbol (EFI_BASE_ADDRESS
, FVPtr
->BaseAddress
, SYM_LOCAL
| SYM_OVERWRITE
);
1119 // Now copy the build commands from the section to the makefile
1121 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1125 sizeof (ExpandedLine
),
1126 EXPANDMODE_NO_DESTDIR
| EXPANDMODE_NO_SOURCEDIR
1128 fprintf (MakeFptr
, ExpandedLine
);
1132 DSCFileRestorePosition (DSC
);
1135 FVPtr
= FVPtr
->Next
;
1138 // Close all the files and free up the memory
1140 while (FVList
!= NULL
) {
1141 FVPtr
= FVList
->Next
;
1142 if (FVList
->FVFilePtr
!= NULL
) {
1143 SmartClose (FVList
->FVFilePtr
);
1146 if (FVList
->AprioriFilePtr
!= NULL
) {
1147 SmartClose (FVList
->AprioriFilePtr
);
1154 while (mNonFfsFVList
!= NULL
) {
1155 FVPtr
= mNonFfsFVList
->Next
;
1156 free (mNonFfsFVList
);
1157 mNonFfsFVList
= FVPtr
;
1160 if (XRefFptr
!= NULL
) {
1164 return STATUS_SUCCESS
;
1168 NonFFSFVWriteInfFiles (
1174 Routine Description:
1176 Generate a Non FFS fv file. It can only some variables,
1177 or simply contains nothing except header.
1181 DSC - pointer to a DSC_FILE object to extract info from
1182 FileName - pointer to the fv file
1186 STATUS_SUCCESS if successful
1187 non-STATUS_SUCCESS otherwise
1197 char Line
[MAX_LINE_LEN
];
1198 char ExpandedLine
[MAX_LINE_LEN
];
1199 char FVDir
[MAX_PATH
];
1202 // See if they specified a FV directory to dump the FV files out to. If not,
1203 // then use the default. Then create the output directory.
1205 DSCFileSavePosition (DSC
);
1206 StartCptr
= GetSymbolValue (FV_INF_DIR
);
1207 if (StartCptr
== NULL
) {
1208 ExpandSymbols (DEFAULT_FV_INF_DIR
, FVDir
, sizeof (FVDir
), EXPANDMODE_NO_UNDEFS
);
1210 strcpy (FVDir
, StartCptr
);
1214 // Make sure the fv directory path ends in /
1216 CSave
= FVDir
[strlen (FVDir
) - 1];
1217 if ((CSave
!= '\\') && (CSave
!= '/')) {
1218 strcat (FVDir
, "\\");
1221 StartCptr
= FileName
;
1222 while (*StartCptr
) {
1223 EndCptr
= StartCptr
;
1224 while (*EndCptr
&& (*EndCptr
!= ',')) {
1231 // Ok, we have a fv name, now see if we've already opened
1232 // an fv output file of this name.
1234 for (FVPtr
= mNonFfsFVList
; FVPtr
!= NULL
; FVPtr
= FVPtr
->Next
) {
1235 if (_stricmp (FVPtr
->FVFileName
, StartCptr
) == 0) {
1240 // If there is already one with the same name, wrong
1242 if (FVPtr
!= NULL
) {
1243 DSCFileRestorePosition (DSC
);
1244 return STATUS_ERROR
;
1247 // Create a new one, add it to the list
1249 FVPtr
= (FV_LIST
*) malloc (sizeof (FV_LIST
));
1250 if (FVPtr
== NULL
) {
1251 Error (__FILE__
, __LINE__
, 0, "failed to allocate memory", NULL
);
1252 DSCFileRestorePosition (DSC
);
1253 return STATUS_ERROR
;
1256 memset ((char *) FVPtr
, 0, sizeof (FV_LIST
));
1257 FVPtr
->Next
= mNonFfsFVList
;
1258 mNonFfsFVList
= FVPtr
;
1260 // Save the FV name in the FileName pointer so we can compare
1261 // for any future FV names specified.
1263 strcpy (FVPtr
->FVFileName
, StartCptr
);
1265 // Add a symbol for the FV filename
1267 UpperCaseString (FVPtr
->FVFileName
);
1268 AddSymbol (FV_FILENAME
, FVPtr
->FVFileName
, SYM_LOCAL
| SYM_OVERWRITE
);
1271 // Now create the FVx.inf filename from the fv name and
1272 // default filename extension. Dump it in the FV directory
1275 strcpy (Str
, FVDir
);
1276 strcat (Str
, FVPtr
->FVFileName
);
1277 strcat (Str
, ".inf");
1279 // Create the directory path for our new fv.inf output file.
1282 if ((FVPtr
->FVFilePtr
= SmartOpen (Str
)) == NULL
) {
1283 Error (NULL
, 0, 0, Str
, "could not open FV output file");
1284 DSCFileRestorePosition (DSC
);
1285 return STATUS_ERROR
;
1288 // Now copy the [fv.fvfile.options] to the fv file
1290 sprintf (Str
, "fv.%s.options", StartCptr
);
1291 Section
= DSCFileFindSection (DSC
, Str
);
1292 if (Section
!= NULL
) {
1293 SmartWrite (FVPtr
->FVFilePtr
, "[options]\n");
1294 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1295 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
1296 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
1297 GetBaseAddress (ExpandedLine
, FVPtr
->BaseAddress
);
1300 Warning (NULL
, 0, 0, NULL
, "Could not find FV section '%s' in description file", Str
);
1303 // Copy the [fv.fvfile.attributes] to the fv file
1305 sprintf (Str
, "fv.%s.attributes", StartCptr
);
1306 Section
= DSCFileFindSection (DSC
, Str
);
1307 if (Section
!= NULL
) {
1308 SmartWrite (FVPtr
->FVFilePtr
, "[attributes]\n");
1309 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1310 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
1311 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
1314 Warning (NULL
, 0, 0, NULL
, "Could not find FV section '%s' in description file", Str
);
1317 // Copy the [fv.fvfile.components] to the fv file
1319 sprintf (Str
, "fv.%s.components", StartCptr
);
1320 Section
= DSCFileFindSection (DSC
, Str
);
1321 if (Section
!= NULL
) {
1322 SmartWrite (FVPtr
->FVFilePtr
, "[components]\n");
1323 while (DSCFileGetLine (DSC
, Line
, sizeof (Line
)) != NULL
) {
1324 ExpandSymbols (Line
, ExpandedLine
, sizeof (ExpandedLine
), 0);
1325 SmartWrite (FVPtr
->FVFilePtr
, ExpandedLine
);
1329 // An empty FV is allowed to contain nothing
1335 SmartClose (FVPtr
->FVFilePtr
);
1337 // Next FV in FileName
1340 StartCptr
= EndCptr
;
1346 DSCFileRestorePosition (DSC
);
1347 return STATUS_SUCCESS
;
1352 AddFirmwareVolumes (
1354 int ComponentsInstance
,
1355 FILE_LIST
*FileListPtr
1363 if ((FVs
!= NULL
) && (FVs
[0] != 0)) {
1365 // Extract each FV name from the string. It's from the DSC file "FV=FvRecover,FvMain"
1368 while (*StartPtr
!= 0) {
1370 while (*EndPtr
&& (*EndPtr
!= ',')) {
1377 // Look through our list of known firmware volumes and see if we've
1378 // already added it.
1380 for (FvPtr
= mFVList
; FvPtr
!= NULL
; FvPtr
= FvPtr
->Next
) {
1381 if (_stricmp (FvPtr
->FVFileName
, StartPtr
) == 0) {
1386 // If we didn't find a match, then create a new one
1388 if (FvPtr
== NULL
) {
1389 FvPtr
= MALLOC (sizeof (FV_LIST
));
1390 if (FvPtr
== NULL
) {
1391 Error (__FILE__
, __LINE__
, 0, "application error", "memory allocation failed");
1395 memset (FvPtr
, 0, sizeof (FV_LIST
));
1396 strcpy (FvPtr
->FVFileName
, StartPtr
);
1397 if (mFVList
== NULL
) {
1400 mFVListLast
->Next
= FvPtr
;
1403 mFVListLast
= FvPtr
;
1406 // If this component's section number is higher than that of this
1407 // FV, then set the FV's to it.
1409 if (FvPtr
->ComponentsInstance
< ComponentsInstance
) {
1410 FvPtr
->ComponentsInstance
= ComponentsInstance
;
1413 // If we found then end of the FVs in the string, then we're done.
1414 // Always restore the original string's contents.
1416 if (SaveChar
!= 0) {
1418 StartPtr
= EndPtr
+ 1;
1435 // Given FvList of format "FV_a,FV_b,FV_c" or "FV_a:1,FV_b:2" and
1436 // FvName of format "FV_c", determine if FvName is in FvList. If
1437 // FV_a:1 format, then return the value after the colon.
1441 // If it matches for the length of FvName...
1443 if (_strnicmp (FvList
, FvName
, strlen (FvName
)) == 0) {
1445 // Then see if the match string in FvList is terminated at the
1448 if ((FvList
[strlen (FvName
)] == ',') || (FvList
[strlen (FvName
)] == 0)) {
1451 } else if (FvList
[strlen (FvName
)] == ':') {
1452 *Order
= atoi (FvList
+ strlen (FvName
) + 1);
1457 // Skip to next FV in the comma-separated list
1459 while ((*FvList
!= ',') && (*FvList
!= 0)) {
1465 if (*FvList
== ',') {
1481 for (Cptr
= Str
; *Cptr
; Cptr
++) {
1482 *Cptr
= (char) toupper (*Cptr
);
1503 // Process each FV in first FV list
1506 while (*StartCptr1
) {
1507 EndCptr1
= StartCptr1
;
1508 while (*EndCptr1
&& (*EndCptr1
!= ',')) {
1517 // Process each FV in second FV list
1520 while (*StartCptr2
) {
1521 EndCptr2
= StartCptr2
;
1522 while (*EndCptr2
&& (*EndCptr2
!= ',')) {
1529 if (_stricmp (StartCptr1
, StartCptr2
) == 0) {
1536 // Next FV on the second FV list
1539 StartCptr2
= EndCptr2
;
1547 // Next FV on the first FV list
1550 StartCptr1
= EndCptr1
;
1560 CFVSetXRefFileName (
1564 mXRefFileName
= FileName
;