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