summaryrefslogtreecommitdiff
path: root/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c
diff options
context:
space:
mode:
Diffstat (limited to 'EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c')
-rw-r--r--EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c1566
1 files changed, 1566 insertions, 0 deletions
diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c
new file mode 100644
index 0000000000..28baf5551b
--- /dev/null
+++ b/EdkCompatibilityPkg/Sample/Tools/Source/ProcessDsc/FWVolume.c
@@ -0,0 +1,1566 @@
+/*++
+
+Copyright (c) 2004 - 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ FWVolume.c
+
+Abstract:
+
+ This module contains functionality to keep track of files destined for
+ multiple firmware volues. It saves them up, and when told to, dumps the
+ file names out to some files used as input to other utilities that
+ actually generate the FVs.
+
+--*/
+
+#include <windows.h> // for max_path definition
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h> // for malloc()
+#include "Common.h"
+#include "DSCFile.h"
+#include "FWVolume.h"
+
+#define FV_INF_DIR "FV_INF_DIR" // symbol for where we create the FV INF file
+#define FV_FILENAME "FV_FILENAME" // symbol for the current FV.INF filename
+#define EFI_BASE_ADDRESS "EFI_BASE_ADDRESS"
+#define DEFAULT_FV_INF_DIR "FV" // default dir for where we create the FV INF file
+#define DEFAULT_FV_DIR "$(BUILD_DIR)" // where the FV file comes from
+#define MALLOC(size) malloc (size)
+#define FREE(ptr) free (ptr)
+
+//
+// Disable warning for unused function arguments
+//
+#pragma warning(disable : 4100)
+//
+// Disable warning for while(1) code
+//
+// #pragma warning (disable : 4127)
+//
+typedef struct {
+ char *ComponentType;
+ char *Extension;
+} COMP_TYPE_EXTENSION;
+
+//
+// Use a linked list of these to keep track of all the FV names used
+//
+typedef struct _FV_LIST {
+ struct _FV_LIST *Next;
+ char FVFileName[MAX_PATH];
+ char BaseAddress[MAX_LINE_LEN];
+ SMART_FILE *FVFilePtr;
+ SMART_FILE *AprioriFilePtr;
+ char *Processor;
+ int ComponentsInstance; // highest [components.n] section with a file for this FV
+} FV_LIST;
+
+//
+// Use a linked list of these to keep track of all FFS files built. When
+// we're done, we turn the info into the FV INF files used to build the
+// firmware volumes.
+//
+typedef struct _FILE_LIST {
+ struct _FILE_LIST *Next;
+ char *FileName;
+ char *BaseFileName;
+ char *FVs; // from FV=x,y,z
+ char *BaseName; // only needed for duplicate basename check
+ char *Processor; // only needed for duplicate basename check
+ char Apriori[100]; // of format "FVRecovery:1,FVMain:2" from APRIORI define
+ char *Guid; // guid string
+ int ComponentsInstance; // which [components.n] section it's in
+} FILE_LIST;
+
+typedef struct _LINKED_LIST {
+ struct _LINKED_LIST *Next;
+ void *Data;
+} LINKED_LIST;
+
+static FILE_LIST *mFileList;
+static FILE_LIST *mLastFile;
+static char *mXRefFileName = NULL;
+static FV_LIST *mNonFfsFVList = NULL;
+
+//
+// Whenever an FV name is referenced, then add it to our list of known
+// FV's using these.
+//
+static FV_LIST *mFVList = NULL;
+static FV_LIST *mFVListLast = NULL;
+
+//
+// We use this list so that from a given component type, we can determine
+// the name of the file on disk. For example, if we're given a file's
+// guid and base name, and we know it's a "bs_driver", then we can look
+// up "bs_driver" in this array and know that the file (after it's built)
+// name is GUID-BASENAME.DXE
+//
+static const COMP_TYPE_EXTENSION mCompTypeExtension[] = {
+ {
+ "bs_driver",
+ ".dxe"
+ },
+ {
+ "rt_driver",
+ ".dxe"
+ },
+ {
+ "sal_rt_driver",
+ ".dxe"
+ },
+ {
+ "security_core",
+ ".sec"
+ },
+ {
+ "pei_core",
+ ".pei"
+ },
+ {
+ "pic_peim",
+ ".pei"
+ },
+ {
+ "pe32_peim",
+ ".pei"
+ },
+ {
+ "relocatable_peim",
+ ".pei"
+ },
+ {
+ "binary",
+ ".ffs"
+ },
+ {
+ "application",
+ ".app"
+ },
+ {
+ "file",
+ ".ffs"
+ },
+ {
+ "fvimagefile",
+ ".fvi"
+ },
+ {
+ "rawfile",
+ ".raw"
+ },
+ {
+ "apriori",
+ ".ffs"
+ },
+ {
+ "combined_peim_driver",
+ ".pei"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+static
+void
+CFVFreeFileList (
+ VOID
+ );
+
+static
+char *
+UpperCaseString (
+ char *Str
+ );
+
+static
+BOOLEAN
+InSameFv (
+ char *FVs1,
+ char *FVs2
+);
+
+static
+void
+AddFirmwareVolumes (
+ char *FVs,
+ int ComponentsInstance,
+ FILE_LIST *FileListPtr
+ );
+
+static
+BOOLEAN
+OrderInFvList (
+ char *FvList,
+ char *FvName,
+ int *Order
+ );
+
+int
+GetBaseAddress (
+ char *Name,
+ char *BaseAddress
+ )
+{
+ char *Start;
+ char *Cptr;
+ char CSave;
+ char *Value;
+
+ Start = Name;
+ while (*Name && isspace (*Name)) {
+ Name++;
+ }
+
+ if (!*Name) {
+ return STATUS_ERROR;
+ }
+ //
+ // Find the end of the name. Either space or a '='.
+ //
+ for (Value = Name; *Value && !isspace (*Value) && (*Value != '='); Value++)
+ ;
+ if (!*Value) {
+ return STATUS_ERROR;
+ }
+ //
+ // Look for the '='
+ //
+ Cptr = Value;
+ while (*Value && (*Value != '=')) {
+ Value++;
+ }
+
+ if (!*Value) {
+ return STATUS_ERROR;
+ }
+ //
+ // Now truncate the name
+ //
+ CSave = *Cptr;
+ *Cptr = 0;
+ if (_stricmp (Name, EFI_BASE_ADDRESS) != 0) {
+ return STATUS_ERROR;
+ }
+
+ *Cptr = CSave;
+ //
+ // Skip over the = and then any spaces
+ //
+ Value++;
+ while (*Value && isspace (*Value)) {
+ Value++;
+ }
+ //
+ // Find end of string, checking for quoted string
+ //
+ if (*Value == '\"') {
+ Value++;
+ for (Cptr = Value; *Cptr && *Cptr != '\"'; Cptr++)
+ ;
+ } else {
+ for (Cptr = Value; *Cptr && !isspace (*Cptr); Cptr++)
+ ;
+ }
+ //
+ // Null terminate the value string
+ //
+ CSave = *Cptr;
+ *Cptr = 0;
+ strcpy (BaseAddress, Value);
+ *Cptr = CSave;
+
+ return STATUS_SUCCESS;
+}
+
+int
+CFVAddFVFile (
+ char *Name,
+ char *ComponentType,
+ char *FVs,
+ int ComponentsInstance,
+ char *FFSExt,
+ char *Processor,
+ char *Apriori,
+ char *BaseName,
+ char *Guid
+ )
+/*++
+
+Routine Description:
+
+ Add a file to the list of files in one or more firmware volumes.
+
+Arguments:
+
+ Name - $(FILE_GUID)-$(BASE_NAME), or filename
+ ComponentType - type of component being added. Required so we know the
+ resultant file name after it has been built
+ FVs - string of commma-separated FVs that the given file is
+ to be added to. For example, FVs="FV0001,FV0002"
+ FFSExt - FFS filename extension of the file after it has been built.
+ This is passed in to us in case we don't know the default
+ filename extension based on the component type.
+ Processor - the target processor which the FV is being built for
+ Apriori - pointer to the definition of APRIORI. For example APRIORI="FvRecovery:1,FvMain:4"
+
+Returns:
+
+ STATUS_SUCCESS if successful
+
+--*/
+{
+ FILE_LIST *Ptr;
+ char FileName[MAX_PATH];
+ char Str[MAX_PATH];
+ int i;
+ char *Sym;
+
+ // If they provided a filename extension for this type of file, then use it.
+ // If they did not provide a filename extension, search our list for a
+ // matching component type and use the extension appropriate for this
+ // component type.
+ //
+ if (FFSExt == NULL) {
+ //
+ // They didn't give us a filename extension. Figure it out from the
+ // component type.
+ //
+ for (i = 0; mCompTypeExtension[i].ComponentType != NULL; i++) {
+ if (_stricmp (ComponentType, mCompTypeExtension[i].ComponentType) == 0) {
+ FFSExt = mCompTypeExtension[i].Extension;
+ break;
+ }
+ }
+ //
+ // If we don't know the file extension, then error out. Just means
+ // the need to define "FFS_EXT = raw" in the component INF file.
+ //
+ if (mCompTypeExtension[i].ComponentType == NULL) {
+ Error (
+ NULL,
+ 0,
+ 0,
+ ComponentType,
+ "unknown component type - must define FFS_EXT for built filename extension in component INF file"
+ );
+ return STATUS_ERROR;
+ }
+ }
+ //
+ // We now have all the parts to the FFS filename. Prepend the path to it if
+ // it's not a full pathname.
+ // See if they overrode the default base directory for the FV files.
+ //
+ if (!IsAbsolutePath (Name)) {
+ Sym = GetSymbolValue (FV_DIR);
+ if (Sym == NULL) {
+ Sym = DEFAULT_FV_DIR;
+ }
+ //
+ // Create the file path. Something like $(BUILD_DIR)\$(PROCESSOR)\$(GUID)-$(BASE_NAME).ext
+ // If the extension is non-zero length, then make sure there's a dot in it.
+ //
+ if ((strlen (FFSExt) > 0) && (FFSExt[0] != '.')) {
+ sprintf (Str, "%s\\%s\\%s.%s", Sym, Processor, Name, FFSExt);
+ } else {
+ sprintf (Str, "%s\\%s\\%s%s", Sym, Processor, Name, FFSExt);
+ }
+
+ ExpandSymbols (Str, FileName, sizeof (FileName), EXPANDMODE_NO_UNDEFS);
+ } else {
+ strcpy (FileName, Name);
+ }
+ //
+ // Traverse the list of files we have so far and make sure we don't have
+ // any duplicate basenames. If the base name and processor match, then we'll
+ // have build issues, so don't allow it. We also don't allow the same file GUID
+ // in the same FV which will cause boot time error if we allow this.
+ //
+ Ptr = mFileList;
+ while (Ptr != NULL) {
+ if ((Ptr->BaseName != NULL) && (BaseName != NULL) && (_stricmp (BaseName, Ptr->BaseName) == 0)) {
+ if ((Ptr->Processor != NULL) && (Processor != NULL) && (_stricmp (Processor, Ptr->Processor) == 0)) {
+ Error (NULL, 0, 0, BaseName, "duplicate base name specified");
+ return STATUS_ERROR;
+ }
+ }
+
+ if ((Ptr->Guid != NULL) && (Guid != NULL) && (_stricmp (Guid, Ptr->Guid) == 0)) {
+ if ((Ptr->FVs != NULL) && (FVs != NULL) && (InSameFv (FVs, Ptr->FVs))) {
+ Error (NULL, 0, 0, Guid, "duplicate Guid specified in the same FV for %s and %s",
+ (Ptr->BaseName==NULL)?"Unknown":Ptr->BaseName,
+ (BaseName==NULL)?"Unknown":BaseName);
+ return STATUS_ERROR;
+ }
+ }
+
+ Ptr = Ptr->Next;
+ }
+ //
+ // Allocate a new structure so we can add this file to the list of
+ // files.
+ //
+ Ptr = (FILE_LIST *) malloc (sizeof (FILE_LIST));
+ if (Ptr == NULL) {
+ Error (NULL, 0, 0, NULL, "failed to allocate memory");
+ return STATUS_ERROR;
+ }
+
+ memset ((char *) Ptr, 0, sizeof (FILE_LIST));
+ Ptr->FileName = (char *) malloc (strlen (FileName) + 1);
+ if (Ptr->FileName == NULL) {
+ Error (NULL, 0, 0, NULL, "failed to allocate memory");
+ return STATUS_ERROR;
+ }
+
+ strcpy (Ptr->FileName, FileName);
+ Ptr->ComponentsInstance = ComponentsInstance;
+ //
+ // Allocate memory to save the FV list if it's going into an FV.
+ //
+ if ((FVs != NULL) && (FVs[0] != 0)) {
+ Ptr->FVs = (char *) malloc (strlen (FVs) + 1);
+ if (Ptr->FVs == NULL) {
+ Error (NULL, 0, 0, NULL, "failed to allocate memory");
+ return STATUS_ERROR;
+ }
+
+ strcpy (Ptr->FVs, FVs);
+ }
+
+ Ptr->BaseFileName = (char *) malloc (strlen (Name) + 1);
+ if (Ptr->BaseFileName == NULL) {
+ Error (NULL, 0, 0, NULL, "failed to allocate memory");
+ return STATUS_ERROR;
+ }
+
+ strcpy (Ptr->BaseFileName, Name);
+ //
+ // Allocate memory for the basename if they gave us one. May not have one
+ // if the user is simply adding pre-existing binary files to the image.
+ //
+ if (BaseName != NULL) {
+ Ptr->BaseName = (char *) malloc (strlen (BaseName) + 1);
+ if (Ptr->BaseName == NULL) {
+ Error (NULL, 0, 0, NULL, "failed to allocate memory");
+ return STATUS_ERROR;
+ }
+
+ strcpy (Ptr->BaseName, BaseName);
+ }
+ //
+ // Allocate memory for the processor name
+ //
+ if (Processor != NULL) {
+ Ptr->Processor = (char *) malloc (strlen (Processor) + 1);
+ if (Ptr->Processor == NULL) {
+ Error (NULL, 0, 0, NULL, "failed to allocate memory");
+ return STATUS_ERROR;
+ }
+
+ strcpy (Ptr->Processor, Processor);
+ }
+ //
+ // Allocate memory for the guid name
+ //
+ if (Guid != NULL) {
+ Ptr->Guid = (char *) malloc (strlen (Guid) + 1);
+ if (Ptr->Guid == NULL) {
+ Error (NULL, 0, 0, NULL, "failed to allocate memory");
+ return STATUS_ERROR;
+ }
+
+ strcpy (Ptr->Guid, Guid);
+ }
+ //
+ // If non-null apriori symbol, then save the apriori list for this file
+ //
+ if (Apriori != NULL) {
+ strcpy (Ptr->Apriori, Apriori);
+ }
+
+ if (mFileList == NULL) {
+ mFileList = Ptr;
+ } else {
+ mLastFile->Next = Ptr;
+ }
+
+ mLastFile = Ptr;
+ //
+ // Add these firmware volumes to the list of known firmware
+ // volume names.
+ //
+ AddFirmwareVolumes (FVs, ComponentsInstance, Ptr);
+
+ return STATUS_SUCCESS;
+}
+
+void
+CFVConstructor (
+ VOID
+ )
+{
+ mFileList = NULL;
+ mLastFile = NULL;
+}
+
+void
+CFVDestructor (
+ VOID
+ )
+{
+ CFVFreeFileList ();
+ //
+ // Free up our firmware volume list
+ //
+ while (mFVList != NULL) {
+ mFVListLast = mFVList->Next;
+ FREE (mFVList);
+ mFVList = mFVListLast;
+ }
+}
+
+static
+void
+CFVFreeFileList (
+ VOID
+ )
+{
+ FILE_LIST *Next;
+ while (mFileList != NULL) {
+ if (mFileList->FileName != NULL) {
+ free (mFileList->FileName);
+ }
+
+ if (mFileList->FVs != NULL) {
+ free (mFileList->FVs);
+ }
+
+ free (mFileList->BaseFileName);
+ if (mFileList->BaseName != NULL) {
+ free (mFileList->BaseName);
+ }
+
+ if (mFileList->Processor != NULL) {
+ free (mFileList->Processor);
+ }
+
+ if (mFileList->Guid != NULL) {
+ free (mFileList->Guid);
+ }
+
+ Next = mFileList->Next;
+ free (mFileList);
+ mFileList = Next;
+ }
+
+ mFileList = NULL;
+}
+
+int
+CFVWriteInfFiles (
+ DSC_FILE *DSC,
+ FILE *MakeFptr
+ )
+/*++
+
+Routine Description:
+
+ After processing all components in a DSC file, create the firmware
+ volume INF files. We actually do a lot more here.
+
+ * Create the FVxxx.inf file that is used by GenFvImage
+ * Create the Apriori files for each firmware volume that requires one
+ * Create makefile.out macros for FVxxx_FILES = FVxxx_FILES AnotherFile
+ so you can do incremental builds of firmware volumes.
+ * For each FV, emit its build commands to makefile.out
+
+Arguments:
+
+ DSC - pointer to a DSC_FILE object to extract info from
+ MakeFptr - pointer to the output makefile
+
+Returns:
+
+ 0 if successful
+ non-zero otherwise
+
+--*/
+{
+ FILE_LIST *FileListPtr;
+ FV_LIST *FVList;
+ FV_LIST *LastFVList;
+ FV_LIST *FVPtr;
+ SECTION *Section;
+ char *StartCptr;
+ char *EndCptr;
+ char CSave;
+ char Str[MAX_PATH];
+ char Line[MAX_LINE_LEN];
+ char ExpandedLine[MAX_LINE_LEN];
+ char FVDir[MAX_PATH];
+ FILE *XRefFptr;
+ int AprioriCounter;
+ int AprioriCount;
+ int AprioriPosition;
+ BOOLEAN AprioriFound;
+ int ComponentsInstance;
+ int ComponentCount;
+
+ //
+ // Use this to keep track of all the firmware volume names
+ //
+ FVList = NULL;
+ LastFVList = NULL;
+ //
+ // See if they specified a FV directory to dump the FV files out to. If not,
+ // then use the default. Then create the output directory.
+ //
+ StartCptr = GetSymbolValue (FV_INF_DIR);
+ if (StartCptr == NULL) {
+ ExpandSymbols (DEFAULT_FV_INF_DIR, FVDir, sizeof (FVDir), EXPANDMODE_NO_UNDEFS);
+ } else {
+ strcpy (FVDir, StartCptr);
+ }
+ //
+ // Make sure the fv directory path ends in /
+ //
+ CSave = FVDir[strlen (FVDir) - 1];
+ if ((CSave != '\\') && (CSave != '/')) {
+ strcat (FVDir, "\\");
+ }
+ //
+ // Traverse the list of all files, determine which FV each is in, then
+ // write out the file's name to the output FVxxx.inf file.
+ //
+ for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
+ //
+ // Parse all the "FV1,FV2..." in the FVs
+ //
+ if (FileListPtr->FVs != NULL) {
+ //
+ // Process each fv this file is in
+ //
+ StartCptr = FileListPtr->FVs;
+ while (*StartCptr) {
+ EndCptr = StartCptr;
+ while (*EndCptr && (*EndCptr != ',')) {
+ EndCptr++;
+ }
+
+ CSave = *EndCptr;
+ *EndCptr = 0;
+ //
+ // Ok, we have a fv name, now see if we've already opened
+ // an fv output file of this name.
+ //
+ for (FVPtr = FVList; FVPtr != NULL; FVPtr = FVPtr->Next) {
+ if (_stricmp (FVPtr->FVFileName, StartCptr) == 0) {
+ break;
+ }
+ }
+ //
+ // If we didn't find one, then create a new one
+ //
+ if (FVPtr == NULL) {
+ //
+ // Create a new one, add it to the list
+ //
+ FVPtr = (FV_LIST *) malloc (sizeof (FV_LIST));
+ if (FVPtr == NULL) {
+ Error (NULL, 0, 0, NULL, "failed to allocate memory for FV");
+ return STATUS_ERROR;
+ }
+
+ memset ((char *) FVPtr, 0, sizeof (FV_LIST));
+ //
+ // Add it to the end of our list
+ //
+ if (FVList == NULL) {
+ FVList = FVPtr;
+ } else {
+ LastFVList->Next = FVPtr;
+ }
+
+ LastFVList = FVPtr;
+ //
+ // Save the FV name in the FileName pointer so we can compare
+ // for any future FV names specified.
+ //
+ strcpy (FVPtr->FVFileName, StartCptr);
+
+ //
+ // Add a symbol for the FV filename
+ //
+ UpperCaseString (FVPtr->FVFileName);
+ AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);
+ //
+ // Now create the FVx.inf filename from the fv name and
+ // default filename extension. Dump it in the FV directory
+ // as well.
+ //
+ strcpy (Str, FVDir);
+ strcat (Str, FVPtr->FVFileName);
+ strcat (Str, ".inf");
+ //
+ // Create the directory path for our new fv.inf output file.
+ //
+ MakeFilePath (Str);
+ if ((FVPtr->FVFilePtr = SmartOpen (Str)) == NULL) {
+ Error (NULL, 0, 0, Str, "could not open FV output file");
+ return STATUS_ERROR;
+ }
+ //
+ // Now copy the [fv.$(FV).options] to the fv INF file
+ //
+ sprintf (Str, "fv.%s.options", StartCptr);
+ Section = DSCFileFindSection (DSC, Str);
+ if (Section != NULL) {
+ SmartWrite (FVPtr->FVFilePtr, "[options]\n");
+ while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
+ ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
+ SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
+ GetBaseAddress (ExpandedLine, FVPtr->BaseAddress);
+ }
+ } else {
+ Error (NULL, 0, 0, Str, "could not find FV section in description file");
+ }
+ //
+ // Copy the [fv.$(FV).attributes] to the fv INF file
+ //
+ sprintf (Str, "fv.%s.attributes", StartCptr);
+ Section = DSCFileFindSection (DSC, Str);
+ if (Section != NULL) {
+ SmartWrite (FVPtr->FVFilePtr, "[attributes]\n");
+ while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
+ ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
+ SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
+ }
+ } else {
+ Error (NULL, 0, 0, Str, "Could not find FV section in description file");
+ }
+ //
+ // Start the files section
+ //
+ SmartWrite (FVPtr->FVFilePtr, "\n[files]\n");
+ }
+ //
+ // Now write the FV filename to the FV.inf file. Prepend $(PROCESSOR) on
+ // it.
+ //
+ sprintf (ExpandedLine, "EFI_FILE_NAME = %s\n", FileListPtr->FileName);
+ SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
+
+ //
+ // Next FV on the FV list
+ //
+ *EndCptr = CSave;
+ StartCptr = EndCptr;
+ if (*StartCptr) {
+ StartCptr++;
+ }
+ }
+ }
+ }
+ //
+ // Now we walk the list of firmware volumes and create the APRIORI list
+ // file for it .
+ //
+ for (FVPtr = FVList; FVPtr != NULL; FVPtr = FVPtr->Next) {
+ //
+ // Run through all the files and count up how many are to be
+ // added to the apriori list for this FV. Then when we're done
+ // we'll make sure we processed them all. We do this in case they
+ // skipped an apriori index for a given FV.
+ //
+ AprioriCount = 0;
+ for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
+ if (OrderInFvList (FileListPtr->Apriori, FVPtr->FVFileName, &AprioriPosition)) {
+ //
+ // Emit an error if the index was 0, or they didn't give one.
+ //
+ if (AprioriPosition == 0) {
+ Error (
+ GetSymbolValue (DSC_FILENAME),
+ 1,
+ 0,
+ "apriori indexes are 1-based",
+ "component %s:APRIORI=%s",
+ FileListPtr->BaseName,
+ FileListPtr->Apriori
+ );
+ } else {
+ AprioriCount++;
+ }
+
+ }
+ }
+ //
+ // Now scan the files as we increment our apriori index
+ //
+ AprioriCounter = 0;
+ do {
+ AprioriFound = 0;
+ AprioriCounter++;
+ for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
+ //
+ // If in the apriori list for this fv, print the name. Open the
+ // file first if we have to.
+ //
+ if ((FileListPtr->Apriori[0] != 0) &&
+ (OrderInFvList (FileListPtr->Apriori, FVPtr->FVFileName, &AprioriPosition))
+ ) {
+ if (AprioriPosition == AprioriCounter) {
+ //
+ // If we've already found one for this index, emit an error. Decrement the
+ // count of how files we are to process so we don't emit another error for
+ // a miscount below.
+ //
+ if (AprioriFound) {
+ Error (
+ GetSymbolValue (DSC_FILENAME),
+ 1,
+ 0,
+ "duplicate apriori index found",
+ "%s:%d",
+ FVPtr->FVFileName,
+ AprioriCounter
+ );
+ AprioriCount--;
+ }
+
+ AprioriFound = 1;
+ //
+ // Open the apriori output file if we haven't already
+ //
+ if (FVPtr->AprioriFilePtr == NULL) {
+ strcpy (Str, FVDir);
+ strcat (Str, FVPtr->FVFileName);
+ strcat (Str, ".apr");
+ if ((FVPtr->AprioriFilePtr = SmartOpen (Str)) == NULL) {
+ Error (NULL, 0, 0, Str, "could not open output Apriori file for writing");
+ return STATUS_ERROR;
+ }
+ }
+
+ sprintf (ExpandedLine, "%s\n", FileListPtr->BaseFileName);
+ SmartWrite (FVPtr->AprioriFilePtr, ExpandedLine);
+ }
+ }
+ }
+ } while (AprioriFound);
+ //
+ // See if they skipped an apriori position for this FV
+ //
+ if (AprioriCount != (AprioriCounter - 1)) {
+ Error (
+ GetSymbolValue (DSC_FILENAME),
+ 1,
+ 0,
+ "apriori index skipped",
+ "%s:%d",
+ FVPtr->FVFileName,
+ AprioriCounter
+ );
+ }
+ }
+ //
+ // Traverse the list of all files again, and create a macro in the output makefile
+ // that defines all the files in each fv. For example, for each FV file, create a line:
+ // FV0001_FILES = $(FV_0001_FILES) xxxx-yyy.dxe.
+ // This can then be used as a dependency in their makefile.
+ // Also if they wanted us to dump a cross-reference, do that now.
+ //
+ if (mXRefFileName != NULL) {
+ if ((XRefFptr = fopen (mXRefFileName, "w")) == NULL) {
+ Message (
+ 0,
+ "Failed to open cross-reference file '%s' for writing\n",
+ mXRefFileName
+ );
+ }
+ } else {
+ XRefFptr = NULL;
+ }
+
+ for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
+ //
+ // Parse all the "FV1,FV2..." in the FV field that came from FV=FVa,FVb,... on the
+ // component line in the DSC file.
+ //
+ if (FileListPtr->FVs != NULL) {
+ //
+ // If generating a cross-reference file, dump the data
+ //
+ if (XRefFptr != NULL) {
+ if ((FileListPtr->Guid != NULL) && (FileListPtr->BaseName != NULL) && (FileListPtr->Processor)) {
+ fprintf (
+ XRefFptr,
+ "%s %s %s\n",
+ FileListPtr->Guid,
+ FileListPtr->BaseName,
+ FileListPtr->Processor
+ );
+ }
+ }
+ //
+ // Convert to uppercase since we're going to use the name as a macro variable name
+ // in the makefile.
+ //
+ UpperCaseString (FileListPtr->FVs);
+ //
+ // Process each FV this file is in to write fvxxx_FILES = $(fvxxx_FILES) Guid-BaseName.ffs
+ //
+ StartCptr = FileListPtr->FVs;
+ while (*StartCptr) {
+ EndCptr = StartCptr;
+ while (*EndCptr && (*EndCptr != ',')) {
+ EndCptr++;
+ }
+
+ CSave = *EndCptr;
+ *EndCptr = 0;
+ fprintf (
+ MakeFptr,
+ "%s_FILES = $(%s_FILES) %s\n",
+ StartCptr,
+ StartCptr,
+ FileListPtr->FileName
+ );
+ //
+ // Next FV on the FV list
+ //
+ *EndCptr = CSave;
+ StartCptr = EndCptr;
+ if (*StartCptr) {
+ StartCptr++;
+ }
+ }
+ }
+ }
+
+ fprintf (MakeFptr, "\n");
+
+ //
+ // Now go through the list of all NonFFS FVs they specified and search for
+ // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the
+ // output makefile. Add them to the "fvs" target as well.
+ //
+ if (mNonFfsFVList != NULL) {
+ fprintf (MakeFptr, "fvs ::");
+ FVPtr = mNonFfsFVList;
+ while (FVPtr != NULL) {
+ fprintf (MakeFptr, " %s%s.fv", FVDir, FVPtr->FVFileName);
+ FVPtr = FVPtr->Next;
+ }
+
+ fprintf (MakeFptr, "\n\n");
+ FVPtr = mNonFfsFVList;
+ while (FVPtr != NULL) {
+ //
+ // Save the position in the file
+ //
+ DSCFileSavePosition (DSC);
+ //
+ // first try to find a build section specific for this fv.
+ //
+ sprintf (Str, "build.fv.%s", FVPtr->FVFileName);
+ Section = DSCFileFindSection (DSC, Str);
+ if (Section == NULL) {
+ sprintf (Str, "build.fv");
+ Section = DSCFileFindSection (DSC, Str);
+ }
+
+ if (Section == NULL) {
+ Warning (
+ NULL,
+ 0,
+ 0,
+ NULL,
+ "No [build.fv.%s] nor [%s] section found in description file for building %s",
+ FVPtr->FVFileName,
+ Str,
+ FVPtr->FVFileName
+ );
+ } else {
+ //
+ // Add a symbol for the FV filename
+ //
+ UpperCaseString (FVPtr->FVFileName);
+ AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);
+ AddSymbol (EFI_BASE_ADDRESS, FVPtr->BaseAddress, SYM_LOCAL | SYM_OVERWRITE);
+
+ //
+ // Now copy the build commands from the section to the makefile
+ //
+ while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
+ ExpandSymbols (
+ Line,
+ ExpandedLine,
+ sizeof (ExpandedLine),
+ EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR
+ );
+
+ fprintf (MakeFptr, ExpandedLine);
+ }
+ }
+
+ FVPtr = FVPtr->Next;
+ DSCFileRestorePosition (DSC);
+ }
+ }
+ //
+ // Go through our list of firmware volumes and create an "fvs" target that
+ // builds everything. It has to be a mix of components and FV's in order.
+ // For example: fvs : components_0 fv\fv001.fv fv\fv002.fv components_1 fv\fv003.fv
+ //
+ ComponentsInstance = 0;
+ ComponentCount = 0;
+ fprintf (MakeFptr, "fvs ::");
+ for (;;) {
+ //
+ // First see if we have any components for this section. If we don't,
+ // then we're done
+ //
+ for (FileListPtr = mFileList; FileListPtr != NULL; FileListPtr = FileListPtr->Next) {
+ if (FileListPtr->ComponentsInstance == ComponentsInstance) {
+ break;
+ }
+ }
+
+ if (FileListPtr == NULL) {
+ break;
+ }
+
+ fprintf (MakeFptr, " components_%d", ComponentsInstance);
+ ComponentCount++;
+ //
+ // Now print any firmware volumes that match this components instance
+ //
+ for (FVPtr = mFVList; FVPtr != NULL; FVPtr = FVPtr->Next) {
+ if (FVPtr->ComponentsInstance == ComponentsInstance) {
+ fprintf (MakeFptr, " %s%s.fv", FVDir, FVPtr->FVFileName);
+ }
+ }
+
+ ComponentsInstance++;
+ }
+
+ fprintf (MakeFptr, "\n\n");
+
+ //
+ // Create a "components" target for build convenience. It should
+ // look something like:
+ // components : components_0 components_1...
+ //
+ if (ComponentCount > 0) {
+ fprintf (MakeFptr, "components :");
+ for (ComponentsInstance = 0; ComponentsInstance < ComponentCount; ComponentsInstance++) {
+ fprintf (MakeFptr, " components_%d", ComponentsInstance);
+ }
+
+ fprintf (MakeFptr, "\n\n");
+ }
+ //
+ // Now go through the list of all FV's defined and search for
+ // a [build.fv.$(FV)] or [build.fv] command and emit the commands to the
+ // output makefile.
+ //
+ FVPtr = mFVList;
+ while (FVPtr != NULL) {
+ if (FVPtr->FVFileName[0]) {
+ //
+ // Save the position in the file
+ //
+ DSCFileSavePosition (DSC);
+ //
+ // First try to find a build section specific for this FV.
+ //
+ sprintf (Str, "build.fv.%s", FVPtr->FVFileName);
+ Section = DSCFileFindSection (DSC, Str);
+ if (Section == NULL) {
+ sprintf (Str, "build.fv");
+ Section = DSCFileFindSection (DSC, Str);
+ }
+
+ if (Section == NULL) {
+ Error (
+ NULL,
+ 0,
+ 0,
+ NULL,
+ "no [build.fv.%s] nor [%s] section found in description file for building %s",
+ FVPtr->FVFileName,
+ Str,
+ FVPtr->FVFileName
+ );
+ } else {
+ //
+ // Add a symbol for the FV filename
+ //
+ UpperCaseString (FVPtr->FVFileName);
+ AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);
+ AddSymbol (EFI_BASE_ADDRESS, FVPtr->BaseAddress, SYM_LOCAL | SYM_OVERWRITE);
+
+ //
+ // Now copy the build commands from the section to the makefile
+ //
+ while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
+ ExpandSymbols (
+ Line,
+ ExpandedLine,
+ sizeof (ExpandedLine),
+ EXPANDMODE_NO_DESTDIR | EXPANDMODE_NO_SOURCEDIR
+ );
+ fprintf (MakeFptr, ExpandedLine);
+ }
+ }
+
+ DSCFileRestorePosition (DSC);
+ }
+
+ FVPtr = FVPtr->Next;
+ }
+ //
+ // Close all the files and free up the memory
+ //
+ while (FVList != NULL) {
+ FVPtr = FVList->Next;
+ if (FVList->FVFilePtr != NULL) {
+ SmartClose (FVList->FVFilePtr);
+ }
+
+ if (FVList->AprioriFilePtr != NULL) {
+ SmartClose (FVList->AprioriFilePtr);
+ }
+
+ free (FVList);
+ FVList = FVPtr;
+ }
+
+ while (mNonFfsFVList != NULL) {
+ FVPtr = mNonFfsFVList->Next;
+ free (mNonFfsFVList);
+ mNonFfsFVList = FVPtr;
+ }
+
+ if (XRefFptr != NULL) {
+ fclose (XRefFptr);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+int
+NonFFSFVWriteInfFiles (
+ DSC_FILE *DSC,
+ char *FileName
+ )
+/*++
+
+Routine Description:
+
+ Generate a Non FFS fv file. It can only some variables,
+ or simply contains nothing except header.
+
+Arguments:
+
+ DSC - pointer to a DSC_FILE object to extract info from
+ FileName - pointer to the fv file
+
+Returns:
+
+ STATUS_SUCCESS if successful
+ non-STATUS_SUCCESS otherwise
+
+--*/
+{
+ FV_LIST *FVPtr;
+ SECTION *Section;
+ char *StartCptr;
+ char *EndCptr;
+ char CSave;
+ char Str[MAX_PATH];
+ char Line[MAX_LINE_LEN];
+ char ExpandedLine[MAX_LINE_LEN];
+ char FVDir[MAX_PATH];
+
+ //
+ // See if they specified a FV directory to dump the FV files out to. If not,
+ // then use the default. Then create the output directory.
+ //
+ DSCFileSavePosition (DSC);
+ StartCptr = GetSymbolValue (FV_INF_DIR);
+ if (StartCptr == NULL) {
+ ExpandSymbols (DEFAULT_FV_INF_DIR, FVDir, sizeof (FVDir), EXPANDMODE_NO_UNDEFS);
+ } else {
+ strcpy (FVDir, StartCptr);
+ }
+
+ //
+ // Make sure the fv directory path ends in /
+ //
+ CSave = FVDir[strlen (FVDir) - 1];
+ if ((CSave != '\\') && (CSave != '/')) {
+ strcat (FVDir, "\\");
+ }
+
+ StartCptr = FileName;
+ while (*StartCptr) {
+ EndCptr = StartCptr;
+ while (*EndCptr && (*EndCptr != ',')) {
+ EndCptr++;
+ }
+
+ CSave = *EndCptr;
+ *EndCptr = 0;
+ //
+ // Ok, we have a fv name, now see if we've already opened
+ // an fv output file of this name.
+ //
+ for (FVPtr = mNonFfsFVList; FVPtr != NULL; FVPtr = FVPtr->Next) {
+ if (_stricmp (FVPtr->FVFileName, StartCptr) == 0) {
+ break;
+ }
+ }
+ //
+ // If there is already one with the same name, wrong
+ //
+ if (FVPtr != NULL) {
+ DSCFileRestorePosition (DSC);
+ return STATUS_ERROR;
+ }
+ //
+ // Create a new one, add it to the list
+ //
+ FVPtr = (FV_LIST *) malloc (sizeof (FV_LIST));
+ if (FVPtr == NULL) {
+ Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL);
+ DSCFileRestorePosition (DSC);
+ return STATUS_ERROR;
+ }
+
+ memset ((char *) FVPtr, 0, sizeof (FV_LIST));
+ FVPtr->Next = mNonFfsFVList;
+ mNonFfsFVList = FVPtr;
+ //
+ // Save the FV name in the FileName pointer so we can compare
+ // for any future FV names specified.
+ //
+ strcpy (FVPtr->FVFileName, StartCptr);
+ //
+ // Add a symbol for the FV filename
+ //
+ UpperCaseString (FVPtr->FVFileName);
+ AddSymbol (FV_FILENAME, FVPtr->FVFileName, SYM_LOCAL | SYM_OVERWRITE);
+
+ //
+ // Now create the FVx.inf filename from the fv name and
+ // default filename extension. Dump it in the FV directory
+ // as well.
+ //
+ strcpy (Str, FVDir);
+ strcat (Str, FVPtr->FVFileName);
+ strcat (Str, ".inf");
+ //
+ // Create the directory path for our new fv.inf output file.
+ //
+ MakeFilePath (Str);
+ if ((FVPtr->FVFilePtr = SmartOpen (Str)) == NULL) {
+ Error (NULL, 0, 0, Str, "could not open FV output file");
+ DSCFileRestorePosition (DSC);
+ return STATUS_ERROR;
+ }
+ //
+ // Now copy the [fv.fvfile.options] to the fv file
+ //
+ sprintf (Str, "fv.%s.options", StartCptr);
+ Section = DSCFileFindSection (DSC, Str);
+ if (Section != NULL) {
+ SmartWrite (FVPtr->FVFilePtr, "[options]\n");
+ while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
+ ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
+ SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
+ GetBaseAddress (ExpandedLine, FVPtr->BaseAddress);
+ }
+ } else {
+ Warning (NULL, 0, 0, NULL, "Could not find FV section '%s' in description file", Str);
+ }
+ //
+ // Copy the [fv.fvfile.attributes] to the fv file
+ //
+ sprintf (Str, "fv.%s.attributes", StartCptr);
+ Section = DSCFileFindSection (DSC, Str);
+ if (Section != NULL) {
+ SmartWrite (FVPtr->FVFilePtr, "[attributes]\n");
+ while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
+ ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
+ SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
+ }
+ } else {
+ Warning (NULL, 0, 0, NULL, "Could not find FV section '%s' in description file", Str);
+ }
+ //
+ // Copy the [fv.fvfile.components] to the fv file
+ //
+ sprintf (Str, "fv.%s.components", StartCptr);
+ Section = DSCFileFindSection (DSC, Str);
+ if (Section != NULL) {
+ SmartWrite (FVPtr->FVFilePtr, "[components]\n");
+ while (DSCFileGetLine (DSC, Line, sizeof (Line)) != NULL) {
+ ExpandSymbols (Line, ExpandedLine, sizeof (ExpandedLine), 0);
+ SmartWrite (FVPtr->FVFilePtr, ExpandedLine);
+ }
+ } else {
+ //
+ // An empty FV is allowed to contain nothing
+ //
+ }
+ //
+ // Close the file
+ //
+ SmartClose (FVPtr->FVFilePtr);
+ //
+ // Next FV in FileName
+ //
+ *EndCptr = CSave;
+ StartCptr = EndCptr;
+ if (*StartCptr) {
+ StartCptr++;
+ }
+ }
+
+ DSCFileRestorePosition (DSC);
+ return STATUS_SUCCESS;
+}
+
+static
+void
+AddFirmwareVolumes (
+ char *FVs,
+ int ComponentsInstance,
+ FILE_LIST *FileListPtr
+ )
+{
+ FV_LIST *FvPtr;
+ char *StartPtr;
+ char *EndPtr;
+ char SaveChar;
+
+ if ((FVs != NULL) && (FVs[0] != 0)) {
+ //
+ // Extract each FV name from the string. It's from the DSC file "FV=FvRecover,FvMain"
+ //
+ StartPtr = FVs;
+ while (*StartPtr != 0) {
+ EndPtr = StartPtr;
+ while (*EndPtr && (*EndPtr != ',')) {
+ EndPtr++;
+ }
+
+ SaveChar = *EndPtr;
+ *EndPtr = 0;
+ //
+ // Look through our list of known firmware volumes and see if we've
+ // already added it.
+ //
+ for (FvPtr = mFVList; FvPtr != NULL; FvPtr = FvPtr->Next) {
+ if (_stricmp (FvPtr->FVFileName, StartPtr) == 0) {
+ break;
+ }
+ }
+ //
+ // If we didn't find a match, then create a new one
+ //
+ if (FvPtr == NULL) {
+ FvPtr = MALLOC (sizeof (FV_LIST));
+ if (FvPtr == NULL) {
+ Error (__FILE__, __LINE__, 0, "application error", "memory allocation failed");
+ return ;
+ }
+
+ memset (FvPtr, 0, sizeof (FV_LIST));
+ strcpy (FvPtr->FVFileName, StartPtr);
+ if (mFVList == NULL) {
+ mFVList = FvPtr;
+ } else {
+ mFVListLast->Next = FvPtr;
+ }
+
+ mFVListLast = FvPtr;
+ }
+ //
+ // If this component's section number is higher than that of this
+ // FV, then set the FV's to it.
+ //
+ if (FvPtr->ComponentsInstance < ComponentsInstance) {
+ FvPtr->ComponentsInstance = ComponentsInstance;
+ }
+ //
+ // If we found then end of the FVs in the string, then we're done.
+ // Always restore the original string's contents.
+ //
+ if (SaveChar != 0) {
+ *EndPtr = SaveChar;
+ StartPtr = EndPtr + 1;
+ } else {
+ StartPtr = EndPtr;
+ }
+ }
+ }
+}
+
+static
+BOOLEAN
+OrderInFvList (
+ char *FvList,
+ char *FvName,
+ int *Order
+ )
+{
+ //
+ // Given FvList of format "FV_a,FV_b,FV_c" or "FV_a:1,FV_b:2" and
+ // FvName of format "FV_c", determine if FvName is in FvList. If
+ // FV_a:1 format, then return the value after the colon.
+ //
+ while (*FvList) {
+ //
+ // If it matches for the length of FvName...
+ //
+ if (_strnicmp (FvList, FvName, strlen (FvName)) == 0) {
+ //
+ // Then see if the match string in FvList is terminated at the
+ // same length.
+ //
+ if ((FvList[strlen (FvName)] == ',') || (FvList[strlen (FvName)] == 0)) {
+ *Order = 0;
+ return TRUE;
+ } else if (FvList[strlen (FvName)] == ':') {
+ *Order = atoi (FvList + strlen (FvName) + 1);
+ return TRUE;
+ }
+ }
+ //
+ // Skip to next FV in the comma-separated list
+ //
+ while ((*FvList != ',') && (*FvList != 0)) {
+ FvList++;
+ }
+ //
+ // Skip over comma
+ //
+ if (*FvList == ',') {
+ FvList++;
+ }
+ }
+
+ return FALSE;
+}
+
+static
+char *
+UpperCaseString (
+ char *Str
+ )
+{
+ char *Cptr;
+
+ for (Cptr = Str; *Cptr; Cptr++) {
+ *Cptr = (char) toupper (*Cptr);
+ }
+
+ return Str;
+}
+
+static
+BOOLEAN
+InSameFv (
+ char *FVs1,
+ char *FVs2
+)
+{
+ char *StartCptr1;
+ char *StartCptr2;
+ char *EndCptr1;
+ char *EndCptr2;
+ char CSave1;
+ char CSave2;
+
+ //
+ // Process each FV in first FV list
+ //
+ StartCptr1 = FVs1;
+ while (*StartCptr1) {
+ EndCptr1 = StartCptr1;
+ while (*EndCptr1 && (*EndCptr1 != ',')) {
+ EndCptr1++;
+ }
+
+ CSave1 = *EndCptr1;
+ *EndCptr1 = 0;
+
+ if (*StartCptr1) {
+ //
+ // Process each FV in second FV list
+ //
+ StartCptr2 = FVs2;
+ while (*StartCptr2) {
+ EndCptr2 = StartCptr2;
+ while (*EndCptr2 && (*EndCptr2 != ',')) {
+ EndCptr2++;
+ }
+
+ CSave2 = *EndCptr2;
+ *EndCptr2 = 0;
+
+ if (_stricmp (StartCptr1, StartCptr2) == 0) {
+ *EndCptr1 = CSave1;
+ *EndCptr2 = CSave2;
+ return TRUE;
+ }
+
+ //
+ // Next FV on the second FV list
+ //
+ *EndCptr2 = CSave2;
+ StartCptr2 = EndCptr2;
+ if (*StartCptr2) {
+ StartCptr2++;
+ }
+ }
+ }
+
+ //
+ // Next FV on the first FV list
+ //
+ *EndCptr1 = CSave1;
+ StartCptr1 = EndCptr1;
+ if (*StartCptr1) {
+ StartCptr1++;
+ }
+ }
+
+ return FALSE;
+}
+
+int
+CFVSetXRefFileName (
+ char *FileName
+ )
+{
+ mXRefFileName = FileName;
+ return 0;
+}