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