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