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