]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/Python/Eot/EotMain.py
791fcdfeaed8059ee7ebd4add209b7468fe29ffe
[mirror_edk2.git] / BaseTools / Source / Python / Eot / EotMain.py
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 #
11 from __future__ import absolute_import
12 import Common.LongFilePathOs as os, time, glob
13 import Common.EdkLogger as EdkLogger
14 import Eot.EotGlobalData as EotGlobalData
15 from optparse import OptionParser
16 from Common.StringUtils import NormPath
17 from Common import BuildToolError
18 from Common.Misc import GuidStructureStringToGuidString
19 from collections import OrderedDict as sdict
20 from Eot.Parser import *
21 from Eot.InfParserLite import EdkInfParser
22 from Common.StringUtils import GetSplitValueList
23 from Eot import c
24 from Eot import Database
25 from array import array
26 from Eot.Report import Report
27 from Common.BuildVersion import gBUILD_VERSION
28 from Eot.Parser import ConvertGuid
29 from Common.LongFilePathSupport import OpenLongFilePath as open
30 import struct
31 import uuid
32 import copy
33 import codecs
34 from GenFds.AprioriSection import DXE_APRIORI_GUID, PEI_APRIORI_GUID
35
36 gGuidStringFormat = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"
37 gIndention = -4
38
39 class 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 #
113 class 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 #
182 class 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 #
207 class 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 #
292 class 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 #
666 class 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 #
788 class 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 #
914 class 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 #
1083 class 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 #
1110 class 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 #
1699 if __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))