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