]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/Python/GenFds/Fv.py
BaseTools: Clean up source files
[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
20from io import BytesIO\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, PackGUID\r
30from Common.LongFilePathSupport import CopyLongFilePath\r
31from Common.LongFilePathSupport import OpenLongFilePath as open\r
32from Common.DataType import *\r
33\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 is None and self.UiFvName.upper() + 'fv' in GenFds.ImageBinDict:\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 is not None:\r
81 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
82 for RegionObj in FdObj.RegionList:\r
83 if RegionObj.RegionType == BINARY_FILE_TYPE_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:\r
88 continue\r
89 elif self.UiFvName.upper() == RegionData.upper():\r
90 GenFdsGlobalVariable.ErrorLogger("Capsule %s in FD region can't contain a FV %s in FD region." % (self.CapsuleName, self.UiFvName.upper()))\r
91 if not Flag:\r
92 GenFdsGlobalVariable.InfLogger( "\nGenerating %s FV" %self.UiFvName)\r
93 GenFdsGlobalVariable.LargeFileInFvFlags.append(False)\r
94 FFSGuid = None\r
95\r
96 if self.FvBaseAddress is not None:\r
97 BaseAddress = self.FvBaseAddress\r
98 if not Flag:\r
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, IsMakefile=Flag)\r
109 FfsFileList.append(FileName)\r
110 # Add Apriori file name to Inf file\r
111 if not Flag:\r
112 self.FvInfFile.writelines("EFI_FILE_NAME = " + \\r
113 FileName + \\r
114 TAB_LINE_BREAK)\r
115\r
116 # Process Modules in FfsList\r
117 for FfsFile in self.FfsList :\r
118 if Flag:\r
119 if isinstance(FfsFile, FfsFileStatement.FileStatement):\r
120 continue\r
121 if GenFdsGlobalVariable.EnableGenfdsMultiThread and GenFdsGlobalVariable.ModuleFile and GenFdsGlobalVariable.ModuleFile.Path.find(os.path.normpath(FfsFile.InfFileName)) == -1:\r
122 continue\r
123 FileName = FfsFile.GenFfs(MacroDict, FvParentAddr=BaseAddress, IsMakefile=Flag, FvName=self.UiFvName)\r
124 FfsFileList.append(FileName)\r
125 if not Flag:\r
126 self.FvInfFile.writelines("EFI_FILE_NAME = " + \\r
127 FileName + \\r
128 TAB_LINE_BREAK)\r
129 if not Flag:\r
130 SaveFileOnChange(self.InfFileName, self.FvInfFile.getvalue(), False)\r
131 self.FvInfFile.close()\r
132 #\r
133 # Call GenFv tool\r
134 #\r
135 FvOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName)\r
136 FvOutputFile = FvOutputFile + '.Fv'\r
137 # BUGBUG: FvOutputFile could be specified from FDF file (FV section, CreateFile statement)\r
138 if self.CreateFileName is not None:\r
139 FvOutputFile = self.CreateFileName\r
140\r
141 if Flag:\r
142 GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile\r
143 return FvOutputFile\r
144\r
145 FvInfoFileName = os.path.join(GenFdsGlobalVariable.FfsDir, self.UiFvName + '.inf')\r
146 if not Flag:\r
147 CopyLongFilePath(GenFdsGlobalVariable.FvAddressFileName, FvInfoFileName)\r
148 OrigFvInfo = None\r
149 if os.path.exists (FvInfoFileName):\r
150 OrigFvInfo = open(FvInfoFileName, 'r').read()\r
151 if GenFdsGlobalVariable.LargeFileInFvFlags[-1]:\r
152 FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID\r
153 GenFdsGlobalVariable.GenerateFirmwareVolume(\r
154 FvOutputFile,\r
155 [self.InfFileName],\r
156 AddressFile=FvInfoFileName,\r
157 FfsList=FfsFileList,\r
158 ForceRebase=self.FvForceRebase,\r
159 FileSystemGuid=FFSGuid\r
160 )\r
161\r
162 NewFvInfo = None\r
163 if os.path.exists (FvInfoFileName):\r
164 NewFvInfo = open(FvInfoFileName, 'r').read()\r
165 if NewFvInfo is not None and NewFvInfo != OrigFvInfo:\r
166 FvChildAddr = []\r
167 AddFileObj = open(FvInfoFileName, 'r')\r
168 AddrStrings = AddFileObj.readlines()\r
169 AddrKeyFound = False\r
170 for AddrString in AddrStrings:\r
171 if AddrKeyFound:\r
172 #get base address for the inside FvImage\r
173 FvChildAddr.append (AddrString)\r
174 elif AddrString.find ("[FV_BASE_ADDRESS]") != -1:\r
175 AddrKeyFound = True\r
176 AddFileObj.close()\r
177\r
178 if FvChildAddr != []:\r
179 # Update Ffs again\r
180 for FfsFile in self.FfsList :\r
181 FileName = FfsFile.GenFfs(MacroDict, FvChildAddr, BaseAddress, IsMakefile=Flag, FvName=self.UiFvName)\r
182\r
183 if GenFdsGlobalVariable.LargeFileInFvFlags[-1]:\r
184 FFSGuid = GenFdsGlobalVariable.EFI_FIRMWARE_FILE_SYSTEM3_GUID;\r
185 #Update GenFv again\r
186 GenFdsGlobalVariable.GenerateFirmwareVolume(\r
187 FvOutputFile,\r
188 [self.InfFileName],\r
189 AddressFile=FvInfoFileName,\r
190 FfsList=FfsFileList,\r
191 ForceRebase=self.FvForceRebase,\r
192 FileSystemGuid=FFSGuid\r
193 )\r
194\r
195 #\r
196 # Write the Fv contents to Buffer\r
197 #\r
198 if os.path.isfile(FvOutputFile):\r
199 FvFileObj = open(FvOutputFile, 'rb')\r
200 GenFdsGlobalVariable.VerboseLogger("\nGenerate %s FV Successfully" % self.UiFvName)\r
201 GenFdsGlobalVariable.SharpCounter = 0\r
202\r
203 Buffer.write(FvFileObj.read())\r
204 FvFileObj.seek(0)\r
205 # PI FvHeader is 0x48 byte\r
206 FvHeaderBuffer = FvFileObj.read(0x48)\r
207 # FV alignment position.\r
208 FvAlignmentValue = 1 << (ord(FvHeaderBuffer[0x2E]) & 0x1F)\r
209 if FvAlignmentValue >= 0x400:\r
210 if FvAlignmentValue >= 0x100000:\r
211 if FvAlignmentValue >= 0x1000000:\r
212 #The max alignment supported by FFS is 16M.\r
213 self.FvAlignment = "16M"\r
214 else:\r
215 self.FvAlignment = str(FvAlignmentValue / 0x100000) + "M"\r
216 else:\r
217 self.FvAlignment = str(FvAlignmentValue / 0x400) + "K"\r
218 else:\r
219 # FvAlignmentValue is less than 1K\r
220 self.FvAlignment = str (FvAlignmentValue)\r
221 FvFileObj.close()\r
222 GenFds.ImageBinDict[self.UiFvName.upper() + 'fv'] = FvOutputFile\r
223 GenFdsGlobalVariable.LargeFileInFvFlags.pop()\r
224 else:\r
225 GenFdsGlobalVariable.ErrorLogger("Failed to generate %s FV file." %self.UiFvName)\r
226 return FvOutputFile\r
227\r
228 ## _GetBlockSize()\r
229 #\r
230 # Calculate FV's block size\r
231 # Inherit block size from FD if no block size specified in FV\r
232 #\r
233 def _GetBlockSize(self):\r
234 if self.BlockSizeList:\r
235 return True\r
236\r
237 for FdObj in GenFdsGlobalVariable.FdfParser.Profile.FdDict.values():\r
238 for RegionObj in FdObj.RegionList:\r
239 if RegionObj.RegionType != BINARY_FILE_TYPE_FV:\r
240 continue\r
241 for RegionData in RegionObj.RegionDataList:\r
242 #\r
243 # Found the FD and region that contain this FV\r
244 #\r
245 if self.UiFvName.upper() == RegionData.upper():\r
246 RegionObj.BlockInfoOfRegion(FdObj.BlockSizeList, self)\r
247 if self.BlockSizeList:\r
248 return True\r
249 return False\r
250\r
251 ## __InitializeInf__()\r
252 #\r
253 # Initilize the inf file to create FV\r
254 #\r
255 # @param self The object pointer\r
256 # @param BaseAddress base address of FV\r
257 # @param BlockSize block size of FV\r
258 # @param BlockNum How many blocks in FV\r
259 # @param ErasePolarity Flash erase polarity\r
260 # @param VtfDict VTF objects\r
261 #\r
262 def __InitializeInf__ (self, BaseAddress = None, BlockSize= None, BlockNum = None, ErasePloarity='1', VtfDict=None) :\r
263 #\r
264 # Create FV inf file\r
265 #\r
266 self.InfFileName = os.path.join(GenFdsGlobalVariable.FvDir,\r
267 self.UiFvName + '.inf')\r
268 self.FvInfFile = BytesIO()\r
269\r
270 #\r
271 # Add [Options]\r
272 #\r
273 self.FvInfFile.writelines("[options]" + TAB_LINE_BREAK)\r
274 if BaseAddress is not None :\r
275 self.FvInfFile.writelines("EFI_BASE_ADDRESS = " + \\r
276 BaseAddress + \\r
277 TAB_LINE_BREAK)\r
278\r
279 if BlockSize is not None:\r
280 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \\r
281 '0x%X' %BlockSize + \\r
282 TAB_LINE_BREAK)\r
283 if BlockNum is not None:\r
284 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \\r
285 ' 0x%X' %BlockNum + \\r
286 TAB_LINE_BREAK)\r
287 else:\r
288 if self.BlockSizeList == []:\r
289 if not self._GetBlockSize():\r
290 #set default block size is 1\r
291 self.FvInfFile.writelines("EFI_BLOCK_SIZE = 0x1" + TAB_LINE_BREAK)\r
292\r
293 for BlockSize in self.BlockSizeList :\r
294 if BlockSize[0] is not None:\r
295 self.FvInfFile.writelines("EFI_BLOCK_SIZE = " + \\r
296 '0x%X' %BlockSize[0] + \\r
297 TAB_LINE_BREAK)\r
298\r
299 if BlockSize[1] is not None:\r
300 self.FvInfFile.writelines("EFI_NUM_BLOCKS = " + \\r
301 ' 0x%X' %BlockSize[1] + \\r
302 TAB_LINE_BREAK)\r
303\r
304 if self.BsBaseAddress is not None:\r
305 self.FvInfFile.writelines('EFI_BOOT_DRIVER_BASE_ADDRESS = ' + \\r
306 '0x%X' %self.BsBaseAddress)\r
307 if self.RtBaseAddress is not None:\r
308 self.FvInfFile.writelines('EFI_RUNTIME_DRIVER_BASE_ADDRESS = ' + \\r
309 '0x%X' %self.RtBaseAddress)\r
310 #\r
311 # Add attribute\r
312 #\r
313 self.FvInfFile.writelines("[attributes]" + TAB_LINE_BREAK)\r
314\r
315 self.FvInfFile.writelines("EFI_ERASE_POLARITY = " + \\r
316 ' %s' %ErasePloarity + \\r
317 TAB_LINE_BREAK)\r
318 if not (self.FvAttributeDict is None):\r
319 for FvAttribute in self.FvAttributeDict.keys() :\r
320 if FvAttribute == "FvUsedSizeEnable":\r
321 if self.FvAttributeDict[FvAttribute].upper() in ('TRUE', '1') :\r
322 self.UsedSizeEnable = True\r
323 continue\r
324 self.FvInfFile.writelines("EFI_" + \\r
325 FvAttribute + \\r
326 ' = ' + \\r
327 self.FvAttributeDict[FvAttribute] + \\r
328 TAB_LINE_BREAK )\r
329 if self.FvAlignment is not None:\r
330 self.FvInfFile.writelines("EFI_FVB2_ALIGNMENT_" + \\r
331 self.FvAlignment.strip() + \\r
332 " = TRUE" + \\r
333 TAB_LINE_BREAK)\r
334\r
335 #\r
336 # Generate FV extension header file\r
337 #\r
338 if not self.FvNameGuid:\r
339 if len(self.FvExtEntryType) > 0 or self.UsedSizeEnable:\r
340 GenFdsGlobalVariable.ErrorLogger("FV Extension Header Entries declared for %s with no FvNameGuid declaration." % (self.UiFvName))\r
341 else:\r
342 TotalSize = 16 + 4\r
343 Buffer = ''\r
344 if self.UsedSizeEnable:\r
345 TotalSize += (4 + 4)\r
346 ## define EFI_FV_EXT_TYPE_USED_SIZE_TYPE 0x03\r
347 #typedef struct\r
348 # {\r
349 # EFI_FIRMWARE_VOLUME_EXT_ENTRY Hdr;\r
350 # UINT32 UsedSize;\r
351 # } EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE;\r
352 Buffer += pack('HHL', 8, 3, 0)\r
353\r
354 if self.FvNameString == 'TRUE':\r
355 #\r
356 # Create EXT entry for FV UI name\r
357 # This GUID is used: A67DF1FA-8DE8-4E98-AF09-4BDF2EFFBC7C\r
358 #\r
359 FvUiLen = len(self.UiFvName)\r
360 TotalSize += (FvUiLen + 16 + 4)\r
361 Guid = FV_UI_EXT_ENTY_GUID.split('-')\r
362 #\r
363 # Layout:\r
364 # EFI_FIRMWARE_VOLUME_EXT_ENTRY : size 4\r
365 # GUID : size 16\r
366 # FV UI name\r
367 #\r
368 Buffer += (pack('HH', (FvUiLen + 16 + 4), 0x0002)\r
369 + PackGUID(Guid)\r
370 + self.UiFvName)\r
371\r
372 for Index in range (0, len(self.FvExtEntryType)):\r
373 if self.FvExtEntryType[Index] == 'FILE':\r
374 # check if the path is absolute or relative\r
375 if os.path.isabs(self.FvExtEntryData[Index]):\r
376 FileFullPath = os.path.normpath(self.FvExtEntryData[Index])\r
377 else:\r
378 FileFullPath = os.path.normpath(os.path.join(GenFdsGlobalVariable.WorkSpaceDir, self.FvExtEntryData[Index]))\r
379 # check if the file path exists or not\r
380 if not os.path.isfile(FileFullPath):\r
381 GenFdsGlobalVariable.ErrorLogger("Error opening FV Extension Header Entry file %s." % (self.FvExtEntryData[Index]))\r
382 FvExtFile = open (FileFullPath, 'rb')\r
383 FvExtFile.seek(0, 2)\r
384 Size = FvExtFile.tell()\r
385 if Size >= 0x10000:\r
386 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry file %s exceeds 0x10000." % (self.FvExtEntryData[Index]))\r
387 TotalSize += (Size + 4)\r
388 FvExtFile.seek(0)\r
389 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))\r
390 Buffer += FvExtFile.read()\r
391 FvExtFile.close()\r
392 if self.FvExtEntryType[Index] == 'DATA':\r
393 ByteList = self.FvExtEntryData[Index].split(',')\r
394 Size = len (ByteList)\r
395 if Size >= 0x10000:\r
396 GenFdsGlobalVariable.ErrorLogger("The size of FV Extension Header Entry data %s exceeds 0x10000." % (self.FvExtEntryData[Index]))\r
397 TotalSize += (Size + 4)\r
398 Buffer += pack('HH', (Size + 4), int(self.FvExtEntryTypeValue[Index], 16))\r
399 for Index1 in range (0, Size):\r
400 Buffer += pack('B', int(ByteList[Index1], 16))\r
401\r
402 Guid = self.FvNameGuid.split('-')\r
403 Buffer = PackGUID(Guid) + pack('=L', TotalSize) + Buffer\r
404\r
405 #\r
406 # Generate FV extension header file if the total size is not zero\r
407 #\r
408 if TotalSize > 0:\r
409 FvExtHeaderFileName = os.path.join(GenFdsGlobalVariable.FvDir, self.UiFvName + '.ext')\r
410 FvExtHeaderFile = BytesIO()\r
411 FvExtHeaderFile.write(Buffer)\r
412 Changed = SaveFileOnChange(FvExtHeaderFileName, FvExtHeaderFile.getvalue(), True)\r
413 FvExtHeaderFile.close()\r
414 if Changed:\r
415 if os.path.exists (self.InfFileName):\r
416 os.remove (self.InfFileName)\r
417 self.FvInfFile.writelines("EFI_FV_EXT_HEADER_FILE_NAME = " + \\r
418 FvExtHeaderFileName + \\r
419 TAB_LINE_BREAK)\r
420\r
421\r
422 #\r
423 # Add [Files]\r
424 #\r
425 self.FvInfFile.writelines("[files]" + TAB_LINE_BREAK)\r
426 if VtfDict and self.UiFvName in VtfDict:\r
427 self.FvInfFile.writelines("EFI_FILE_NAME = " + \\r
428 VtfDict[self.UiFvName] + \\r
429 TAB_LINE_BREAK)\r