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