1## @file 2# This file is used to be the main entrance of EOT tool 3# 4# Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR> 5# SPDX-License-Identifier: BSD-2-Clause-Patent 6# 7 8## 9# Import Modules 10# 11from __future__ import absolute_import 12import Common.LongFilePathOs as os, time, glob 13import Common.EdkLogger as EdkLogger 14import Eot.EotGlobalData as EotGlobalData 15from optparse import OptionParser 16from Common.StringUtils import NormPath 17from Common import BuildToolError 18from Common.Misc import GuidStructureStringToGuidString 19from collections import OrderedDict as sdict 20from Eot.Parser import * 21from Eot.InfParserLite import EdkInfParser 22from Common.StringUtils import GetSplitValueList 23from Eot import c 24from Eot import Database 25from array import array 26from Eot.Report import Report 27from Common.BuildVersion import gBUILD_VERSION 28from Eot.Parser import ConvertGuid 29from Common.LongFilePathSupport import OpenLongFilePath as open 30import struct 31import uuid 32import copy 33import codecs 34from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID 35 36gGuidStringFormat = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X" 37gIndention = -4 38 39class Image(array): 40 _HEADER_ = struct.Struct("") 41 _HEADER_SIZE_ = _HEADER_.size 42 43 def __new__(cls, *args, **kwargs): 44 return array.__new__(cls, 'B') 45 46 def __init__(self, ID=None): 47 if ID is None: 48 self._ID_ = str(uuid.uuid1()).upper() 49 else: 50 self._ID_ = ID 51 self._BUF_ = None 52 self._LEN_ = None 53 self._OFF_ = None 54 55 self._SubImages = sdict() # {offset: Image()} 56 57 array.__init__(self) 58 59 def __repr__(self): 60 return self._ID_ 61 62 def __len__(self): 63 Len = array.__len__(self) 64 for Offset in self._SubImages.keys(): 65 Len += len(self._SubImages[Offset]) 66 return Len 67 68 def _Unpack(self): 69 self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._LEN_]) 70 return len(self) 71 72 def _Pack(self, PadByte=0xFF): 73 raise NotImplementedError 74 75 def frombuffer(self, Buffer, Offset=0, Size=None): 76 self._BUF_ = Buffer 77 self._OFF_ = Offset 78 # we may need the Size information in advance if it's given 79 self._LEN_ = Size 80 self._LEN_ = self._Unpack() 81 82 def empty(self): 83 del self[0:] 84 85 def GetField(self, FieldStruct, Offset=0): 86 return FieldStruct.unpack_from(self, Offset) 87 88 def SetField(self, FieldStruct, Offset, *args): 89 # check if there's enough space 90 Size = FieldStruct.size 91 if Size > len(self): 92 self.extend([0] * (Size - len(self))) 93 FieldStruct.pack_into(self, Offset, *args) 94 95 def _SetData(self, Data): 96 if len(self) < self._HEADER_SIZE_: 97 self.extend([0] * (self._HEADER_SIZE_ - len(self))) 98 else: 99 del self[self._HEADER_SIZE_:] 100 self.extend(Data) 101 102 def _GetData(self): 103 if len(self) > self._HEADER_SIZE_: 104 return self[self._HEADER_SIZE_:] 105 return None 106 107 Data = property(_GetData, _SetData) 108 109## CompressedImage() class 110# 111# A class for Compressed Image 112# 113class CompressedImage(Image): 114 # UncompressedLength = 4-byte 115 # CompressionType = 1-byte 116 _HEADER_ = struct.Struct("1I 1B") 117 _HEADER_SIZE_ = _HEADER_.size 118 119 _ORIG_SIZE_ = struct.Struct("1I") 120 _CMPRS_TYPE_ = struct.Struct("4x 1B") 121 122 def __init__(self, CompressedData=None, CompressionType=None, UncompressedLength=None): 123 Image.__init__(self) 124 if UncompressedLength is not None: 125 self.UncompressedLength = UncompressedLength 126 if CompressionType is not None: 127 self.CompressionType = CompressionType 128 if CompressedData is not None: 129 self.Data = CompressedData 130 131 def __str__(self): 132 global gIndention 133 S = "algorithm=%s uncompressed=%x" % (self.CompressionType, self.UncompressedLength) 134 for Sec in self.Sections: 135 S += '\n' + str(Sec) 136 137 return S 138 139 def _SetOriginalSize(self, Size): 140 self.SetField(self._ORIG_SIZE_, 0, Size) 141 142 def _GetOriginalSize(self): 143 return self.GetField(self._ORIG_SIZE_)[0] 144 145 def _SetCompressionType(self, Type): 146 self.SetField(self._CMPRS_TYPE_, 0, Type) 147 148 def _GetCompressionType(self): 149 return self.GetField(self._CMPRS_TYPE_)[0] 150 151 def _GetSections(self): 152 try: 153 TmpData = DeCompress('Efi', self[self._HEADER_SIZE_:]) 154 DecData = array('B') 155 DecData.fromstring(TmpData) 156 except: 157 TmpData = DeCompress('Framework', self[self._HEADER_SIZE_:]) 158 DecData = array('B') 159 DecData.fromstring(TmpData) 160 161 SectionList = [] 162 Offset = 0 163 while Offset < len(DecData): 164 Sec = Section() 165 try: 166 Sec.frombuffer(DecData, Offset) 167 Offset += Sec.Size 168 # the section is aligned to 4-byte boundary 169 except: 170 break 171 SectionList.append(Sec) 172 return SectionList 173 174 UncompressedLength = property(_GetOriginalSize, _SetOriginalSize) 175 CompressionType = property(_GetCompressionType, _SetCompressionType) 176 Sections = property(_GetSections) 177 178## Ui() class 179# 180# A class for Ui 181# 182class Ui(Image): 183 _HEADER_ = struct.Struct("") 184 _HEADER_SIZE_ = 0 185 186 def __init__(self): 187 Image.__init__(self) 188 189 def __str__(self): 190 return self.String 191 192 def _Unpack(self): 193 # keep header in this Image object 194 self.empty() 195 self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._LEN_]) 196 return len(self) 197 198 def _GetUiString(self): 199 return codecs.utf_16_decode(self[0:-2].tostring())[0] 200 201 String = property(_GetUiString) 202 203## Depex() class 204# 205# A class for Depex 206# 207class Depex(Image): 208 _HEADER_ = struct.Struct("") 209 _HEADER_SIZE_ = 0 210 211 _GUID_ = struct.Struct("1I2H8B") 212 _OPCODE_ = struct.Struct("1B") 213 214 _OPCODE_STRING_ = { 215 0x00 : "BEFORE", 216 0x01 : "AFTER", 217 0x02 : "PUSH", 218 0x03 : "AND", 219 0x04 : "OR", 220 0x05 : "NOT", 221 0x06 : "TRUE", 222 0x07 : "FALSE", 223 0x08 : "END", 224 0x09 : "SOR" 225 } 226 227 _NEXT_ = { 228 -1 : _OPCODE_, # first one in depex must be an opcdoe 229 0x00 : _GUID_, #"BEFORE", 230 0x01 : _GUID_, #"AFTER", 231 0x02 : _GUID_, #"PUSH", 232 0x03 : _OPCODE_, #"AND", 233 0x04 : _OPCODE_, #"OR", 234 0x05 : _OPCODE_, #"NOT", 235 0x06 : _OPCODE_, #"TRUE", 236 0x07 : _OPCODE_, #"FALSE", 237 0x08 : None, #"END", 238 0x09 : _OPCODE_, #"SOR" 239 } 240 241 def __init__(self): 242 Image.__init__(self) 243 self._ExprList = [] 244 245 def __str__(self): 246 global gIndention 247 gIndention += 4 248 Indention = ' ' * gIndention 249 S = '\n' 250 for T in self.Expression: 251 if T in self._OPCODE_STRING_: 252 S += Indention + self._OPCODE_STRING_[T] 253 if T not in [0x00, 0x01, 0x02]: 254 S += '\n' 255 else: 256 S += ' ' + gGuidStringFormat % T + '\n' 257 gIndention -= 4 258 return S 259 260 def _Unpack(self): 261 # keep header in this Image object 262 self.empty() 263 self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._LEN_]) 264 return len(self) 265 266 def _GetExpression(self): 267 if self._ExprList == []: 268 Offset = 0 269 CurrentData = self._OPCODE_ 270 while Offset < len(self): 271 Token = CurrentData.unpack_from(self, Offset) 272 Offset += CurrentData.size 273 if len(Token) == 1: 274 Token = Token[0] 275 if Token in self._NEXT_: 276 CurrentData = self._NEXT_[Token] 277 else: 278 CurrentData = self._GUID_ 279 else: 280 CurrentData = self._OPCODE_ 281 self._ExprList.append(Token) 282 if CurrentData is None: 283 break 284 return self._ExprList 285 286 Expression = property(_GetExpression) 287 288# # FirmwareVolume() class 289# 290# A class for Firmware Volume 291# 292class FirmwareVolume(Image): 293 # Read FvLength, Attributes, HeaderLength, Checksum 294 _HEADER_ = struct.Struct("16x 1I2H8B 1Q 4x 1I 1H 1H") 295 _HEADER_SIZE_ = _HEADER_.size 296 297 _FfsGuid = "8C8CE578-8A3D-4F1C-9935-896185C32DD3" 298 299 _GUID_ = struct.Struct("16x 1I2H8B") 300 _LENGTH_ = struct.Struct("16x 16x 1Q") 301 _SIG_ = struct.Struct("16x 16x 8x 1I") 302 _ATTR_ = struct.Struct("16x 16x 8x 4x 1I") 303 _HLEN_ = struct.Struct("16x 16x 8x 4x 4x 1H") 304 _CHECKSUM_ = struct.Struct("16x 16x 8x 4x 4x 2x 1H") 305 306 def __init__(self, Name=''): 307 Image.__init__(self) 308 self.Name = Name 309 self.FfsDict = sdict() 310 self.OrderedFfsDict = sdict() 311 self.UnDispatchedFfsDict = sdict() 312 self.ProtocolList = sdict() 313 314 def CheckArchProtocol(self): 315 for Item in EotGlobalData.gArchProtocolGuids: 316 if Item.lower() not in EotGlobalData.gProtocolList: 317 return False 318 return True 319 320 def ParseDepex(self, Depex, Type): 321 List = None 322 if Type == 'Ppi': 323 List = EotGlobalData.gPpiList 324 if Type == 'Protocol': 325 List = EotGlobalData.gProtocolList 326 DepexStack = [] 327 DepexList = [] 328 DepexString = '' 329 FileDepex = None 330 CouldBeLoaded = True 331 for Index in range(0, len(Depex.Expression)): 332 Item = Depex.Expression[Index] 333 if Item == 0x00: 334 Index = Index + 1 335 Guid = gGuidStringFormat % Depex.Expression[Index] 336 if Guid in self.OrderedFfsDict and Depex.Expression[Index + 1] == 0x08: 337 return (True, 'BEFORE %s' % Guid, [Guid, 'BEFORE']) 338 elif Item == 0x01: 339 Index = Index + 1 340 Guid = gGuidStringFormat % Depex.Expression[Index] 341 if Guid in self.OrderedFfsDict and Depex.Expression[Index + 1] == 0x08: 342 return (True, 'AFTER %s' % Guid, [Guid, 'AFTER']) 343 elif Item == 0x02: 344 Index = Index + 1 345 Guid = gGuidStringFormat % Depex.Expression[Index] 346 if Guid.lower() in List: 347 DepexStack.append(True) 348 DepexList.append(Guid) 349 else: 350 DepexStack.append(False) 351 DepexList.append(Guid) 352 continue 353 elif Item == 0x03 or Item == 0x04: 354 DepexStack.append(eval(str(DepexStack.pop()) + ' ' + Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexStack.pop()))) 355 DepexList.append(str(DepexList.pop()) + ' ' + Depex._OPCODE_STRING_[Item].upper() + ' ' + str(DepexList.pop())) 356 elif Item == 0x05: 357 DepexStack.append(eval(Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexStack.pop()))) 358 DepexList.append(Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexList.pop())) 359 elif Item == 0x06: 360 DepexStack.append(True) 361 DepexList.append('TRUE') 362 DepexString = DepexString + 'TRUE' + ' ' 363 elif Item == 0x07: 364 DepexStack.append(False) 365 DepexList.append('False') 366 DepexString = DepexString + 'FALSE' + ' ' 367 elif Item == 0x08: 368 if Index != len(Depex.Expression) - 1: 369 CouldBeLoaded = False 370 else: 371 CouldBeLoaded = DepexStack.pop() 372 else: 373 CouldBeLoaded = False 374 if DepexList != []: 375 DepexString = DepexList[0].strip() 376 return (CouldBeLoaded, DepexString, FileDepex) 377 378 def Dispatch(self, Db=None): 379 if Db is None: 380 return False 381 self.UnDispatchedFfsDict = copy.copy(self.FfsDict) 382 # Find PeiCore, DexCore, PeiPriori, DxePriori first 383 FfsSecCoreGuid = None 384 FfsPeiCoreGuid = None 385 FfsDxeCoreGuid = None 386 FfsPeiPrioriGuid = None 387 FfsDxePrioriGuid = None 388 for FfsID in list(self.UnDispatchedFfsDict.keys()): 389 Ffs = self.UnDispatchedFfsDict[FfsID] 390 if Ffs.Type == 0x03: 391 FfsSecCoreGuid = FfsID 392 continue 393 if Ffs.Type == 0x04: 394 FfsPeiCoreGuid = FfsID 395 continue 396 if Ffs.Type == 0x05: 397 FfsDxeCoreGuid = FfsID 398 continue 399 if Ffs.Guid.lower() == PEI_APRIORI_GUID.lower(): 400 FfsPeiPrioriGuid = FfsID 401 continue 402 if Ffs.Guid.lower() == DXE_APRIORI_GUID.lower(): 403 FfsDxePrioriGuid = FfsID 404 continue 405 406 # Parse SEC_CORE first 407 if FfsSecCoreGuid is not None: 408 self.OrderedFfsDict[FfsSecCoreGuid] = self.UnDispatchedFfsDict.pop(FfsSecCoreGuid) 409 self.LoadPpi(Db, FfsSecCoreGuid) 410 411 # Parse PEI first 412 if FfsPeiCoreGuid is not None: 413 self.OrderedFfsDict[FfsPeiCoreGuid] = self.UnDispatchedFfsDict.pop(FfsPeiCoreGuid) 414 self.LoadPpi(Db, FfsPeiCoreGuid) 415 if FfsPeiPrioriGuid is not None: 416 # Load PEIM described in priori file 417 FfsPeiPriori = self.UnDispatchedFfsDict.pop(FfsPeiPrioriGuid) 418 if len(FfsPeiPriori.Sections) == 1: 419 Section = FfsPeiPriori.Sections.popitem()[1] 420 if Section.Type == 0x19: 421 GuidStruct = struct.Struct('1I2H8B') 422 Start = 4 423 while len(Section) > Start: 424 Guid = GuidStruct.unpack_from(Section[Start : Start + 16]) 425 GuidString = gGuidStringFormat % Guid 426 Start = Start + 16 427 if GuidString in self.UnDispatchedFfsDict: 428 self.OrderedFfsDict[GuidString] = self.UnDispatchedFfsDict.pop(GuidString) 429 self.LoadPpi(Db, GuidString) 430 431 self.DisPatchPei(Db) 432 433 # Parse DXE then 434 if FfsDxeCoreGuid is not None: 435 self.OrderedFfsDict[FfsDxeCoreGuid] = self.UnDispatchedFfsDict.pop(FfsDxeCoreGuid) 436 self.LoadProtocol(Db, FfsDxeCoreGuid) 437 if FfsDxePrioriGuid is not None: 438 # Load PEIM described in priori file 439 FfsDxePriori = self.UnDispatchedFfsDict.pop(FfsDxePrioriGuid) 440 if len(FfsDxePriori.Sections) == 1: 441 Section = FfsDxePriori.Sections.popitem()[1] 442 if Section.Type == 0x19: 443 GuidStruct = struct.Struct('1I2H8B') 444 Start = 4 445 while len(Section) > Start: 446 Guid = GuidStruct.unpack_from(Section[Start : Start + 16]) 447 GuidString = gGuidStringFormat % Guid 448 Start = Start + 16 449 if GuidString in self.UnDispatchedFfsDict: 450 self.OrderedFfsDict[GuidString] = self.UnDispatchedFfsDict.pop(GuidString) 451 self.LoadProtocol(Db, GuidString) 452 453 self.DisPatchDxe(Db) 454 455 def LoadProtocol(self, Db, ModuleGuid): 456 SqlCommand = """select GuidValue from Report 457 where SourceFileFullPath in 458 (select Value1 from Inf where BelongsToFile = 459 (select BelongsToFile from Inf 460 where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s) 461 and Model = %s) 462 and ItemType = 'Protocol' and ItemMode = 'Produced'""" \ 463 % (ModuleGuid, 5001, 3007) 464 RecordSet = Db.TblReport.Exec(SqlCommand) 465 for Record in RecordSet: 466 SqlCommand = """select Value2 from Inf where BelongsToFile = 467 (select DISTINCT BelongsToFile from Inf 468 where Value1 = 469 (select SourceFileFullPath from Report 470 where GuidValue like '%s' and ItemMode = 'Callback')) 471 and Value1 = 'FILE_GUID'""" % Record[0] 472 CallBackSet = Db.TblReport.Exec(SqlCommand) 473 if CallBackSet != []: 474 EotGlobalData.gProtocolList[Record[0].lower()] = ModuleGuid 475 else: 476 EotGlobalData.gProtocolList[Record[0].lower()] = ModuleGuid 477 478 def LoadPpi(self, Db, ModuleGuid): 479 SqlCommand = """select GuidValue from Report 480 where SourceFileFullPath in 481 (select Value1 from Inf where BelongsToFile = 482 (select BelongsToFile from Inf 483 where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s) 484 and Model = %s) 485 and ItemType = 'Ppi' and ItemMode = 'Produced'""" \ 486 % (ModuleGuid, 5001, 3007) 487 RecordSet = Db.TblReport.Exec(SqlCommand) 488 for Record in RecordSet: 489 EotGlobalData.gPpiList[Record[0].lower()] = ModuleGuid 490 491 def DisPatchDxe(self, Db): 492 IsInstalled = False 493 ScheduleList = sdict() 494 for FfsID in list(self.UnDispatchedFfsDict.keys()): 495 CouldBeLoaded = False 496 DepexString = '' 497 FileDepex = None 498 Ffs = self.UnDispatchedFfsDict[FfsID] 499 if Ffs.Type == 0x07: 500 # Get Depex 501 IsFoundDepex = False 502 for Section in Ffs.Sections.values(): 503 # Find Depex 504 if Section.Type == 0x13: 505 IsFoundDepex = True 506 CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(Section._SubImages[4], 'Protocol') 507 break 508 if Section.Type == 0x01: 509 CompressSections = Section._SubImages[4] 510 for CompressSection in CompressSections.Sections: 511 if CompressSection.Type == 0x13: 512 IsFoundDepex = True 513 CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(CompressSection._SubImages[4], 'Protocol') 514 break 515 if CompressSection.Type == 0x02: 516 NewSections = CompressSection._SubImages[4] 517 for NewSection in NewSections.Sections: 518 if NewSection.Type == 0x13: 519 IsFoundDepex = True 520 CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(NewSection._SubImages[4], 'Protocol') 521 break 522 523 # Not find Depex 524 if not IsFoundDepex: 525 CouldBeLoaded = self.CheckArchProtocol() 526 DepexString = '' 527 FileDepex = None 528 529 # Append New Ffs 530 if CouldBeLoaded: 531 IsInstalled = True 532 NewFfs = self.UnDispatchedFfsDict.pop(FfsID) 533 NewFfs.Depex = DepexString 534 if FileDepex is not None: 535 ScheduleList.insert(FileDepex[1], FfsID, NewFfs, FileDepex[0]) 536 else: 537 ScheduleList[FfsID] = NewFfs 538 else: 539 self.UnDispatchedFfsDict[FfsID].Depex = DepexString 540 541 for FfsID in ScheduleList.keys(): 542 NewFfs = ScheduleList.pop(FfsID) 543 FfsName = 'UnKnown' 544 self.OrderedFfsDict[FfsID] = NewFfs 545 self.LoadProtocol(Db, FfsID) 546 547 SqlCommand = """select Value2 from Inf 548 where BelongsToFile = (select BelongsToFile from Inf where Value1 = 'FILE_GUID' and lower(Value2) = lower('%s') and Model = %s) 549 and Model = %s and Value1='BASE_NAME'""" % (FfsID, 5001, 5001) 550 RecordSet = Db.TblReport.Exec(SqlCommand) 551 if RecordSet != []: 552 FfsName = RecordSet[0][0] 553 554 if IsInstalled: 555 self.DisPatchDxe(Db) 556 557 def DisPatchPei(self, Db): 558 IsInstalled = False 559 for FfsID in list(self.UnDispatchedFfsDict.keys()): 560 CouldBeLoaded = True 561 DepexString = '' 562 FileDepex = None 563 Ffs = self.UnDispatchedFfsDict[FfsID] 564 if Ffs.Type == 0x06 or Ffs.Type == 0x08: 565 # Get Depex 566 for Section in Ffs.Sections.values(): 567 if Section.Type == 0x1B: 568 CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(Section._SubImages[4], 'Ppi') 569 break 570 if Section.Type == 0x01: 571 CompressSections = Section._SubImages[4] 572 for CompressSection in CompressSections.Sections: 573 if CompressSection.Type == 0x1B: 574 CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(CompressSection._SubImages[4], 'Ppi') 575 break 576 if CompressSection.Type == 0x02: 577 NewSections = CompressSection._SubImages[4] 578 for NewSection in NewSections.Sections: 579 if NewSection.Type == 0x1B: 580 CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(NewSection._SubImages[4], 'Ppi') 581 break 582 583 # Append New Ffs 584 if CouldBeLoaded: 585 IsInstalled = True 586 NewFfs = self.UnDispatchedFfsDict.pop(FfsID) 587 NewFfs.Depex = DepexString 588 self.OrderedFfsDict[FfsID] = NewFfs 589 self.LoadPpi(Db, FfsID) 590 else: 591 self.UnDispatchedFfsDict[FfsID].Depex = DepexString 592 593 if IsInstalled: 594 self.DisPatchPei(Db) 595 596 597 def __str__(self): 598 global gIndention 599 gIndention += 4 600 FvInfo = '\n' + ' ' * gIndention 601 FvInfo += "[FV:%s] file_system=%s size=%x checksum=%s\n" % (self.Name, self.FileSystemGuid, self.Size, self.Checksum) 602 FfsInfo = "\n".join([str(self.FfsDict[FfsId]) for FfsId in self.FfsDict]) 603 gIndention -= 4 604 return FvInfo + FfsInfo 605 606 def _Unpack(self): 607 Size = self._LENGTH_.unpack_from(self._BUF_, self._OFF_)[0] 608 self.empty() 609 self.extend(self._BUF_[self._OFF_:self._OFF_ + Size]) 610 611 # traverse the FFS 612 EndOfFv = Size 613 FfsStartAddress = self.HeaderSize 614 LastFfsObj = None 615 while FfsStartAddress < EndOfFv: 616 FfsObj = Ffs() 617 FfsObj.frombuffer(self, FfsStartAddress) 618 FfsId = repr(FfsObj) 619 if ((self.Attributes & 0x00000800) != 0 and len(FfsObj) == 0xFFFFFF) \ 620 or ((self.Attributes & 0x00000800) == 0 and len(FfsObj) == 0): 621 if LastFfsObj is not None: 622 LastFfsObj.FreeSpace = EndOfFv - LastFfsObj._OFF_ - len(LastFfsObj) 623 else: 624 if FfsId in self.FfsDict: 625 EdkLogger.error("FV", 0, "Duplicate GUID in FFS", 626 ExtraData="\t%s @ %s\n\t%s @ %s" \ 627 % (FfsObj.Guid, FfsObj.Offset, 628 self.FfsDict[FfsId].Guid, self.FfsDict[FfsId].Offset)) 629 self.FfsDict[FfsId] = FfsObj 630 if LastFfsObj is not None: 631 LastFfsObj.FreeSpace = FfsStartAddress - LastFfsObj._OFF_ - len(LastFfsObj) 632 633 FfsStartAddress += len(FfsObj) 634 # 635 # align to next 8-byte aligned address: A = (A + 8 - 1) & (~(8 - 1)) 636 # The next FFS must be at the latest next 8-byte aligned address 637 # 638 FfsStartAddress = (FfsStartAddress + 7) & (~7) 639 LastFfsObj = FfsObj 640 641 def _GetAttributes(self): 642 return self.GetField(self._ATTR_, 0)[0] 643 644 def _GetSize(self): 645 return self.GetField(self._LENGTH_, 0)[0] 646 647 def _GetChecksum(self): 648 return self.GetField(self._CHECKSUM_, 0)[0] 649 650 def _GetHeaderLength(self): 651 return self.GetField(self._HLEN_, 0)[0] 652 653 def _GetFileSystemGuid(self): 654 return gGuidStringFormat % self.GetField(self._GUID_, 0) 655 656 Attributes = property(_GetAttributes) 657 Size = property(_GetSize) 658 Checksum = property(_GetChecksum) 659 HeaderSize = property(_GetHeaderLength) 660 FileSystemGuid = property(_GetFileSystemGuid) 661 662## GuidDefinedImage() class 663# 664# A class for GUID Defined Image 665# 666class GuidDefinedImage(Image): 667 _HEADER_ = struct.Struct("1I2H8B 1H 1H") 668 _HEADER_SIZE_ = _HEADER_.size 669 670 _GUID_ = struct.Struct("1I2H8B") 671 _DATA_OFFSET_ = struct.Struct("16x 1H") 672 _ATTR_ = struct.Struct("18x 1H") 673 674 CRC32_GUID = "FC1BCDB0-7D31-49AA-936A-A4600D9DD083" 675 TIANO_COMPRESS_GUID = 'A31280AD-481E-41B6-95E8-127F4C984779' 676 LZMA_COMPRESS_GUID = 'EE4E5898-3914-4259-9D6E-DC7BD79403CF' 677 678 def __init__(self, SectionDefinitionGuid=None, DataOffset=None, Attributes=None, Data=None): 679 Image.__init__(self) 680 if SectionDefinitionGuid is not None: 681 self.SectionDefinitionGuid = SectionDefinitionGuid 682 if DataOffset is not None: 683 self.DataOffset = DataOffset 684 if Attributes is not None: 685 self.Attributes = Attributes 686 if Data is not None: 687 self.Data = Data 688 689 def __str__(self): 690 S = "guid=%s" % (gGuidStringFormat % self.SectionDefinitionGuid) 691 for Sec in self.Sections: 692 S += "\n" + str(Sec) 693 return S 694 695 def _Unpack(self): 696 # keep header in this Image object 697 self.empty() 698 self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._LEN_]) 699 return len(self) 700 701 def _SetAttribute(self, Attribute): 702 self.SetField(self._ATTR_, 0, Attribute) 703 704 def _GetAttribute(self): 705 return self.GetField(self._ATTR_)[0] 706 707 def _SetGuid(self, Guid): 708 self.SetField(self._GUID_, 0, Guid) 709 710 def _GetGuid(self): 711 return self.GetField(self._GUID_) 712 713 def _SetDataOffset(self, Offset): 714 self.SetField(self._DATA_OFFSET_, 0, Offset) 715 716 def _GetDataOffset(self): 717 return self.GetField(self._DATA_OFFSET_)[0] 718 719 def _GetSections(self): 720 SectionList = [] 721 Guid = gGuidStringFormat % self.SectionDefinitionGuid 722 if Guid == self.CRC32_GUID: 723 # skip the CRC32 value, we don't do CRC32 verification here 724 Offset = self.DataOffset - 4 725 while Offset < len(self): 726 Sec = Section() 727 try: 728 Sec.frombuffer(self, Offset) 729 Offset += Sec.Size 730 # the section is aligned to 4-byte boundary 731 Offset = (Offset + 3) & (~3) 732 except: 733 break 734 SectionList.append(Sec) 735 elif Guid == self.TIANO_COMPRESS_GUID: 736 try: 737 # skip the header 738 Offset = self.DataOffset - 4 739 TmpData = DeCompress('Framework', self[self.Offset:]) 740 DecData = array('B') 741 DecData.fromstring(TmpData) 742 Offset = 0 743 while Offset < len(DecData): 744 Sec = Section() 745 try: 746 Sec.frombuffer(DecData, Offset) 747 Offset += Sec.Size 748 # the section is aligned to 4-byte boundary 749 Offset = (Offset + 3) & (~3) 750 except: 751 break 752 SectionList.append(Sec) 753 except: 754 pass 755 elif Guid == self.LZMA_COMPRESS_GUID: 756 try: 757 # skip the header 758 Offset = self.DataOffset - 4 759 760 TmpData = DeCompress('Lzma', self[self.Offset:]) 761 DecData = array('B') 762 DecData.fromstring(TmpData) 763 Offset = 0 764 while Offset < len(DecData): 765 Sec = Section() 766 try: 767 Sec.frombuffer(DecData, Offset) 768 Offset += Sec.Size 769 # the section is aligned to 4-byte boundary 770 Offset = (Offset + 3) & (~3) 771 except: 772 break 773 SectionList.append(Sec) 774 except: 775 pass 776 777 return SectionList 778 779 Attributes = property(_GetAttribute, _SetAttribute) 780 SectionDefinitionGuid = property(_GetGuid, _SetGuid) 781 DataOffset = property(_GetDataOffset, _SetDataOffset) 782 Sections = property(_GetSections) 783 784## Section() class 785# 786# A class for Section 787# 788class Section(Image): 789 _TypeName = { 790 0x00 : "<unknown>", 791 0x01 : "COMPRESSION", 792 0x02 : "GUID_DEFINED", 793 0x10 : "PE32", 794 0x11 : "PIC", 795 0x12 : "TE", 796 0x13 : "DXE_DEPEX", 797 0x14 : "VERSION", 798 0x15 : "USER_INTERFACE", 799 0x16 : "COMPATIBILITY16", 800 0x17 : "FIRMWARE_VOLUME_IMAGE", 801 0x18 : "FREEFORM_SUBTYPE_GUID", 802 0x19 : "RAW", 803 0x1B : "PEI_DEPEX" 804 } 805 806 _SectionSubImages = { 807 0x01 : CompressedImage, 808 0x02 : GuidDefinedImage, 809 0x17 : FirmwareVolume, 810 0x13 : Depex, 811 0x1B : Depex, 812 0x15 : Ui 813 } 814 815 # Size = 3-byte 816 # Type = 1-byte 817 _HEADER_ = struct.Struct("3B 1B") 818 _HEADER_SIZE_ = _HEADER_.size 819 820 # SubTypeGuid 821 # _FREE_FORM_SUBTYPE_GUID_HEADER_ = struct.Struct("1I2H8B") 822 _SIZE_ = struct.Struct("3B") 823 _TYPE_ = struct.Struct("3x 1B") 824 825 def __init__(self, Type=None, Size=None): 826 Image.__init__(self) 827 self._Alignment = 1 828 if Type is not None: 829 self.Type = Type 830 if Size is not None: 831 self.Size = Size 832 833 def __str__(self): 834 global gIndention 835 gIndention += 4 836 SectionInfo = ' ' * gIndention 837 if self.Type in self._TypeName: 838 SectionInfo += "[SECTION:%s] offset=%x size=%x" % (self._TypeName[self.Type], self._OFF_, self.Size) 839 else: 840 SectionInfo += "[SECTION:%x<unknown>] offset=%x size=%x " % (self.Type, self._OFF_, self.Size) 841 for Offset in self._SubImages.keys(): 842 SectionInfo += ", " + str(self._SubImages[Offset]) 843 gIndention -= 4 844 return SectionInfo 845 846 def _Unpack(self): 847 self.empty() 848 Type, = self._TYPE_.unpack_from(self._BUF_, self._OFF_) 849 Size1, Size2, Size3 = self._SIZE_.unpack_from(self._BUF_, self._OFF_) 850 Size = Size1 + (Size2 << 8) + (Size3 << 16) 851 852 if Type not in self._SectionSubImages: 853 # no need to extract sub-image, keep all in this Image object 854 self.extend(self._BUF_[self._OFF_ : self._OFF_ + Size]) 855 else: 856 # keep header in this Image object 857 self.extend(self._BUF_[self._OFF_ : self._OFF_ + self._HEADER_SIZE_]) 858 # 859 # use new Image object to represent payload, which may be another kind 860 # of image such as PE32 861 # 862 PayloadOffset = self._HEADER_SIZE_ 863 PayloadLen = self.Size - self._HEADER_SIZE_ 864 Payload = self._SectionSubImages[self.Type]() 865 Payload.frombuffer(self._BUF_, self._OFF_ + self._HEADER_SIZE_, PayloadLen) 866 self._SubImages[PayloadOffset] = Payload 867 868 return Size 869 870 def _SetSize(self, Size): 871 Size1 = Size & 0xFF 872 Size2 = (Size & 0xFF00) >> 8 873 Size3 = (Size & 0xFF0000) >> 16 874 self.SetField(self._SIZE_, 0, Size1, Size2, Size3) 875 876 def _GetSize(self): 877 Size1, Size2, Size3 = self.GetField(self._SIZE_) 878 return Size1 + (Size2 << 8) + (Size3 << 16) 879 880 def _SetType(self, Type): 881 self.SetField(self._TYPE_, 0, Type) 882 883 def _GetType(self): 884 return self.GetField(self._TYPE_)[0] 885 886 def _GetAlignment(self): 887 return self._Alignment 888 889 def _SetAlignment(self, Alignment): 890 self._Alignment = Alignment 891 AlignmentMask = Alignment - 1 892 # section alignment is actually for payload, so we need to add header size 893 PayloadOffset = self._OFF_ + self._HEADER_SIZE_ 894 if (PayloadOffset & (~AlignmentMask)) == 0: 895 return 896 NewOffset = (PayloadOffset + AlignmentMask) & (~AlignmentMask) 897 while (NewOffset - PayloadOffset) < self._HEADER_SIZE_: 898 NewOffset += self._Alignment 899 900 def tofile(self, f): 901 self.Size = len(self) 902 Image.tofile(self, f) 903 for Offset in self._SubImages: 904 self._SubImages[Offset].tofile(f) 905 906 Type = property(_GetType, _SetType) 907 Size = property(_GetSize, _SetSize) 908 Alignment = property(_GetAlignment, _SetAlignment) 909 910## Ffs() class 911# 912# A class for Ffs Section 913# 914class Ffs(Image): 915 _FfsFormat = "24B%(payload_size)sB" 916 # skip IntegrityCheck 917 _HEADER_ = struct.Struct("1I2H8B 2x 1B 1B 3B 1B") 918 _HEADER_SIZE_ = _HEADER_.size 919 920 _NAME_ = struct.Struct("1I2H8B") 921 _INT_CHECK_ = struct.Struct("16x 1H") 922 _TYPE_ = struct.Struct("18x 1B") 923 _ATTR_ = struct.Struct("19x 1B") 924 _SIZE_ = struct.Struct("20x 3B") 925 _STATE_ = struct.Struct("23x 1B") 926 927 FFS_ATTRIB_FIXED = 0x04 928 FFS_ATTRIB_DATA_ALIGNMENT = 0x38 929 FFS_ATTRIB_CHECKSUM = 0x40 930 931 _TypeName = { 932 0x00 : "<unknown>", 933 0x01 : "RAW", 934 0x02 : "FREEFORM", 935 0x03 : "SECURITY_CORE", 936 0x04 : "PEI_CORE", 937 0x05 : "DXE_CORE", 938 0x06 : "PEIM", 939 0x07 : "DRIVER", 940 0x08 : "COMBINED_PEIM_DRIVER", 941 0x09 : "APPLICATION", 942 0x0A : "SMM", 943 0x0B : "FIRMWARE_VOLUME_IMAGE", 944 0x0C : "COMBINED_SMM_DXE", 945 0x0D : "SMM_CORE", 946 0x0E : "MM_STANDALONE", 947 0x0F : "MM_CORE_STANDALONE", 948 0xc0 : "OEM_MIN", 949 0xdf : "OEM_MAX", 950 0xe0 : "DEBUG_MIN", 951 0xef : "DEBUG_MAX", 952 0xf0 : "FFS_MIN", 953 0xff : "FFS_MAX", 954 0xf0 : "FFS_PAD", 955 } 956 957 def __init__(self): 958 Image.__init__(self) 959 self.FreeSpace = 0 960 961 self.Sections = sdict() 962 self.Depex = '' 963 964 self.__ID__ = None 965 966 def __str__(self): 967 global gIndention 968 gIndention += 4 969 Indention = ' ' * gIndention 970 FfsInfo = Indention 971 FfsInfo += "[FFS:%s] offset=%x size=%x guid=%s free_space=%x alignment=%s\n" % \ 972 (Ffs._TypeName[self.Type], self._OFF_, self.Size, self.Guid, self.FreeSpace, self.Alignment) 973 SectionInfo = '\n'.join([str(self.Sections[Offset]) for Offset in self.Sections.keys()]) 974 gIndention -= 4 975 return FfsInfo + SectionInfo + "\n" 976 977 def __len__(self): 978 return self.Size 979 980 def __repr__(self): 981 return self.__ID__ 982 983 def _Unpack(self): 984 Size1, Size2, Size3 = self._SIZE_.unpack_from(self._BUF_, self._OFF_) 985 Size = Size1 + (Size2 << 8) + (Size3 << 16) 986 self.empty() 987 self.extend(self._BUF_[self._OFF_ : self._OFF_ + Size]) 988 989 # Pad FFS may use the same GUID. We need to avoid it. 990 if self.Type == 0xf0: 991 self.__ID__ = str(uuid.uuid1()).upper() 992 else: 993 self.__ID__ = self.Guid 994 995 # Traverse the SECTION. RAW and PAD do not have sections 996 if self.Type not in [0xf0, 0x01] and Size > 0 and Size < 0xFFFFFF: 997 EndOfFfs = Size 998 SectionStartAddress = self._HEADER_SIZE_ 999 while SectionStartAddress < EndOfFfs: 1000 SectionObj = Section() 1001 SectionObj.frombuffer(self, SectionStartAddress) 1002 #f = open(repr(SectionObj), 'wb') 1003 #SectionObj.Size = 0 1004 #SectionObj.tofile(f) 1005 #f.close() 1006 self.Sections[SectionStartAddress] = SectionObj 1007 SectionStartAddress += len(SectionObj) 1008 SectionStartAddress = (SectionStartAddress + 3) & (~3) 1009 1010 def Pack(self): 1011 pass 1012 1013 def SetFreeSpace(self, Size): 1014 self.FreeSpace = Size 1015 1016 def _GetGuid(self): 1017 return gGuidStringFormat % self.Name 1018 1019 def _SetName(self, Value): 1020 # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11 1021 self.SetField(self._NAME_, 0, Value) 1022 1023 def _GetName(self): 1024 # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11 1025 return self.GetField(self._NAME_) 1026 1027 def _SetSize(self, Size): 1028 Size1 = Size & 0xFF 1029 Size2 = (Size & 0xFF00) >> 8 1030 Size3 = (Size & 0xFF0000) >> 16 1031 self.SetField(self._SIZE_, 0, Size1, Size2, Size3) 1032 1033 def _GetSize(self): 1034 Size1, Size2, Size3 = self.GetField(self._SIZE_) 1035 return Size1 + (Size2 << 8) + (Size3 << 16) 1036 1037 def _SetType(self, Type): 1038 self.SetField(self._TYPE_, 0, Type) 1039 1040 def _GetType(self): 1041 return self.GetField(self._TYPE_)[0] 1042 1043 def _SetAttributes(self, Value): 1044 self.SetField(self._ATTR_, 0, Value) 1045 1046 def _GetAttributes(self): 1047 return self.GetField(self._ATTR_)[0] 1048 1049 def _GetFixed(self): 1050 if (self.Attributes & self.FFS_ATTRIB_FIXED) != 0: 1051 return True 1052 return False 1053 1054 def _GetCheckSum(self): 1055 if (self.Attributes & self.FFS_ATTRIB_CHECKSUM) != 0: 1056 return True 1057 return False 1058 1059 def _GetAlignment(self): 1060 return (self.Attributes & self.FFS_ATTRIB_DATA_ALIGNMENT) >> 3 1061 1062 def _SetState(self, Value): 1063 self.SetField(self._STATE_, 0, Value) 1064 1065 def _GetState(self): 1066 return self.GetField(self._STATE_)[0] 1067 1068 Name = property(_GetName, _SetName) 1069 Guid = property(_GetGuid) 1070 Type = property(_GetType, _SetType) 1071 Size = property(_GetSize, _SetSize) 1072 Attributes = property(_GetAttributes, _SetAttributes) 1073 Fixed = property(_GetFixed) 1074 Checksum = property(_GetCheckSum) 1075 Alignment = property(_GetAlignment) 1076 State = property(_GetState, _SetState) 1077 1078 1079## MultipleFv() class 1080# 1081# A class for Multiple FV 1082# 1083class MultipleFv(FirmwareVolume): 1084 def __init__(self, FvList): 1085 FirmwareVolume.__init__(self) 1086 self.BasicInfo = [] 1087 for FvPath in FvList: 1088 Fd = None 1089 FvName = os.path.splitext(os.path.split(FvPath)[1])[0] 1090 if FvPath.strip(): 1091 Fd = open(FvPath, 'rb') 1092 Buf = array('B') 1093 try: 1094 Buf.fromfile(Fd, os.path.getsize(FvPath)) 1095 except EOFError: 1096 pass 1097 1098 Fv = FirmwareVolume(FvName) 1099 Fv.frombuffer(Buf, 0, len(Buf)) 1100 1101 self.BasicInfo.append([Fv.Name, Fv.FileSystemGuid, Fv.Size]) 1102 self.FfsDict.update(Fv.FfsDict) 1103 1104## Class Eot 1105# 1106# This class is used to define Eot main entrance 1107# 1108# @param object: Inherited from object class 1109# 1110class Eot(object): 1111 ## The constructor 1112 # 1113 # @param self: The object pointer 1114 # 1115 def __init__(self, CommandLineOption=True, IsInit=True, SourceFileList=None, \ 1116 IncludeDirList=None, DecFileList=None, GuidList=None, LogFile=None, 1117 FvFileList="", MapFileList="", Report='Report.html', Dispatch=None): 1118 # Version and Copyright 1119 self.VersionNumber = ("0.02" + " " + gBUILD_VERSION) 1120 self.Version = "%prog Version " + self.VersionNumber 1121 self.Copyright = "Copyright (c) 2008 - 2018, Intel Corporation All rights reserved." 1122 self.Report = Report 1123 1124 self.IsInit = IsInit 1125 self.SourceFileList = SourceFileList 1126 self.IncludeDirList = IncludeDirList 1127 self.DecFileList = DecFileList 1128 self.GuidList = GuidList 1129 self.LogFile = LogFile 1130 self.FvFileList = FvFileList 1131 self.MapFileList = MapFileList 1132 self.Dispatch = Dispatch 1133 1134 # Check workspace environment 1135 if "EFI_SOURCE" not in os.environ: 1136 if "EDK_SOURCE" not in os.environ: 1137 pass 1138 else: 1139 EotGlobalData.gEDK_SOURCE = os.path.normpath(os.getenv("EDK_SOURCE")) 1140 else: 1141 EotGlobalData.gEFI_SOURCE = os.path.normpath(os.getenv("EFI_SOURCE")) 1142 EotGlobalData.gEDK_SOURCE = os.path.join(EotGlobalData.gEFI_SOURCE, 'Edk') 1143 1144 if "WORKSPACE" not in os.environ: 1145 EdkLogger.error("EOT", BuildToolError.ATTRIBUTE_NOT_AVAILABLE, "Environment variable not found", 1146 ExtraData="WORKSPACE") 1147 else: 1148 EotGlobalData.gWORKSPACE = os.path.normpath(os.getenv("WORKSPACE")) 1149 1150 EotGlobalData.gMACRO['WORKSPACE'] = EotGlobalData.gWORKSPACE 1151 EotGlobalData.gMACRO['EFI_SOURCE'] = EotGlobalData.gEFI_SOURCE 1152 EotGlobalData.gMACRO['EDK_SOURCE'] = EotGlobalData.gEDK_SOURCE 1153 1154 # Parse the options and args 1155 if CommandLineOption: 1156 self.ParseOption() 1157 1158 if self.FvFileList: 1159 for FvFile in GetSplitValueList(self.FvFileList, ' '): 1160 FvFile = os.path.normpath(FvFile) 1161 if not os.path.isfile(FvFile): 1162 EdkLogger.error("Eot", EdkLogger.EOT_ERROR, "Can not find file %s " % FvFile) 1163 EotGlobalData.gFV_FILE.append(FvFile) 1164 else: 1165 EdkLogger.error("Eot", EdkLogger.EOT_ERROR, "The fv file list of target platform was not specified") 1166 1167 if self.MapFileList: 1168 for MapFile in GetSplitValueList(self.MapFileList, ' '): 1169 MapFile = os.path.normpath(MapFile) 1170 if not os.path.isfile(MapFile): 1171 EdkLogger.error("Eot", EdkLogger.EOT_ERROR, "Can not find file %s " % MapFile) 1172 EotGlobalData.gMAP_FILE.append(MapFile) 1173 1174 # Generate source file list 1175 self.GenerateSourceFileList(self.SourceFileList, self.IncludeDirList) 1176 1177 # Generate guid list of dec file list 1178 self.ParseDecFile(self.DecFileList) 1179 1180 # Generate guid list from GUID list file 1181 self.ParseGuidList(self.GuidList) 1182 1183 # Init Eot database 1184 EotGlobalData.gDb = Database.Database(Database.DATABASE_PATH) 1185 EotGlobalData.gDb.InitDatabase(self.IsInit) 1186 1187 # Build ECC database 1188 self.BuildDatabase() 1189 1190 # Parse Ppi/Protocol 1191 self.ParseExecutionOrder() 1192 1193 # Merge Identifier tables 1194 self.GenerateQueryTable() 1195 1196 # Generate report database 1197 self.GenerateReportDatabase() 1198 1199 # Load Fv Info 1200 self.LoadFvInfo() 1201 1202 # Load Map Info 1203 self.LoadMapInfo() 1204 1205 # Generate Report 1206 self.GenerateReport() 1207 1208 # Convert log file 1209 self.ConvertLogFile(self.LogFile) 1210 1211 # DONE 1212 EdkLogger.quiet("EOT FINISHED!") 1213 1214 # Close Database 1215 EotGlobalData.gDb.Close() 1216 1217 ## ParseDecFile() method 1218 # 1219 # parse DEC file and get all GUID names with GUID values as {GuidName : GuidValue} 1220 # The Dict is stored in EotGlobalData.gGuidDict 1221 # 1222 # @param self: The object pointer 1223 # @param DecFileList: A list of all DEC files 1224 # 1225 def ParseDecFile(self, DecFileList): 1226 if DecFileList: 1227 path = os.path.normpath(DecFileList) 1228 lfr = open(path, 'rb') 1229 for line in lfr: 1230 path = os.path.normpath(os.path.join(EotGlobalData.gWORKSPACE, line.strip())) 1231 if os.path.exists(path): 1232 dfr = open(path, 'rb') 1233 for line in dfr: 1234 line = CleanString(line) 1235 list = line.split('=') 1236 if len(list) == 2: 1237 EotGlobalData.gGuidDict[list[0].strip()] = GuidStructureStringToGuidString(list[1].strip()) 1238 1239 1240 ## ParseGuidList() method 1241 # 1242 # Parse Guid list and get all GUID names with GUID values as {GuidName : GuidValue} 1243 # The Dict is stored in EotGlobalData.gGuidDict 1244 # 1245 # @param self: The object pointer 1246 # @param GuidList: A list of all GUID and its value 1247 # 1248 def ParseGuidList(self, GuidList): 1249 Path = os.path.join(EotGlobalData.gWORKSPACE, GuidList) 1250 if os.path.isfile(Path): 1251 for Line in open(Path): 1252 if Line.strip(): 1253 (GuidName, GuidValue) = Line.split() 1254 EotGlobalData.gGuidDict[GuidName] = GuidValue 1255 1256 ## ConvertLogFile() method 1257 # 1258 # Parse a real running log file to get real dispatch order 1259 # The result is saved to old file name + '.new' 1260 # 1261 # @param self: The object pointer 1262 # @param LogFile: A real running log file name 1263 # 1264 def ConvertLogFile(self, LogFile): 1265 newline = [] 1266 lfr = None 1267 lfw = None 1268 if LogFile: 1269 lfr = open(LogFile, 'rb') 1270 lfw = open(LogFile + '.new', 'wb') 1271 for line in lfr: 1272 line = line.strip() 1273 line = line.replace('.efi', '') 1274 index = line.find("Loading PEIM at ") 1275 if index > -1: 1276 newline.append(line[index + 55 : ]) 1277 continue 1278 index = line.find("Loading driver at ") 1279 if index > -1: 1280 newline.append(line[index + 57 : ]) 1281 continue 1282 1283 for line in newline: 1284 lfw.write(line + '\r\n') 1285 1286 if lfr: 1287 lfr.close() 1288 if lfw: 1289 lfw.close() 1290 1291 ## GenerateSourceFileList() method 1292 # 1293 # Generate a list of all source files 1294 # 1. Search the file list one by one 1295 # 2. Store inf file name with source file names under it like 1296 # { INF file name: [source file1, source file2, ...]} 1297 # 3. Search the include list to find all .h files 1298 # 4. Store source file list to EotGlobalData.gSOURCE_FILES 1299 # 5. Store INF file list to EotGlobalData.gINF_FILES 1300 # 1301 # @param self: The object pointer 1302 # @param SourceFileList: A list of all source files 1303 # @param IncludeFileList: A list of all include files 1304 # 1305 def GenerateSourceFileList(self, SourceFileList, IncludeFileList): 1306 EdkLogger.quiet("Generating source files list ... ") 1307 mSourceFileList = [] 1308 mInfFileList = [] 1309 mDecFileList = [] 1310 mFileList = {} 1311 mCurrentInfFile = '' 1312 mCurrentSourceFileList = [] 1313 1314 if SourceFileList: 1315 sfl = open(SourceFileList, 'r') 1316 for line in sfl: 1317 line = os.path.normpath(os.path.join(EotGlobalData.gWORKSPACE, line.strip())) 1318 if line[-2:].upper() == '.C' or line[-2:].upper() == '.H': 1319 if line not in mCurrentSourceFileList: 1320 mCurrentSourceFileList.append(line) 1321 mSourceFileList.append(line) 1322 EotGlobalData.gOP_SOURCE_FILES.write('%s\n' % line) 1323 if line[-4:].upper() == '.INF': 1324 if mCurrentInfFile != '': 1325 mFileList[mCurrentInfFile] = mCurrentSourceFileList 1326 mCurrentSourceFileList = [] 1327 mCurrentInfFile = os.path.normpath(os.path.join(EotGlobalData.gWORKSPACE, line)) 1328 EotGlobalData.gOP_INF.write('%s\n' % mCurrentInfFile) 1329 if mCurrentInfFile not in mFileList: 1330 mFileList[mCurrentInfFile] = mCurrentSourceFileList 1331 1332 # Get all include files from packages 1333 if IncludeFileList: 1334 ifl = open(IncludeFileList, 'rb') 1335 for line in ifl: 1336 if not line.strip(): 1337 continue 1338 newline = os.path.normpath(os.path.join(EotGlobalData.gWORKSPACE, line.strip())) 1339 for Root, Dirs, Files in os.walk(str(newline)): 1340 for File in Files: 1341 FullPath = os.path.normpath(os.path.join(Root, File)) 1342 if FullPath not in mSourceFileList and File[-2:].upper() == '.H': 1343 mSourceFileList.append(FullPath) 1344 EotGlobalData.gOP_SOURCE_FILES.write('%s\n' % FullPath) 1345 if FullPath not in mDecFileList and File.upper().find('.DEC') > -1: 1346 mDecFileList.append(FullPath) 1347 1348 EotGlobalData.gSOURCE_FILES = mSourceFileList 1349 EotGlobalData.gOP_SOURCE_FILES.close() 1350 1351 EotGlobalData.gINF_FILES = mFileList 1352 EotGlobalData.gOP_INF.close() 1353 1354 ## GenerateReport() method 1355 # 1356 # Generate final HTML report 1357 # 1358 # @param self: The object pointer 1359 # 1360 def GenerateReport(self): 1361 EdkLogger.quiet("Generating report file ... ") 1362 Rep = Report(self.Report, EotGlobalData.gFV, self.Dispatch) 1363 Rep.GenerateReport() 1364 1365 ## LoadMapInfo() method 1366 # 1367 # Load map files and parse them 1368 # 1369 # @param self: The object pointer 1370 # 1371 def LoadMapInfo(self): 1372 if EotGlobalData.gMAP_FILE != []: 1373 EdkLogger.quiet("Parsing Map file ... ") 1374 EotGlobalData.gMap = ParseMapFile(EotGlobalData.gMAP_FILE) 1375 1376 ## LoadFvInfo() method 1377 # 1378 # Load FV binary files and parse them 1379 # 1380 # @param self: The object pointer 1381 # 1382 def LoadFvInfo(self): 1383 EdkLogger.quiet("Parsing FV file ... ") 1384 EotGlobalData.gFV = MultipleFv(EotGlobalData.gFV_FILE) 1385 EotGlobalData.gFV.Dispatch(EotGlobalData.gDb) 1386 1387 for Protocol in EotGlobalData.gProtocolList: 1388 EotGlobalData.gOP_UN_MATCHED_IN_LIBRARY_CALLING.write('%s\n' %Protocol) 1389 1390 ## GenerateReportDatabase() method 1391 # 1392 # Generate data for the information needed by report 1393 # 1. Update name, macro and value of all found PPI/PROTOCOL GUID 1394 # 2. Install hard coded PPI/PROTOCOL 1395 # 1396 # @param self: The object pointer 1397 # 1398 def GenerateReportDatabase(self): 1399 EdkLogger.quiet("Generating the cross-reference table of GUID for Ppi/Protocol ... ") 1400 1401 # Update Protocol/Ppi Guid 1402 SqlCommand = """select DISTINCT GuidName from Report""" 1403 RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand) 1404 for Record in RecordSet: 1405 GuidName = Record[0] 1406 GuidMacro = '' 1407 GuidMacro2 = '' 1408 GuidValue = '' 1409 1410 # Find guid value defined in Dec file 1411 if GuidName in EotGlobalData.gGuidDict: 1412 GuidValue = EotGlobalData.gGuidDict[GuidName] 1413 SqlCommand = """update Report set GuidMacro = '%s', GuidValue = '%s' where GuidName = '%s'""" %(GuidMacro, GuidValue, GuidName) 1414 EotGlobalData.gDb.TblReport.Exec(SqlCommand) 1415 continue 1416 1417 # Search defined Macros for guid name 1418 SqlCommand ="""select DISTINCT Value, Modifier from Query where Name like '%s'""" % GuidName 1419 GuidMacroSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand) 1420 # Ignore NULL result 1421 if not GuidMacroSet: 1422 continue 1423 GuidMacro = GuidMacroSet[0][0].strip() 1424 if not GuidMacro: 1425 continue 1426 # Find Guid value of Guid Macro 1427 SqlCommand ="""select DISTINCT Value from Query2 where Value like '%%%s%%' and Model = %s""" % (GuidMacro, MODEL_IDENTIFIER_MACRO_DEFINE) 1428 GuidValueSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand) 1429 if GuidValueSet != []: 1430 GuidValue = GuidValueSet[0][0] 1431 GuidValue = GuidValue[GuidValue.find(GuidMacro) + len(GuidMacro) :] 1432 GuidValue = GuidValue.lower().replace('\\', '').replace('\r', '').replace('\n', '').replace('l', '').strip() 1433 GuidValue = GuidStructureStringToGuidString(GuidValue) 1434 SqlCommand = """update Report set GuidMacro = '%s', GuidValue = '%s' where GuidName = '%s'""" %(GuidMacro, GuidValue, GuidName) 1435 EotGlobalData.gDb.TblReport.Exec(SqlCommand) 1436 continue 1437 1438 # Update Hard Coded Ppi/Protocol 1439 SqlCommand = """select DISTINCT GuidValue, ItemType from Report where ModuleID = -2 and ItemMode = 'Produced'""" 1440 RecordSet = EotGlobalData.gDb.TblReport.Exec(SqlCommand) 1441 for Record in RecordSet: 1442 if Record[1] == 'Ppi': 1443 EotGlobalData.gPpiList[Record[0].lower()] = -2 1444 if Record[1] == 'Protocol': 1445 EotGlobalData.gProtocolList[Record[0].lower()] = -2 1446 1447 ## GenerateQueryTable() method 1448 # 1449 # Generate two tables improve query performance 1450 # 1451 # @param self: The object pointer 1452 # 1453 def GenerateQueryTable(self): 1454 EdkLogger.quiet("Generating temp query table for analysis ... ") 1455 for Identifier in EotGlobalData.gIdentifierTableList: 1456 SqlCommand = """insert into Query (Name, Modifier, Value, Model) 1457 select Name, Modifier, Value, Model from %s where (Model = %s or Model = %s)""" \ 1458 % (Identifier[0], MODEL_IDENTIFIER_VARIABLE, MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION) 1459 EotGlobalData.gDb.TblReport.Exec(SqlCommand) 1460 SqlCommand = """insert into Query2 (Name, Modifier, Value, Model) 1461 select Name, Modifier, Value, Model from %s where Model = %s""" \ 1462 % (Identifier[0], MODEL_IDENTIFIER_MACRO_DEFINE) 1463 EotGlobalData.gDb.TblReport.Exec(SqlCommand) 1464 1465 ## ParseExecutionOrder() method 1466 # 1467 # Get final execution order 1468 # 1. Search all PPI 1469 # 2. Search all PROTOCOL 1470 # 1471 # @param self: The object pointer 1472 # 1473 def ParseExecutionOrder(self): 1474 EdkLogger.quiet("Searching Ppi/Protocol ... ") 1475 for Identifier in EotGlobalData.gIdentifierTableList: 1476 ModuleID, ModuleName, ModuleGuid, SourceFileID, SourceFileFullPath, ItemName, ItemType, ItemMode, GuidName, GuidMacro, GuidValue, BelongsToFunction, Enabled = \ 1477 -1, '', '', -1, '', '', '', '', '', '', '', '', 0 1478 1479 SourceFileID = Identifier[0].replace('Identifier', '') 1480 SourceFileFullPath = Identifier[1] 1481 Identifier = Identifier[0] 1482 1483 # Find Ppis 1484 ItemMode = 'Produced' 1485 SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s 1486 where (Name like '%%%s%%' or Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \ 1487 % (Identifier, '.InstallPpi', '->InstallPpi', 'PeiInstallPpi', MODEL_IDENTIFIER_FUNCTION_CALLING) 1488 SearchPpi(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode) 1489 1490 ItemMode = 'Produced' 1491 SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s 1492 where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \ 1493 % (Identifier, '.ReInstallPpi', '->ReInstallPpi', MODEL_IDENTIFIER_FUNCTION_CALLING) 1494 SearchPpi(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 2) 1495 1496 SearchPpiCallFunction(Identifier, SourceFileID, SourceFileFullPath, ItemMode) 1497 1498 ItemMode = 'Consumed' 1499 SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s 1500 where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \ 1501 % (Identifier, '.LocatePpi', '->LocatePpi', MODEL_IDENTIFIER_FUNCTION_CALLING) 1502 SearchPpi(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode) 1503 1504 SearchFunctionCalling(Identifier, SourceFileID, SourceFileFullPath, 'Ppi', ItemMode) 1505 1506 ItemMode = 'Callback' 1507 SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s 1508 where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \ 1509 % (Identifier, '.NotifyPpi', '->NotifyPpi', MODEL_IDENTIFIER_FUNCTION_CALLING) 1510 SearchPpi(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode) 1511 1512 # Find Protocols 1513 ItemMode = 'Produced' 1514 SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s 1515 where (Name like '%%%s%%' or Name like '%%%s%%' or Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \ 1516 % (Identifier, '.InstallProtocolInterface', '.ReInstallProtocolInterface', '->InstallProtocolInterface', '->ReInstallProtocolInterface', MODEL_IDENTIFIER_FUNCTION_CALLING) 1517 SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 1) 1518 1519 SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s 1520 where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \ 1521 % (Identifier, '.InstallMultipleProtocolInterfaces', '->InstallMultipleProtocolInterfaces', MODEL_IDENTIFIER_FUNCTION_CALLING) 1522 SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 2) 1523 1524 SearchFunctionCalling(Identifier, SourceFileID, SourceFileFullPath, 'Protocol', ItemMode) 1525 1526 ItemMode = 'Consumed' 1527 SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s 1528 where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \ 1529 % (Identifier, '.LocateProtocol', '->LocateProtocol', MODEL_IDENTIFIER_FUNCTION_CALLING) 1530 SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 0) 1531 1532 SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s 1533 where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \ 1534 % (Identifier, '.HandleProtocol', '->HandleProtocol', MODEL_IDENTIFIER_FUNCTION_CALLING) 1535 SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 1) 1536 1537 SearchFunctionCalling(Identifier, SourceFileID, SourceFileFullPath, 'Protocol', ItemMode) 1538 1539 ItemMode = 'Callback' 1540 SqlCommand = """select Value, Name, BelongsToFile, StartLine, EndLine from %s 1541 where (Name like '%%%s%%' or Name like '%%%s%%') and Model = %s""" \ 1542 % (Identifier, '.RegisterProtocolNotify', '->RegisterProtocolNotify', MODEL_IDENTIFIER_FUNCTION_CALLING) 1543 SearchProtocols(SqlCommand, Identifier, SourceFileID, SourceFileFullPath, ItemMode, 0) 1544 1545 SearchFunctionCalling(Identifier, SourceFileID, SourceFileFullPath, 'Protocol', ItemMode) 1546 1547 # Hard Code 1548 EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gEfiSecPlatformInformationPpiGuid', '', '', '', 0) 1549 EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gEfiNtLoadAsDllPpiGuid', '', '', '', 0) 1550 EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gNtPeiLoadFileGuid', '', '', '', 0) 1551 EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiNtAutoScanPpiGuid', '', '', '', 0) 1552 EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gNtFwhPpiGuid', '', '', '', 0) 1553 EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiNtThunkPpiGuid', '', '', '', 0) 1554 EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiPlatformTypePpiGuid', '', '', '', 0) 1555 EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiFrequencySelectionCpuPpiGuid', '', '', '', 0) 1556 EotGlobalData.gDb.TblReport.Insert(-2, '', '', -1, '', '', 'Ppi', 'Produced', 'gPeiCachePpiGuid', '', '', '', 0) 1557 1558 EotGlobalData.gDb.Conn.commit() 1559 1560 1561 ## BuildDatabase() methoc 1562 # 1563 # Build the database for target 1564 # 1565 # @param self: The object pointer 1566 # 1567 def BuildDatabase(self): 1568 # Clean report table 1569 EotGlobalData.gDb.TblReport.Drop() 1570 EotGlobalData.gDb.TblReport.Create() 1571 1572 # Build database 1573 if self.IsInit: 1574 self.BuildMetaDataFileDatabase(EotGlobalData.gINF_FILES) 1575 EdkLogger.quiet("Building database for source code ...") 1576 c.CreateCCodeDB(EotGlobalData.gSOURCE_FILES) 1577 EdkLogger.quiet("Building database for source code done!") 1578 1579 EotGlobalData.gIdentifierTableList = GetTableList((MODEL_FILE_C, MODEL_FILE_H), 'Identifier', EotGlobalData.gDb) 1580 1581 ## BuildMetaDataFileDatabase() method 1582 # 1583 # Build the database for meta data files 1584 # 1585 # @param self: The object pointer 1586 # @param Inf_Files: A list for all INF files 1587 # 1588 def BuildMetaDataFileDatabase(self, Inf_Files): 1589 EdkLogger.quiet("Building database for meta data files ...") 1590 for InfFile in Inf_Files: 1591 if not InfFile: 1592 continue 1593 EdkLogger.quiet("Parsing %s ..." % str(InfFile)) 1594 EdkInfParser(InfFile, EotGlobalData.gDb, Inf_Files[InfFile]) 1595 1596 EotGlobalData.gDb.Conn.commit() 1597 EdkLogger.quiet("Building database for meta data files done!") 1598 1599 ## ParseOption() method 1600 # 1601 # Parse command line options 1602 # 1603 # @param self: The object pointer 1604 # 1605 def ParseOption(self): 1606 (Options, Target) = self.EotOptionParser() 1607 1608 # Set log level 1609 self.SetLogLevel(Options) 1610 1611 if Options.FvFileList: 1612 self.FvFileList = Options.FvFileList 1613 1614 if Options.MapFileList: 1615 self.MapFileList = Options.FvMapFileList 1616 1617 if Options.SourceFileList: 1618 self.SourceFileList = Options.SourceFileList 1619 1620 if Options.IncludeDirList: 1621 self.IncludeDirList = Options.IncludeDirList 1622 1623 if Options.DecFileList: 1624 self.DecFileList = Options.DecFileList 1625 1626 if Options.GuidList: 1627 self.GuidList = Options.GuidList 1628 1629 if Options.LogFile: 1630 self.LogFile = Options.LogFile 1631 1632 if Options.keepdatabase: 1633 self.IsInit = False 1634 1635 ## SetLogLevel() method 1636 # 1637 # Set current log level of the tool based on args 1638 # 1639 # @param self: The object pointer 1640 # @param Option: The option list including log level setting 1641 # 1642 def SetLogLevel(self, Option): 1643 if Option.verbose is not None: 1644 EdkLogger.SetLevel(EdkLogger.VERBOSE) 1645 elif Option.quiet is not None: 1646 EdkLogger.SetLevel(EdkLogger.QUIET) 1647 elif Option.debug is not None: 1648 EdkLogger.SetLevel(Option.debug + 1) 1649 else: 1650 EdkLogger.SetLevel(EdkLogger.INFO) 1651 1652 ## EotOptionParser() method 1653 # 1654 # Using standard Python module optparse to parse command line option of this tool. 1655 # 1656 # @param self: The object pointer 1657 # 1658 # @retval Opt A optparse.Values object containing the parsed options 1659 # @retval Args Target of build command 1660 # 1661 def EotOptionParser(self): 1662 Parser = OptionParser(description = self.Copyright, version = self.Version, prog = "Eot.exe", usage = "%prog [options]") 1663 Parser.add_option("-m", "--makefile filename", action="store", type="string", dest='MakeFile', 1664 help="Specify a makefile for the platform.") 1665 Parser.add_option("-c", "--dsc filename", action="store", type="string", dest="DscFile", 1666 help="Specify a dsc file for the platform.") 1667 Parser.add_option("-f", "--fv filename", action="store", type="string", dest="FvFileList", 1668 help="Specify fv file list, quoted by \"\".") 1669 Parser.add_option("-a", "--map filename", action="store", type="string", dest="MapFileList", 1670 help="Specify map file list, quoted by \"\".") 1671 Parser.add_option("-s", "--source files", action="store", type="string", dest="SourceFileList", 1672 help="Specify source file list by a file") 1673 Parser.add_option("-i", "--include dirs", action="store", type="string", dest="IncludeDirList", 1674 help="Specify include dir list by a file") 1675 Parser.add_option("-e", "--dec files", action="store", type="string", dest="DecFileList", 1676 help="Specify dec file list by a file") 1677 Parser.add_option("-g", "--guid list", action="store", type="string", dest="GuidList", 1678 help="Specify guid file list by a file") 1679 Parser.add_option("-l", "--log filename", action="store", type="string", dest="LogFile", 1680 help="Specify real execution log file") 1681 1682 Parser.add_option("-k", "--keepdatabase", action="store_true", type=None, help="The existing Eot database will not be cleaned except report information if this option is specified.") 1683 1684 Parser.add_option("-q", "--quiet", action="store_true", type=None, help="Disable all messages except FATAL ERRORS.") 1685 Parser.add_option("-v", "--verbose", action="store_true", type=None, help="Turn on verbose output with informational messages printed, "\ 1686 "including library instances selected, final dependency expression, "\ 1687 "and warning messages, etc.") 1688 Parser.add_option("-d", "--debug", action="store", type="int", help="Enable debug messages at specified level.") 1689 1690 (Opt, Args)=Parser.parse_args() 1691 1692 return (Opt, Args) 1693 1694## 1695# 1696# This acts like the main() function for the script, unless it is 'import'ed into another 1697# script. 1698# 1699if __name__ == '__main__': 1700 # Initialize log system 1701 EdkLogger.Initialize() 1702 EdkLogger.IsRaiseError = False 1703 EdkLogger.quiet(time.strftime("%H:%M:%S, %b.%d %Y ", time.localtime()) + "[00:00]" + "\n") 1704 1705 StartTime = time.clock() 1706 Eot = Eot(CommandLineOption=False, 1707 SourceFileList=r'C:\TestEot\Source.txt', 1708 GuidList=r'C:\TestEot\Guid.txt', 1709 FvFileList=r'C:\TestEot\FVRECOVERY.Fv') 1710 FinishTime = time.clock() 1711 1712 BuildDuration = time.strftime("%M:%S", time.gmtime(int(round(FinishTime - StartTime)))) 1713 EdkLogger.quiet("\n%s [%s]" % (time.strftime("%H:%M:%S, %b.%d %Y", time.localtime()), BuildDuration)) 1714