]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/GenFds/Fv.py
Sync BaseTool trunk (version r2649) into EDKII BaseTools.
[mirror_edk2.git] / BaseTools / Source / Python / GenFds / Fv.py
1 ## @file
2 # process FV generation
3 #
4 # Copyright (c) 2007 - 2010, 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 #
18 import os
19 import shutil
20 import subprocess
21 import StringIO
22 from struct import *
23
24 import Ffs
25 import AprioriSection
26 from GenFdsGlobalVariable import GenFdsGlobalVariable
27 from GenFds import GenFds
28 from CommonDataClass.FdfClass import FvClassObject
29 from Common.Misc import SaveFileOnChange
30
31 T_CHAR_LF = '\n'
32
33 ## generate FV
34 #
35 #
36 class FV (FvClassObject):
37 ## The constructor
38 #
39 # @param self The object pointer
40 #
41 def __init__(self):
42 FvClassObject.__init__(self)
43 self.FvInfFile = None
44 self.FvAddressFile = None
45 self.BaseAddress = None
46 self.InfFileName = None
47 self.FvAddressFileName = None
48 self.CapsuleName = None
49 self.FvBaseAddress = None
50 self.FvForceRebase = None
51
52 ## AddToBuffer()
53 #
54 # Generate Fv and add it to the Buffer
55 #
56 # @param self The object pointer
57 # @param Buffer The buffer generated FV data will be put
58 # @param BaseAddress base address of FV
59 # @param BlockSize block size of FV
60 # @param BlockNum How many blocks in FV
61 # @param ErasePolarity Flash erase polarity
62 # @param VtfDict VTF objects
63 # @param MacroDict macro value pair
64 # @retval string Generated FV file path
65 #
66 def AddToBuffer (self, Buffer, BaseAddress=None, BlockSize= None, BlockNum=None, ErasePloarity='1', VtfDict=None, MacroDict = {}) :
67
68 if BaseAddress == None and self.UiFvName.upper() + 'fv' in GenFds.ImageBinDict.keys():
69 return GenFds.ImageBinDict[self.UiFvName.upper() + 'fv']
70
71 #
72 # Check whether FV in Capsule is in FD flash region.
73 # If yes, return error. Doesn't support FV in Capsule image is also in FD flash region.
74 #
75 if self.CapsuleName != None:
76 for FdName in GenFdsGlobalVariable.FdfParser.Profile.FdDict.keys():
77 FdObj = GenFdsGlobalVariable.FdfParser.Profile.FdDict[FdName]
78 for RegionObj in FdObj.RegionList:
79 if RegionObj.RegionType == 'FV':
80 for RegionData in RegionObj.RegionDataList:
81 if RegionData.endswith(".fv"):
82 continue
83 elif RegionData.upper() + 'fv' in GenFds.ImageBinDict.keys():
84 continue
85 elif self.UiFvName.upper() == RegionData.upper():
86 GenFdsGlobalVariable.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self.CapsuleName, self.UiFvName.upper()))
87
88 GenFdsGlobalVariable.InfLogger( "\nGenerating %s FV" %self.UiFvName)
89 GenFdsGlobalVariable.LargeFileInFvFlags.append(False)
90 FFSGuid = None
91
92 if self.FvBaseAddress != None:
93 BaseAddress = self.FvBaseAddress
94
95 self.__InitializeInf__(BaseAddress, BlockSize, BlockNum, ErasePloarity, VtfDict)
96 #
97 # First Process the Apriori section
98 #
99 MacroDict.update(self.DefineVarDict)
100
101 GenFdsGlobalVariable.VerboseLogger('First generate Apriori file !')
102 FfsFileList = []
103 for AprSection in self.AprioriSectionList:
104 FileName = AprSection.GenFfs (self.UiFvName, MacroDict)
105 FfsFileList.append(FileName)
106 # Add Apriori file name to Inf file
107 self.FvInfFile.writelines("EFI_FILE_NAME = " + \
108 FileName + \
109 T_CHAR_LF)
110
111 # Process Modules in FfsList
112 for FfsFile in self.FfsList :
113 FileName = FfsFile.GenFfs(MacroDict, FvParentAddr=BaseAddress)
114 FfsFileList.append(FileName)
115 self.FvInfFile.writelines("EFI_FILE_NAME = " + \
116 FileName + \
117 T_CHAR_LF)
118
119 SaveFileOnChange(self.InfFileName, self.FvInfFile.getvalue(), False)
120 self.FvInfFile.close()
121 #
122 # Call GenFv tool
123 #
124 FvOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName)
125 FvOutputFile = FvOutputFile + '.Fv'
126 # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement)
127 if self.CreateFileName != None:
128 FvOutputFile = self.CreateFileName
129
130 FvInfoFileName = os.path.join(GenFdsGlobalVariable.FfsDir, self.UiFvName + '.inf')
131 shutil.copy(GenFdsGlobalVariable.FvAddressFileName, FvInfoFileName)
132 OrigFvInfo = None
133 if os.path.exists (FvInfoFileName):
134 OrigFvInfo = open(FvInfoFileName, 'r').read()
135 if GenFdsGlobalVariable.LargeFileInFvFlags[-1]:
136 FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID;
137 GenFdsGlobalVariable.GenerateFirmwareVolume(
138 FvOutputFile,
139 [self.InfFileName],
140 AddressFile=FvInfoFileName,
141 FfsList=FfsFileList,
142 ForceRebase=self.FvForceRebase,
143 FileSystemGuid=FFSGuid
144 )
145
146 NewFvInfo = None
147 if os.path.exists (FvInfoFileName):
148 NewFvInfo = open(FvInfoFileName, 'r').read()
149 if NewFvInfo != None and NewFvInfo != OrigFvInfo:
150 FvChildAddr = []
151 AddFileObj = open(FvInfoFileName, 'r')
152 AddrStrings = AddFileObj.readlines()
153 AddrKeyFound = False
154 for AddrString in AddrStrings:
155 if AddrKeyFound:
156 #get base address for the inside FvImage
157 FvChildAddr.append (AddrString)
158 elif AddrString.find ("[FV_BASE_ADDRESS]") != -1:
159 AddrKeyFound = True
160 AddFileObj.close()
161
162 if FvChildAddr != []:
163 # Update Ffs again
164 for FfsFile in self.FfsList :
165 FileName = FfsFile.GenFfs(MacroDict, FvChildAddr, BaseAddress)
166
167 if GenFdsGlobalVariable.LargeFileInFvFlags[-1]:
168 FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID;
169 #Update GenFv again
170 GenFdsGlobalVariable.GenerateFirmwareVolume(
171 FvOutputFile,
172 [self.InfFileName],
173 AddressFile=FvInfoFileName,
174 FfsList=FfsFileList,
175 ForceRebase=self.FvForceRebase,
176 FileSystemGuid=FFSGuid
177 )
178
179 #
180 # Write the Fv contents to Buffer
181 #
182 FvFileObj = open ( FvOutputFile,'r+b')
183
184 GenFdsGlobalVariable.VerboseLogger( "\nGenerate %s FV Successfully" %self.UiFvName)
185 GenFdsGlobalVariable.SharpCounter = 0
186
187 Buffer.write(FvFileObj.read())
188 FvFileObj.seek(0)
189 # PI FvHeader is 0x48 byte
190 FvHeaderBuffer = FvFileObj.read(0x48)
191 # FV alignment position.
192 FvAlignmentValue = 1 << (ord (FvHeaderBuffer[0x2E]) & 0x1F)
193 # FvAlignmentValue is larger than or equal to 1K
194 if FvAlignmentValue >= 0x400:
195 if FvAlignmentValue >= 0x10000:
196 #The max alignment supported by FFS is 64K.
197 self.FvAlignment = "64K"
198 else:
199 self.FvAlignment = str (FvAlignmentValue / 0x400) + "K"
200 else:
201 # FvAlignmentValue is less than 1K
202 self.FvAlignment = str (FvAlignmentValue)
203 FvFileObj.close()
204 GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile
205 GenFdsGlobalVariable.LargeFileInFvFlags.pop()
206 return FvOutputFile
207
208 ## __InitializeInf__()
209 #
210 # Initilize the inf file to create FV
211 #
212 # @param self The object pointer
213 # @param BaseAddress base address of FV
214 # @param BlockSize block size of FV
215 # @param BlockNum How many blocks in FV
216 # @param ErasePolarity Flash erase polarity
217 # @param VtfDict VTF objects
218 #
219 def __InitializeInf__ (self, BaseAddress = None, BlockSize= None, BlockNum = None, ErasePloarity='1', VtfDict=None) :
220 #
221 # Create FV inf file
222 #
223 self.InfFileName = os.path.join(GenFdsGlobalVariable.FvDir,
224 self.UiFvName + '.inf')
225 self.FvInfFile = StringIO.StringIO()
226
227 #
228 # Add [Options]
229 #
230 self.FvInfFile.writelines("[options]" + T_CHAR_LF)
231 if BaseAddress != None :
232 self.FvInfFile.writelines("EFI_BASE_ADDRESS = " + \
233 BaseAddress + \
234 T_CHAR_LF)
235
236 if BlockSize != None:
237 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \
238 '0x%X' %BlockSize + \
239 T_CHAR_LF)
240 if BlockNum != None:
241 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \
242 ' 0x%X' %BlockNum + \
243 T_CHAR_LF)
244 else:
245 if self.BlockSizeList == []:
246 #set default block size is 1
247 self.FvInfFile.writelines("EFI_BLOCK_SIZE = 0x1" + T_CHAR_LF)
248
249 for BlockSize in self.BlockSizeList :
250 if BlockSize[0] != None:
251 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \
252 '0x%X' %BlockSize[0] + \
253 T_CHAR_LF)
254
255 if BlockSize[1] != None:
256 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \
257 ' 0x%X' %BlockSize[1] + \
258 T_CHAR_LF)
259
260 if self.BsBaseAddress != None:
261 self.FvInfFile.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \
262 '0x%X' %self.BsBaseAddress)
263 if self.RtBaseAddress != None:
264 self.FvInfFile.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \
265 '0x%X' %self.RtBaseAddress)
266 #
267 # Add attribute
268 #
269 self.FvInfFile.writelines("[attributes]" + T_CHAR_LF)
270
271 self.FvInfFile.writelines("EFI_ERASE_POLARITY = " + \
272 ' %s' %ErasePloarity + \
273 T_CHAR_LF)
274 if not (self.FvAttributeDict == None):
275 for FvAttribute in self.FvAttributeDict.keys() :
276 self.FvInfFile.writelines("EFI_" + \
277 FvAttribute + \
278 ' = ' + \
279 self.FvAttributeDict[FvAttribute] + \
280 T_CHAR_LF )
281 if self.FvAlignment != None:
282 self.FvInfFile.writelines("EFI_FVB2_ALIGNMENT_" + \
283 self.FvAlignment.strip() + \
284 " = TRUE" + \
285 T_CHAR_LF)
286
287 #
288 # Generate FV extension header file
289 #
290 if self.FvNameGuid == None or self.FvNameGuid == '':
291 if len(self.FvExtEntryType) > 0:
292 GenFdsGlobalVariable.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self.UiFvName))
293
294 if self.FvNameGuid <> None and self.FvNameGuid <> '':
295 TotalSize = 16 + 4
296 Buffer = ''
297 for Index in range (0, len(self.FvExtEntryType)):
298 if self.FvExtEntryType[Index] == 'FILE':
299 # check if the path is absolute or relative
300 if os.path.isabs(self.FvExtEntryData[Index]):
301 FileFullPath = os.path.normpath(self.FvExtEntryData[Index])
302 else:
303 FileFullPath = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.FvExtEntryData[Index]))
304 # check if the file path exists or not
305 if not os.path.isfile(FileFullPath):
306 GenFdsGlobalVariable.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self.FvExtEntryData[Index]))
307 FvExtFile = open (FileFullPath,'rb')
308 FvExtFile.seek(0,2)
309 Size = FvExtFile.tell()
310 if Size >= 0x10000:
311 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
312 TotalSize += (Size + 4)
313 FvExtFile.seek(0)
314 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
315 Buffer += FvExtFile.read()
316 FvExtFile.close()
317 if self.FvExtEntryType[Index] == 'DATA':
318 ByteList = self.FvExtEntryData[Index].split(',')
319 Size = len (ByteList)
320 if Size >= 0x10000:
321 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self.FvExtEntryData[Index]))
322 TotalSize += (Size + 4)
323 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))
324 for Index1 in range (0, Size):
325 Buffer += pack('B', int(ByteList[Index1], 16))
326
327 Guid = self.FvNameGuid.split('-')
328 Buffer = pack('=LHHBBBBBBBBL',
329 int(Guid[0], 16),
330 int(Guid[1], 16),
331 int(Guid[2], 16),
332 int(Guid[3][-4:-2], 16),
333 int(Guid[3][-2:], 16),
334 int(Guid[4][-12:-10], 16),
335 int(Guid[4][-10:-8], 16),
336 int(Guid[4][-8:-6], 16),
337 int(Guid[4][-6:-4], 16),
338 int(Guid[4][-4:-2], 16),
339 int(Guid[4][-2:], 16),
340 TotalSize
341 ) + Buffer
342
343 #
344 # Generate FV extension header file if the total size is not zero
345 #
346 if TotalSize > 0:
347 FvExtHeaderFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName + '.ext')
348 FvExtHeaderFile = StringIO.StringIO()
349 FvExtHeaderFile.write(Buffer)
350 Changed = SaveFileOnChange(FvExtHeaderFileName, FvExtHeaderFile.getvalue(), True)
351 FvExtHeaderFile.close()
352 if Changed:
353 if os.path.exists (self.InfFileName):
354 os.remove (self.InfFileName)
355 self.FvInfFile.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \
356 FvExtHeaderFileName + \
357 T_CHAR_LF)
358
359
360 #
361 # Add [Files]
362 #
363 self.FvInfFile.writelines("[files]" + T_CHAR_LF)
364 if VtfDict != None and self.UiFvName in VtfDict.keys():
365 self.FvInfFile.writelines("EFI_FILE_NAME = " + \
366 VtfDict.get(self.UiFvName) + \
367 T_CHAR_LF)