• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1## @file
2# process FV generation
3#
4#  Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
5#
6#  This program and the accompanying materials
7#  are licensed and made available under the terms and conditions of the BSD License
8#  which accompanies this distribution.  The full text of the license may be found at
9#  http://opensource.org/licenses/bsd-license.php
10#
11#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13#
14
15##
16# Import Modules
17#
18import Common.LongFilePathOs as os
19import subprocess
20import StringIO
21from struct import *
22
23import Ffs
24import AprioriSection
25from GenFdsGlobalVariable import GenFdsGlobalVariable
26from GenFds import GenFds
27from CommonDataClass.FdfClass import FvClassObject
28from Common.Misc import SaveFileOnChange
29from Common.LongFilePathSupport import CopyLongFilePath
30from Common.LongFilePathSupport import OpenLongFilePath as open
31
32T_CHAR_LF = '\n'
33FV_UI_EXT_ENTY_GUID = 'A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C'
34
35## generate FV
36#
37#
38class FV (FvClassObject):
39    ## The constructor
40    #
41    #   @param  self        The object pointer
42    #
43    def __init__(self):
44        FvClassObject.__init__(self)
45        self.FvInfFile = None
46        self.FvAddressFile = None
47        self.BaseAddress = None
48        self.InfFileName = None
49        self.FvAddressFileName = None
50        self.CapsuleName = None
51        self.FvBaseAddress = None
52        self.FvForceRebase = None
53
54    ## AddToBuffer()
55    #
56    #   Generate Fv and add it to the Buffer
57    #
58    #   @param  self        The object pointer
59    #   @param  Buffer      The buffer generated FV data will be put
60    #   @param  BaseAddress base address of FV
61    #   @param  BlockSize   block size of FV
62    #   @param  BlockNum    How many blocks in FV
63    #   @param  ErasePolarity      Flash erase polarity
64    #   @param  VtfDict     VTF objects
65    #   @param  MacroDict   macro value pair
66    #   @retval string      Generated FV file path
67    #
68    def AddToBuffer (self, Buffer, BaseAddress=None, BlockSize= None, BlockNum=None, ErasePloarity='1', VtfDict=None, MacroDict = {}) :
69
70        if BaseAddress == None and self.UiFvName.upper() + 'fv' in GenFds.ImageBinDict.keys():
71            return GenFds.ImageBinDict[self.UiFvName.upper() + 'fv']
72
73        #
74        # Check whether FV in Capsule is in FD flash region.
75        # If yes, return error. Doesn't support FV in Capsule image is also in FD flash region.
76        #
77        if self.CapsuleName != None:
78            for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
79                FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
80                for RegionObj in FdObj.RegionList:
81                    if RegionObj.RegionType == 'FV':
82                        for RegionData in RegionObj.RegionDataList:
83                            if RegionData.endswith(".fv"):
84                                continue
85                            elif RegionData.upper() + 'fv' in GenFds.ImageBinDict.keys():
86                                continue
87                            elif self.UiFvName.upper() == RegionData.upper():
88                                GenFdsGlobalVariable.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self.CapsuleName, self.UiFvName.upper()))
89
90        GenFdsGlobalVariable.InfLogger( "\nGenerating %s FV" %self.UiFvName)
91        GenFdsGlobalVariable.LargeFileInFvFlags.append(False)
92        FFSGuid = None
93
94        if self.FvBaseAddress != None:
95            BaseAddress = self.FvBaseAddress
96
97        self.__InitializeInf__(BaseAddress, BlockSize, BlockNum, ErasePloarity, VtfDict)
98        #
99        # First Process the Apriori section
100        #
101        MacroDict.update(self.DefineVarDict)
102
103        GenFdsGlobalVariable.VerboseLogger('First generate Apriori file !')
104        FfsFileList = []
105        for AprSection in self.AprioriSectionList:
106            FileName = AprSection.GenFfs (self.UiFvName, MacroDict)
107            FfsFileList.append(FileName)
108            # Add Apriori file name to Inf file
109            self.FvInfFile.writelines("EFI_FILE_NAME = " + \
110                                       FileName          + \
111                                           T_CHAR_LF)
112
113        # Process Modules in FfsList
114        for FfsFile in self.FfsList :
115            FileName = FfsFile.GenFfs(MacroDict, FvParentAddr=BaseAddress)
116            FfsFileList.append(FileName)
117            self.FvInfFile.writelines("EFI_FILE_NAME = " + \
118                                       FileName          + \
119                                       T_CHAR_LF)
120
121        SaveFileOnChange(self.InfFileName, self.FvInfFile.getvalue(), False)
122        self.FvInfFile.close()
123        #
124        # Call GenFv tool
125        #
126        FvOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName)
127        FvOutputFile = FvOutputFile + '.Fv'
128        # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement)
129        if self.CreateFileName != None:
130            FvOutputFile = self.CreateFileName
131
132        FvInfoFileName = os.path.join(GenFdsGlobalVariable.FfsDir, self.UiFvName + '.inf')
133        CopyLongFilePath(GenFdsGlobalVariable.FvAddressFileName, FvInfoFileName)
134        OrigFvInfo = None
135        if os.path.exists (FvInfoFileName):
136            OrigFvInfo = open(FvInfoFileName, 'r').read()
137        if GenFdsGlobalVariable.LargeFileInFvFlags[-1]:
138            FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID;
139        GenFdsGlobalVariable.GenerateFirmwareVolume(
140                                FvOutputFile,
141                                [self.InfFileName],
142                                AddressFile=FvInfoFileName,
143                                FfsList=FfsFileList,
144                                ForceRebase=self.FvForceRebase,
145                                FileSystemGuid=FFSGuid
146                                )
147
148        NewFvInfo = None
149        if os.path.exists (FvInfoFileName):
150            NewFvInfo = open(FvInfoFileName, 'r').read()
151        if NewFvInfo != None and NewFvInfo != OrigFvInfo:
152            FvChildAddr = []
153            AddFileObj = open(FvInfoFileName, 'r')
154            AddrStrings = AddFileObj.readlines()
155            AddrKeyFound = False
156            for AddrString in AddrStrings:
157                if AddrKeyFound:
158                    #get base address for the inside FvImage
159                    FvChildAddr.append (AddrString)
160                elif AddrString.find ("[FV_BASE_ADDRESS]") != -1:
161                    AddrKeyFound = True
162            AddFileObj.close()
163
164            if FvChildAddr != []:
165                # Update Ffs again
166                for FfsFile in self.FfsList :
167                    FileName = FfsFile.GenFfs(MacroDict, FvChildAddr, BaseAddress)
168
169                if GenFdsGlobalVariable.LargeFileInFvFlags[-1]:
170                    FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID;
171                #Update GenFv again
172                GenFdsGlobalVariable.GenerateFirmwareVolume(
173                                        FvOutputFile,
174                                        [self.InfFileName],
175                                        AddressFile=FvInfoFileName,
176                                        FfsList=FfsFileList,
177                                        ForceRebase=self.FvForceRebase,
178                                        FileSystemGuid=FFSGuid
179                                        )
180
181        #
182        # Write the Fv contents to Buffer
183        #
184        if os.path.isfile(FvOutputFile):
185            FvFileObj = open ( FvOutputFile,'r+b')
186
187            GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName)
188            GenFdsGlobalVariable.SharpCounter = 0
189
190            Buffer.write(FvFileObj.read())
191            FvFileObj.seek(0)
192            # PI FvHeader is 0x48 byte
193            FvHeaderBuffer = FvFileObj.read(0x48)
194            # FV alignment position.
195            FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F)
196            # FvAlignmentValue is larger than or equal to 1K
197            if FvAlignmentValue >= 0x400:
198                if FvAlignmentValue >= 0x10000:
199                    #The max alignment supported by FFS is 64K.
200                    self.FvAlignment = "64K"
201                else:
202                    self.FvAlignment = str (FvAlignmentValue / 0x400) + "K"
203            else:
204                # FvAlignmentValue is less than 1K
205                self.FvAlignment = str (FvAlignmentValue)
206            FvFileObj.close()
207            GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile
208            GenFdsGlobalVariable.LargeFileInFvFlags.pop()
209        else:
210            GenFdsGlobalVariable.ErrorLogger("Failed to generate %s FV file." %self.UiFvName)
211        return FvOutputFile
212
213    ## _GetBlockSize()
214    #
215    #   Calculate FV's block size
216    #   Inherit block size from FD if no block size specified in FV
217    #
218    def _GetBlockSize(self):
219        if self.BlockSizeList:
220            return True
221
222        for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
223            FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
224            for RegionObj in FdObj.RegionList:
225                if RegionObj.RegionType != 'FV':
226                    continue
227                for RegionData in RegionObj.RegionDataList:
228                    #
229                    # Found the FD and region that contain this FV
230                    #
231                    if self.UiFvName.upper() == RegionData.upper():
232                        RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, self)
233                        if self.BlockSizeList:
234                            return True
235        return False
236
237    ## __InitializeInf__()
238    #
239    #   Initilize the inf file to create FV
240    #
241    #   @param  self        The object pointer
242    #   @param  BaseAddress base address of FV
243    #   @param  BlockSize   block size of FV
244    #   @param  BlockNum    How many blocks in FV
245    #   @param  ErasePolarity      Flash erase polarity
246    #   @param  VtfDict     VTF objects
247    #
248    def __InitializeInf__ (self, BaseAddress = None, BlockSize= None, BlockNum = None, ErasePloarity='1', VtfDict=None) :
249        #
250        # Create FV inf file
251        #
252        self.InfFileName = os.path.join(GenFdsGlobalVariable.FvDir,
253                                   self.UiFvName + '.inf')
254        self.FvInfFile = StringIO.StringIO()
255
256        #
257        # Add [Options]
258        #
259        self.FvInfFile.writelines("[options]" + T_CHAR_LF)
260        if BaseAddress != None :
261            self.FvInfFile.writelines("EFI_BASE_ADDRESS = " + \
262                                       BaseAddress          + \
263                                       T_CHAR_LF)
264
265        if BlockSize != None:
266            self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \
267                                      '0x%X' %BlockSize    + \
268                                      T_CHAR_LF)
269            if BlockNum != None:
270                self.FvInfFile.writelines("EFI_NUM_BLOCKS   = "  + \
271                                      ' 0x%X' %BlockNum    + \
272                                      T_CHAR_LF)
273        else:
274            if self.BlockSizeList == []:
275                if not self._GetBlockSize():
276                    #set default block size is 1
277                    self.FvInfFile.writelines("EFI_BLOCK_SIZE  = 0x1" + T_CHAR_LF)
278
279            for BlockSize in self.BlockSizeList :
280                if BlockSize[0] != None:
281                    self.FvInfFile.writelines("EFI_BLOCK_SIZE  = "  + \
282                                          '0x%X' %BlockSize[0]    + \
283                                          T_CHAR_LF)
284
285                if BlockSize[1] != None:
286                    self.FvInfFile.writelines("EFI_NUM_BLOCKS   = "  + \
287                                          ' 0x%X' %BlockSize[1]    + \
288                                          T_CHAR_LF)
289
290        if self.BsBaseAddress != None:
291            self.FvInfFile.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
292                                       '0x%X' %self.BsBaseAddress)
293        if self.RtBaseAddress != None:
294            self.FvInfFile.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
295                                      '0x%X' %self.RtBaseAddress)
296        #
297        # Add attribute
298        #
299        self.FvInfFile.writelines("[attributes]" + T_CHAR_LF)
300
301        self.FvInfFile.writelines("EFI_ERASE_POLARITY   = "       + \
302                                          ' %s' %ErasePloarity    + \
303                                          T_CHAR_LF)
304        if not (self.FvAttributeDict == None):
305            for FvAttribute in self.FvAttributeDict.keys() :
306                self.FvInfFile.writelines("EFI_"            + \
307                                          FvAttribute       + \
308                                          ' = '             + \
309                                          self.FvAttributeDict[FvAttribute] + \
310                                          T_CHAR_LF )
311        if self.FvAlignment != None:
312            self.FvInfFile.writelines("EFI_FVB2_ALIGNMENT_"     + \
313                                       self.FvAlignment.strip() + \
314                                       " = TRUE"                + \
315                                       T_CHAR_LF)
316
317        #
318        # Generate FV extension header file
319        #
320        if self.FvNameGuid == None or self.FvNameGuid == '':
321            if len(self.FvExtEntryType) > 0:
322                GenFdsGlobalVariable.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self.UiFvName))
323
324        if self.FvNameGuid <> None and self.FvNameGuid <> '':
325            TotalSize = 16 + 4
326            Buffer = ''
327            if self.FvNameString == 'TRUE':
328                #
329                # Create EXT entry for FV UI name
330                # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C
331                #
332                FvUiLen = len(self.UiFvName)
333                TotalSize += (FvUiLen + 16 + 4)
334                Guid = FV_UI_EXT_ENTY_GUID.split('-')
335                #
336                # Layout:
337                #   EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4
338                #   GUID                          : size 16
339                #   FV UI name
340                #
341                Buffer += (pack('HH', (FvUiLen + 16 + 4), 0x0002)
342                           + pack('=LHHBBBBBBBB', int(Guid[0], 16), int(Guid[1], 16), int(Guid[2], 16),
343                                  int(Guid[3][-4:-2], 16), int(Guid[3][-2:], 16), int(Guid[4][-12:-10], 16),
344                                  int(Guid[4][-10:-8], 16), int(Guid[4][-8:-6], 16), int(Guid[4][-6:-4], 16),
345                                  int(Guid[4][-4:-2], 16), int(Guid[4][-2:], 16))
346                           + self.UiFvName)
347
348            for Index in range (0, len(self.FvExtEntryType)):
349                if self.FvExtEntryType[Index] == 'FILE':
350                    # check if the path is absolute or relative
351                    if os.path.isabs(self.FvExtEntryData[Index]):
352                        FileFullPath = os.path.normpath(self.FvExtEntryData[Index])
353                    else:
354                        FileFullPath = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.FvExtEntryData[Index]))
355                    # check if the file path exists or not
356                    if not os.path.isfile(FileFullPath):
357                        GenFdsGlobalVariable.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self.FvExtEntryData[Index]))
358                    FvExtFile = open (FileFullPath,'rb')
359                    FvExtFile.seek(0,2)
360                    Size = FvExtFile.tell()
361                    if Size >= 0x10000:
362                        GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
363                    TotalSize += (Size + 4)
364                    FvExtFile.seek(0)
365                    Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
366                    Buffer += FvExtFile.read()
367                    FvExtFile.close()
368                if self.FvExtEntryType[Index] == 'DATA':
369                    ByteList = self.FvExtEntryData[Index].split(',')
370                    Size = len (ByteList)
371                    if Size >= 0x10000:
372                        GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
373                    TotalSize += (Size + 4)
374                    Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
375                    for Index1 in range (0, Size):
376                        Buffer += pack('B', int(ByteList[Index1], 16))
377
378            Guid = self.FvNameGuid.split('-')
379            Buffer = pack('=LHHBBBBBBBBL',
380                        int(Guid[0], 16),
381                        int(Guid[1], 16),
382                        int(Guid[2], 16),
383                        int(Guid[3][-4:-2], 16),
384                        int(Guid[3][-2:], 16),
385                        int(Guid[4][-12:-10], 16),
386                        int(Guid[4][-10:-8], 16),
387                        int(Guid[4][-8:-6], 16),
388                        int(Guid[4][-6:-4], 16),
389                        int(Guid[4][-4:-2], 16),
390                        int(Guid[4][-2:], 16),
391                        TotalSize
392                        ) + Buffer
393
394            #
395            # Generate FV extension header file if the total size is not zero
396            #
397            if TotalSize > 0:
398                FvExtHeaderFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName + '.ext')
399                FvExtHeaderFile = StringIO.StringIO()
400                FvExtHeaderFile.write(Buffer)
401                Changed = SaveFileOnChange(FvExtHeaderFileName, FvExtHeaderFile.getvalue(), True)
402                FvExtHeaderFile.close()
403                if Changed:
404                  if os.path.exists (self.InfFileName):
405                    os.remove (self.InfFileName)
406                self.FvInfFile.writelines("EFI_FV_EXT_HEADER_FILE_NAME = "      + \
407                                           FvExtHeaderFileName                  + \
408                                           T_CHAR_LF)
409
410
411        #
412        # Add [Files]
413        #
414        self.FvInfFile.writelines("[files]" + T_CHAR_LF)
415        if VtfDict != None and self.UiFvName in VtfDict.keys():
416            self.FvInfFile.writelines("EFI_FILE_NAME = "                   + \
417                                       VtfDict.get(self.UiFvName)          + \
418                                       T_CHAR_LF)
419