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