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