1## @file
2# Parse FV image
3#
4# Copyright (c) 2008 - 2014, 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## Import Modules
15#
16import Common.LongFilePathOs as os
17import re
18import sys
19import uuid
20import struct
21import codecs
22import copy
23
24from UserDict import IterableUserDict
25from cStringIO import StringIO
26from array import array
27from Common.LongFilePathSupport import OpenLongFilePath as open
28from CommonDataClass import *
29from Common.Misc import sdict, GuidStructureStringToGuidString
30
31import Common.EdkLogger as EdkLogger
32
33import EotGlobalData
34
35# Global definiton
36gFfsPrintTitle  = "%-36s  %-21s %8s %8s %8s  %-4s %-36s" % ("GUID", "TYPE", "OFFSET", "SIZE", "FREE", "ALIGN", "NAME")
37gFfsPrintFormat = "%36s  %-21s %8X %8X %8X  %4s %-36s"
38gGuidStringFormat = "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"
39gPeiAprioriFileNameGuid = '1b45cc0a-156a-428a-af62-49864da0e6e6'
40gAprioriGuid = 'fc510ee7-ffdc-11d4-bd41-0080c73c8881'
41gIndention = -4
42
43## Image() class
44#
45#  A class for Image
46#
47class Image(array):
48    _HEADER_ = struct.Struct("")
49    _HEADER_SIZE_ = _HEADER_.size
50
51    def __new__(cls, *args, **kwargs):
52        return array.__new__(cls, 'B')
53
54    def __init__(m, ID=None):
55        if ID == None:
56            m._ID_ = str(uuid.uuid1()).upper()
57        else:
58            m._ID_ = ID
59        m._BUF_ = None
60        m._LEN_ = None
61        m._OFF_ = None
62
63        m._SubImages = sdict() # {offset: Image()}
64
65        array.__init__(m, 'B')
66
67    def __repr__(m):
68        return m._ID_
69
70    def __len__(m):
71        Len = array.__len__(m)
72        for Offset in m._SubImages:
73            Len += len(m._SubImages[Offset])
74        return Len
75
76    def _Unpack(m):
77        m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._LEN_])
78        return len(m)
79
80    def _Pack(m, PadByte=0xFF):
81        raise NotImplementedError
82
83    def frombuffer(m, Buffer, Offset=0, Size=None):
84        m._BUF_ = Buffer
85        m._OFF_ = Offset
86        # we may need the Size information in advance if it's given
87        m._LEN_ = Size
88        m._LEN_ = m._Unpack()
89
90    def empty(m):
91        del m[0:]
92
93    def GetField(m, FieldStruct, Offset=0):
94        return FieldStruct.unpack_from(m, Offset)
95
96    def SetField(m, FieldStruct, Offset, *args):
97        # check if there's enough space
98        Size = FieldStruct.size
99        if Size > len(m):
100            m.extend([0] * (Size - len(m)))
101        FieldStruct.pack_into(m, Offset, *args)
102
103    def _SetData(m, Data):
104        if len(m) < m._HEADER_SIZE_:
105            m.extend([0] * (m._HEADER_SIZE_ - len(m)))
106        else:
107            del m[m._HEADER_SIZE_:]
108        m.extend(Data)
109
110    def _GetData(m):
111        if len(m) > m._HEADER_SIZE_:
112            return m[m._HEADER_SIZE_:]
113        return None
114
115    Data = property(_GetData, _SetData)
116
117## FirmwareVolume() class
118#
119#  A class for Firmware Volume
120#
121class FirmwareVolume(Image):
122    # Read FvLength, Attributes, HeaderLength, Checksum
123    _HEADER_ = struct.Struct("16x 1I2H8B 1Q 4x 1I 1H 1H")
124    _HEADER_SIZE_ = _HEADER_.size
125
126    _FfsGuid = "8C8CE578-8A3D-4F1C-9935-896185C32DD3"
127
128    _GUID_      = struct.Struct("16x 1I2H8B")
129    _LENGTH_    = struct.Struct("16x 16x 1Q")
130    _SIG_       = struct.Struct("16x 16x 8x 1I")
131    _ATTR_      = struct.Struct("16x 16x 8x 4x 1I")
132    _HLEN_      = struct.Struct("16x 16x 8x 4x 4x 1H")
133    _CHECKSUM_  = struct.Struct("16x 16x 8x 4x 4x 2x 1H")
134
135    def __init__(self, Name=''):
136        Image.__init__(self)
137        self.Name = Name
138        self.FfsDict = sdict()
139        self.OrderedFfsDict = sdict()
140        self.UnDispatchedFfsDict = sdict()
141        self.NoDepexFfsDict = sdict()
142        self.ProtocolList = sdict()
143
144    def CheckArchProtocol(self):
145        for Item in EotGlobalData.gArchProtocolGuids:
146            if Item.lower() not in EotGlobalData.gProtocolList:
147
148                return False
149
150        return True
151
152    def ParseDepex(self, Depex, Type):
153        List = None
154        if Type == 'Ppi':
155            List = EotGlobalData.gPpiList
156        if Type == 'Protocol':
157            List = EotGlobalData.gProtocolList
158        DepexStack = []
159        DepexList = []
160        DepexString = ''
161        FileDepex = None
162        CouldBeLoaded = True
163        for Index in range(0, len(Depex.Expression)):
164            Item = Depex.Expression[Index]
165            if Item == 0x00:
166                Index = Index + 1
167                Guid = gGuidStringFormat % Depex.Expression[Index]
168                if Guid in self.OrderedFfsDict and Depex.Expression[Index + 1] == 0x08:
169                    return (True, 'BEFORE %s' % Guid, [Guid, 'BEFORE'])
170            elif Item == 0x01:
171                Index = Index + 1
172                Guid = gGuidStringFormat % Depex.Expression[Index]
173                if Guid in self.OrderedFfsDict and Depex.Expression[Index + 1] == 0x08:
174                    return (True, 'AFTER %s' % Guid, [Guid, 'AFTER'])
175            elif Item == 0x02:
176                Index = Index + 1
177                Guid = gGuidStringFormat % Depex.Expression[Index]
178                if Guid.lower() in List:
179                    DepexStack.append(True)
180                    DepexList.append(Guid)
181                else:
182                    DepexStack.append(False)
183                    DepexList.append(Guid)
184                continue
185            elif Item == 0x03 or Item == 0x04:
186                DepexStack.append(eval(str(DepexStack.pop()) + ' ' + Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexStack.pop())))
187                DepexList.append(str(DepexList.pop()) + ' ' + Depex._OPCODE_STRING_[Item].upper() + ' ' + str(DepexList.pop()))
188            elif Item == 0x05:
189                DepexStack.append(eval(Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexStack.pop())))
190                DepexList.append(Depex._OPCODE_STRING_[Item].lower() + ' ' + str(DepexList.pop()))
191            elif Item == 0x06:
192                DepexStack.append(True)
193                DepexList.append('TRUE')
194                DepexString = DepexString + 'TRUE' + ' '
195            elif Item == 0x07:
196                DepexStack.append(False)
197                DepexList.append('False')
198                DepexString = DepexString + 'FALSE' + ' '
199            elif Item == 0x08:
200                if Index != len(Depex.Expression) - 1:
201                    CouldBeLoaded = False
202                else:
203                    CouldBeLoaded = DepexStack.pop()
204            else:
205                CouldBeLoaded = False
206        if DepexList != []:
207            DepexString = DepexList[0].strip()
208        return (CouldBeLoaded, DepexString, FileDepex)
209
210    def Dispatch(self, Db = None):
211        if Db == None:
212            return False
213        self.UnDispatchedFfsDict = copy.copy(self.FfsDict)
214        # Find PeiCore, DexCore, PeiPriori, DxePriori first
215        FfsSecCoreGuid = None
216        FfsPeiCoreGuid = None
217        FfsDxeCoreGuid = None
218        FfsPeiPrioriGuid = None
219        FfsDxePrioriGuid = None
220        for FfsID in self.UnDispatchedFfsDict:
221            Ffs = self.UnDispatchedFfsDict[FfsID]
222            if Ffs.Type == 0x03:
223                FfsSecCoreGuid = FfsID
224                continue
225            if Ffs.Type == 0x04:
226                FfsPeiCoreGuid = FfsID
227                continue
228            if Ffs.Type == 0x05:
229                FfsDxeCoreGuid = FfsID
230                continue
231            if Ffs.Guid.lower() == gPeiAprioriFileNameGuid:
232                FfsPeiPrioriGuid = FfsID
233                continue
234            if Ffs.Guid.lower() == gAprioriGuid:
235                FfsDxePrioriGuid = FfsID
236                continue
237
238        # Parse SEC_CORE first
239        if FfsSecCoreGuid != None:
240            self.OrderedFfsDict[FfsSecCoreGuid] = self.UnDispatchedFfsDict.pop(FfsSecCoreGuid)
241            self.LoadPpi(Db, FfsSecCoreGuid)
242
243        # Parse PEI first
244        if FfsPeiCoreGuid != None:
245            self.OrderedFfsDict[FfsPeiCoreGuid] = self.UnDispatchedFfsDict.pop(FfsPeiCoreGuid)
246            self.LoadPpi(Db, FfsPeiCoreGuid)
247            if FfsPeiPrioriGuid != None:
248                # Load PEIM described in priori file
249                FfsPeiPriori = self.UnDispatchedFfsDict.pop(FfsPeiPrioriGuid)
250                if len(FfsPeiPriori.Sections) == 1:
251                    Section = FfsPeiPriori.Sections.popitem()[1]
252                    if Section.Type == 0x19:
253                        GuidStruct = struct.Struct('1I2H8B')
254                        Start = 4
255                        while len(Section) > Start:
256                            Guid = GuidStruct.unpack_from(Section[Start : Start + 16])
257                            GuidString = gGuidStringFormat % Guid
258                            Start = Start + 16
259                            if GuidString in self.UnDispatchedFfsDict:
260                                self.OrderedFfsDict[GuidString] = self.UnDispatchedFfsDict.pop(GuidString)
261                                self.LoadPpi(Db, GuidString)
262
263        self.DisPatchPei(Db)
264
265        # Parse DXE then
266        if FfsDxeCoreGuid != None:
267            self.OrderedFfsDict[FfsDxeCoreGuid] = self.UnDispatchedFfsDict.pop(FfsDxeCoreGuid)
268            self.LoadProtocol(Db, FfsDxeCoreGuid)
269            if FfsDxePrioriGuid != None:
270                # Load PEIM described in priori file
271                FfsDxePriori = self.UnDispatchedFfsDict.pop(FfsDxePrioriGuid)
272                if len(FfsDxePriori.Sections) == 1:
273                    Section = FfsDxePriori.Sections.popitem()[1]
274                    if Section.Type == 0x19:
275                        GuidStruct = struct.Struct('1I2H8B')
276                        Start = 4
277                        while len(Section) > Start:
278                            Guid = GuidStruct.unpack_from(Section[Start : Start + 16])
279                            GuidString = gGuidStringFormat % Guid
280                            Start = Start + 16
281                            if GuidString in self.UnDispatchedFfsDict:
282                                self.OrderedFfsDict[GuidString] = self.UnDispatchedFfsDict.pop(GuidString)
283                                self.LoadProtocol(Db, GuidString)
284
285        self.DisPatchDxe(Db)
286
287    def DisPatchNoDepexFfs(self, Db):
288        # Last Load Drivers without Depex
289        for FfsID in self.NoDepexFfsDict:
290            NewFfs = self.NoDepexFfsDict.pop(FfsID)
291            self.OrderedFfsDict[FfsID] = NewFfs
292            self.LoadProtocol(Db, FfsID)
293
294        return True
295
296    def LoadCallbackProtocol(self):
297        IsLoad = True
298        for Protocol in self.ProtocolList:
299            for Callback in self.ProtocolList[Protocol][1]:
300                if Callback[0] not in self.OrderedFfsDict.keys():
301                    IsLoad = False
302                    continue
303            if IsLoad:
304                EotGlobalData.gProtocolList[Protocol.lower()] = self.ProtocolList[Protocol][0]
305                self.ProtocolList.pop(Protocol)
306
307    def LoadProtocol(self, Db, ModuleGuid):
308        SqlCommand = """select GuidValue from Report
309                        where SourceFileFullPath in
310                        (select Value1 from Inf where BelongsToFile =
311                        (select BelongsToFile from Inf
312                        where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
313                        and Model = %s)
314                        and ItemType = 'Protocol' and ItemMode = 'Produced'""" \
315                        % (ModuleGuid, 5001, 3007)
316        RecordSet = Db.TblReport.Exec(SqlCommand)
317        for Record in RecordSet:
318            SqlCommand = """select Value2 from Inf where BelongsToFile =
319                            (select DISTINCT BelongsToFile from Inf
320                            where Value1 =
321                            (select SourceFileFullPath from Report
322                            where GuidValue like '%s' and ItemMode = 'Callback'))
323                            and Value1 = 'FILE_GUID'""" % Record[0]
324            CallBackSet = Db.TblReport.Exec(SqlCommand)
325            if CallBackSet != []:
326                EotGlobalData.gProtocolList[Record[0].lower()] = ModuleGuid
327            else:
328                EotGlobalData.gProtocolList[Record[0].lower()] = ModuleGuid
329
330    def LoadPpi(self, Db, ModuleGuid):
331        SqlCommand = """select GuidValue from Report
332                        where SourceFileFullPath in
333                        (select Value1 from Inf where BelongsToFile =
334                        (select BelongsToFile from Inf
335                        where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
336                        and Model = %s)
337                        and ItemType = 'Ppi' and ItemMode = 'Produced'""" \
338                        % (ModuleGuid, 5001, 3007)
339        RecordSet = Db.TblReport.Exec(SqlCommand)
340        for Record in RecordSet:
341            EotGlobalData.gPpiList[Record[0].lower()] = ModuleGuid
342
343    def DisPatchDxe(self, Db):
344        IsInstalled = False
345        ScheduleList = sdict()
346        for FfsID in self.UnDispatchedFfsDict:
347            CouldBeLoaded = False
348            DepexString = ''
349            FileDepex = None
350            Ffs = self.UnDispatchedFfsDict[FfsID]
351            if Ffs.Type == 0x07:
352                # Get Depex
353                IsFoundDepex = False
354                for Section in Ffs.Sections.values():
355                    # Find Depex
356                    if Section.Type == 0x13:
357                        IsFoundDepex = True
358                        CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(Section._SubImages[4], 'Protocol')
359                        break
360                    if Section.Type == 0x01:
361                        CompressSections = Section._SubImages[4]
362                        for CompressSection in CompressSections.Sections:
363                            if CompressSection.Type == 0x13:
364                                IsFoundDepex = True
365                                CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(CompressSection._SubImages[4], 'Protocol')
366                                break
367                            if CompressSection.Type == 0x02:
368                                NewSections = CompressSection._SubImages[4]
369                                for NewSection in NewSections.Sections:
370                                    if NewSection.Type == 0x13:
371                                        IsFoundDepex = True
372                                        CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(NewSection._SubImages[4], 'Protocol')
373                                        break
374
375                # Not find Depex
376                if not IsFoundDepex:
377                    CouldBeLoaded = self.CheckArchProtocol()
378                    DepexString = ''
379                    FileDepex = None
380
381                # Append New Ffs
382                if CouldBeLoaded:
383                    IsInstalled = True
384                    NewFfs = self.UnDispatchedFfsDict.pop(FfsID)
385                    NewFfs.Depex = DepexString
386                    if FileDepex != None:
387                        ScheduleList.insert.insert(FileDepex[1], FfsID, NewFfs, FileDepex[0])
388                    else:
389                        ScheduleList[FfsID] = NewFfs
390                else:
391                    self.UnDispatchedFfsDict[FfsID].Depex = DepexString
392
393        for FfsID in ScheduleList:
394            NewFfs = ScheduleList.pop(FfsID)
395            FfsName = 'UnKnown'
396            self.OrderedFfsDict[FfsID] = NewFfs
397            self.LoadProtocol(Db, FfsID)
398
399            SqlCommand = """select Value2 from Inf
400                            where BelongsToFile = (select BelongsToFile from Inf where Value1 = 'FILE_GUID' and lower(Value2) = lower('%s') and Model = %s)
401                            and Model = %s and Value1='BASE_NAME'""" % (FfsID, 5001, 5001)
402            RecordSet = Db.TblReport.Exec(SqlCommand)
403            if RecordSet != []:
404                FfsName = RecordSet[0][0]
405
406        if IsInstalled:
407            self.DisPatchDxe(Db)
408
409    def DisPatchPei(self, Db):
410        IsInstalled = False
411        for FfsID in self.UnDispatchedFfsDict:
412            CouldBeLoaded = True
413            DepexString = ''
414            FileDepex = None
415            Ffs = self.UnDispatchedFfsDict[FfsID]
416            if Ffs.Type == 0x06 or Ffs.Type == 0x08:
417                # Get Depex
418                for Section in Ffs.Sections.values():
419                    if Section.Type == 0x1B:
420                        CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(Section._SubImages[4], 'Ppi')
421                        break
422
423                    if Section.Type == 0x01:
424                        CompressSections = Section._SubImages[4]
425                        for CompressSection in CompressSections.Sections:
426                            if CompressSection.Type == 0x1B:
427                                CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(CompressSection._SubImages[4], 'Ppi')
428                                break
429                            if CompressSection.Type == 0x02:
430                                NewSections = CompressSection._SubImages[4]
431                                for NewSection in NewSections.Sections:
432                                    if NewSection.Type == 0x1B:
433                                        CouldBeLoaded, DepexString, FileDepex = self.ParseDepex(NewSection._SubImages[4], 'Ppi')
434                                        break
435
436                # Append New Ffs
437                if CouldBeLoaded:
438                    IsInstalled = True
439                    NewFfs = self.UnDispatchedFfsDict.pop(FfsID)
440                    NewFfs.Depex = DepexString
441                    self.OrderedFfsDict[FfsID] = NewFfs
442                    self.LoadPpi(Db, FfsID)
443                else:
444                    self.UnDispatchedFfsDict[FfsID].Depex = DepexString
445
446        if IsInstalled:
447            self.DisPatchPei(Db)
448
449
450    def __str__(self):
451        global gIndention
452        gIndention += 4
453        FvInfo = '\n' + ' ' * gIndention
454        FvInfo +=  "[FV:%s] file_system=%s size=%x checksum=%s\n" % (self.Name, self.FileSystemGuid, self.Size, self.Checksum)
455        FfsInfo = "\n".join([str(self.FfsDict[FfsId]) for FfsId in self.FfsDict])
456        gIndention -= 4
457        return FvInfo + FfsInfo
458
459    def _Unpack(self):
460        Size = self._LENGTH_.unpack_from(self._BUF_, self._OFF_)[0]
461        self.empty()
462        self.extend(self._BUF_[self._OFF_:self._OFF_+Size])
463
464        # traverse the FFS
465        EndOfFv = Size
466        FfsStartAddress = self.HeaderSize
467        LastFfsObj = None
468        while FfsStartAddress < EndOfFv:
469            FfsObj = Ffs()
470            FfsObj.frombuffer(self, FfsStartAddress)
471            FfsId = repr(FfsObj)
472            if ((self.Attributes & 0x00000800) != 0 and len(FfsObj) == 0xFFFFFF) \
473                or ((self.Attributes & 0x00000800) == 0 and len(FfsObj) == 0):
474                if LastFfsObj != None:
475                    LastFfsObj.FreeSpace = EndOfFv - LastFfsObj._OFF_ - len(LastFfsObj)
476            else:
477                if FfsId in self.FfsDict:
478                    EdkLogger.error("FV", 0, "Duplicate GUID in FFS",
479                                    ExtraData="\t%s @ %s\n\t%s @ %s" \
480                                    % (FfsObj.Guid, FfsObj.Offset,
481                                       self.FfsDict[FfsId].Guid, self.FfsDict[FfsId].Offset))
482                self.FfsDict[FfsId] = FfsObj
483                if LastFfsObj != None:
484                    LastFfsObj.FreeSpace = FfsStartAddress - LastFfsObj._OFF_ - len(LastFfsObj)
485
486            FfsStartAddress += len(FfsObj)
487            #
488            # align to next 8-byte aligned address: A = (A + 8 - 1) & (~(8 - 1))
489            # The next FFS must be at the latest next 8-byte aligned address
490            #
491            FfsStartAddress = (FfsStartAddress + 7) & (~7)
492            LastFfsObj = FfsObj
493
494    def _GetAttributes(self):
495        return self.GetField(self._ATTR_, 0)[0]
496
497    def _GetSize(self):
498        return self.GetField(self._LENGTH_, 0)[0]
499
500    def _GetChecksum(self):
501        return self.GetField(self._CHECKSUM_, 0)[0]
502
503    def _GetHeaderLength(self):
504        return self.GetField(self._HLEN_, 0)[0]
505
506    def _GetFileSystemGuid(self):
507        return gGuidStringFormat % self.GetField(self._GUID_, 0)
508
509    Attributes = property(_GetAttributes)
510    Size = property(_GetSize)
511    Checksum = property(_GetChecksum)
512    HeaderSize = property(_GetHeaderLength)
513    FileSystemGuid = property(_GetFileSystemGuid)
514
515## CompressedImage() class
516#
517#  A class for Compressed Image
518#
519class CompressedImage(Image):
520    # UncompressedLength = 4-byte
521    # CompressionType = 1-byte
522    _HEADER_ = struct.Struct("1I 1B")
523    _HEADER_SIZE_ = _HEADER_.size
524
525    _ORIG_SIZE_     = struct.Struct("1I")
526    _CMPRS_TYPE_    = struct.Struct("4x 1B")
527
528    def __init__(m, CompressedData=None, CompressionType=None, UncompressedLength=None):
529        Image.__init__(m)
530        if UncompressedLength != None:
531            m.UncompressedLength = UncompressedLength
532        if CompressionType != None:
533            m.CompressionType = CompressionType
534        if CompressedData != None:
535            m.Data = CompressedData
536
537    def __str__(m):
538        global gIndention
539        S = "algorithm=%s uncompressed=%x" % (m.CompressionType, m.UncompressedLength)
540        for Sec in m.Sections:
541            S += '\n' + str(Sec)
542
543        return S
544
545    def _SetOriginalSize(m, Size):
546        m.SetField(m._ORIG_SIZE_, 0, Size)
547
548    def _GetOriginalSize(m):
549        return m.GetField(m._ORIG_SIZE_)[0]
550
551    def _SetCompressionType(m, Type):
552        m.SetField(m._CMPRS_TYPE_, 0, Type)
553
554    def _GetCompressionType(m):
555        return m.GetField(m._CMPRS_TYPE_)[0]
556
557    def _GetSections(m):
558        try:
559            import EfiCompressor
560            TmpData = EfiCompressor.FrameworkDecompress(
561                                        m[m._HEADER_SIZE_:],
562                                        len(m) - m._HEADER_SIZE_
563                                        )
564            DecData = array('B')
565            DecData.fromstring(TmpData)
566        except:
567            import EfiCompressor
568            TmpData = EfiCompressor.UefiDecompress(
569                                        m[m._HEADER_SIZE_:],
570                                        len(m) - m._HEADER_SIZE_
571                                        )
572            DecData = array('B')
573            DecData.fromstring(TmpData)
574
575        SectionList = []
576        Offset = 0
577        while Offset < len(DecData):
578            Sec = Section()
579            try:
580                Sec.frombuffer(DecData, Offset)
581                Offset += Sec.Size
582                # the section is aligned to 4-byte boundary
583            except:
584                break
585            SectionList.append(Sec)
586        return SectionList
587
588    UncompressedLength = property(_GetOriginalSize, _SetOriginalSize)
589    CompressionType = property(_GetCompressionType, _SetCompressionType)
590    Sections = property(_GetSections)
591
592## GuidDefinedImage() class
593#
594#  A class for GUID Defined Image
595#
596class GuidDefinedImage(Image):
597    _HEADER_ = struct.Struct("1I2H8B 1H 1H")
598    _HEADER_SIZE_ = _HEADER_.size
599
600    _GUID_          = struct.Struct("1I2H8B")
601    _DATA_OFFSET_   = struct.Struct("16x 1H")
602    _ATTR_          = struct.Struct("18x 1H")
603
604    CRC32_GUID          = "FC1BCDB0-7D31-49AA-936A-A4600D9DD083"
605    TIANO_COMPRESS_GUID = 'A31280AD-481E-41B6-95E8-127F4C984779'
606    LZMA_COMPRESS_GUID  = 'EE4E5898-3914-4259-9D6E-DC7BD79403CF'
607
608    def __init__(m, SectionDefinitionGuid=None, DataOffset=None, Attributes=None, Data=None):
609        Image.__init__(m)
610        if SectionDefinitionGuid != None:
611            m.SectionDefinitionGuid = SectionDefinitionGuid
612        if DataOffset != None:
613            m.DataOffset = DataOffset
614        if Attributes != None:
615            m.Attributes = Attributes
616        if Data != None:
617            m.Data = Data
618
619    def __str__(m):
620        S = "guid=%s" % (gGuidStringFormat % m.SectionDefinitionGuid)
621        for Sec in m.Sections:
622            S += "\n" + str(Sec)
623        return S
624
625    def _Unpack(m):
626        # keep header in this Image object
627        m.empty()
628        m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._LEN_])
629        return len(m)
630
631    def _SetAttribute(m, Attribute):
632        m.SetField(m._ATTR_, 0, Attribute)
633
634    def _GetAttribute(m):
635        return m.GetField(m._ATTR_)[0]
636
637    def _SetGuid(m, Guid):
638        m.SetField(m._GUID_, 0, Guid)
639
640    def _GetGuid(m):
641        return m.GetField(m._GUID_)
642
643    def _SetDataOffset(m, Offset):
644        m.SetField(m._DATA_OFFSET_, 0, Offset)
645
646    def _GetDataOffset(m):
647        return m.GetField(m._DATA_OFFSET_)[0]
648
649    def _GetSections(m):
650        SectionList = []
651        Guid = gGuidStringFormat % m.SectionDefinitionGuid
652        if Guid == m.CRC32_GUID:
653            # skip the CRC32 value, we don't do CRC32 verification here
654            Offset = m.DataOffset - 4
655            while Offset < len(m):
656                Sec = Section()
657                try:
658                    Sec.frombuffer(m, Offset)
659                    Offset += Sec.Size
660                    # the section is aligned to 4-byte boundary
661                    Offset = (Offset + 3) & (~3)
662                except:
663                    break
664                SectionList.append(Sec)
665        elif Guid == m.TIANO_COMPRESS_GUID:
666            try:
667                import EfiCompressor
668                # skip the header
669                Offset = m.DataOffset - 4
670                TmpData = EfiCompressor.FrameworkDecompress(m[Offset:], len(m)-Offset)
671                DecData = array('B')
672                DecData.fromstring(TmpData)
673                Offset = 0
674                while Offset < len(DecData):
675                    Sec = Section()
676                    try:
677                        Sec.frombuffer(DecData, Offset)
678                        Offset += Sec.Size
679                        # the section is aligned to 4-byte boundary
680                        Offset = (Offset + 3) & (~3)
681                    except:
682                        break
683                    SectionList.append(Sec)
684            except:
685                pass
686        elif Guid == m.LZMA_COMPRESS_GUID:
687            try:
688                import LzmaCompressor
689                # skip the header
690                Offset = m.DataOffset - 4
691                TmpData = LzmaCompressor.LzmaDecompress(m[Offset:], len(m)-Offset)
692                DecData = array('B')
693                DecData.fromstring(TmpData)
694                Offset = 0
695                while Offset < len(DecData):
696                    Sec = Section()
697                    try:
698                        Sec.frombuffer(DecData, Offset)
699                        Offset += Sec.Size
700                        # the section is aligned to 4-byte boundary
701                        Offset = (Offset + 3) & (~3)
702                    except:
703                        break
704                    SectionList.append(Sec)
705            except:
706                pass
707
708        return SectionList
709
710    Attributes = property(_GetAttribute, _SetAttribute)
711    SectionDefinitionGuid = property(_GetGuid, _SetGuid)
712    DataOffset = property(_GetDataOffset, _SetDataOffset)
713    Sections = property(_GetSections)
714
715## Depex() class
716#
717#  A class for Depex
718#
719class Depex(Image):
720    _HEADER_ = struct.Struct("")
721    _HEADER_SIZE_ = 0
722
723    _GUID_          = struct.Struct("1I2H8B")
724    _OPCODE_        = struct.Struct("1B")
725
726    _OPCODE_STRING_ = {
727        0x00    :   "BEFORE",
728        0x01    :   "AFTER",
729        0x02    :   "PUSH",
730        0x03    :   "AND",
731        0x04    :   "OR",
732        0x05    :   "NOT",
733        0x06    :   "TRUE",
734        0x07    :   "FALSE",
735        0x08    :   "END",
736        0x09    :   "SOR"
737    }
738
739    _NEXT_ = {
740        -1      :   _OPCODE_,   # first one in depex must be an opcdoe
741        0x00    :   _GUID_,     #"BEFORE",
742        0x01    :   _GUID_,     #"AFTER",
743        0x02    :   _GUID_,     #"PUSH",
744        0x03    :   _OPCODE_,   #"AND",
745        0x04    :   _OPCODE_,   #"OR",
746        0x05    :   _OPCODE_,   #"NOT",
747        0x06    :   _OPCODE_,   #"TRUE",
748        0x07    :   _OPCODE_,   #"FALSE",
749        0x08    :   None,       #"END",
750        0x09    :   _OPCODE_,   #"SOR"
751    }
752
753    def __init__(m):
754        Image.__init__(m)
755        m._ExprList = []
756
757    def __str__(m):
758        global gIndention
759        gIndention += 4
760        Indention = ' ' * gIndention
761        S = '\n'
762        for T in m.Expression:
763            if T in m._OPCODE_STRING_:
764                S += Indention + m._OPCODE_STRING_[T]
765                if T not in [0x00, 0x01, 0x02]:
766                    S += '\n'
767            else:
768                S += ' ' + gGuidStringFormat % T + '\n'
769        gIndention -= 4
770        return S
771
772    def _Unpack(m):
773        # keep header in this Image object
774        m.empty()
775        m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._LEN_])
776        return len(m)
777
778    def _GetExpression(m):
779        if m._ExprList == []:
780            Offset = 0
781            CurrentData = m._OPCODE_
782            while Offset < len(m):
783                Token = CurrentData.unpack_from(m, Offset)
784                Offset += CurrentData.size
785                if len(Token) == 1:
786                    Token = Token[0]
787                    if Token in m._NEXT_:
788                        CurrentData = m._NEXT_[Token]
789                    else:
790                        CurrentData = m._GUID_
791                else:
792                    CurrentData = m._OPCODE_
793                m._ExprList.append(Token)
794                if CurrentData == None:
795                    break
796        return m._ExprList
797
798    Expression = property(_GetExpression)
799
800## Ui() class
801#
802#  A class for Ui
803#
804class Ui(Image):
805    _HEADER_ = struct.Struct("")
806    _HEADER_SIZE_ = 0
807
808    def __init__(m):
809        Image.__init__(m)
810
811    def __str__(m):
812        return m.String
813
814    def _Unpack(m):
815        # keep header in this Image object
816        m.empty()
817        m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._LEN_])
818        return len(m)
819
820    def _GetUiString(m):
821        return codecs.utf_16_decode(m[0:-2].tostring())[0]
822
823    String = property(_GetUiString)
824
825## Section() class
826#
827#  A class for Section
828#
829class Section(Image):
830    _TypeName = {
831        0x00    :   "<unknown>",
832        0x01    :   "COMPRESSION",
833        0x02    :   "GUID_DEFINED",
834        0x10    :   "PE32",
835        0x11    :   "PIC",
836        0x12    :   "TE",
837        0x13    :   "DXE_DEPEX",
838        0x14    :   "VERSION",
839        0x15    :   "USER_INTERFACE",
840        0x16    :   "COMPATIBILITY16",
841        0x17    :   "FIRMWARE_VOLUME_IMAGE",
842        0x18    :   "FREEFORM_SUBTYPE_GUID",
843        0x19    :   "RAW",
844        0x1B    :   "PEI_DEPEX"
845    }
846
847    _SectionSubImages = {
848        0x01    :   CompressedImage,
849        0x02    :   GuidDefinedImage,
850        0x17    :   FirmwareVolume,
851        0x13    :   Depex,
852        0x1B    :   Depex,
853        0x15    :   Ui
854    }
855
856    # Size = 3-byte
857    # Type = 1-byte
858    _HEADER_ = struct.Struct("3B 1B")
859    _HEADER_SIZE_ = _HEADER_.size
860
861    # SubTypeGuid
862    # _FREE_FORM_SUBTYPE_GUID_HEADER_ = struct.Struct("1I2H8B")
863
864    _SIZE_          = struct.Struct("3B")
865    _TYPE_          = struct.Struct("3x 1B")
866
867    def __init__(m, Type=None, Size=None):
868        Image.__init__(m)
869        m._Alignment = 1
870        if Type != None:
871            m.Type = Type
872        if Size != None:
873            m.Size = Size
874
875    def __str__(m):
876        global gIndention
877        gIndention += 4
878        SectionInfo = ' ' * gIndention
879        if m.Type in m._TypeName:
880            SectionInfo += "[SECTION:%s] offset=%x size=%x" % (m._TypeName[m.Type], m._OFF_, m.Size)
881        else:
882            SectionInfo += "[SECTION:%x<unknown>] offset=%x size=%x " % (m.Type, m._OFF_, m.Size)
883        for Offset in m._SubImages:
884            SectionInfo += ", " + str(m._SubImages[Offset])
885        gIndention -= 4
886        return SectionInfo
887
888    def _Unpack(m):
889        m.empty()
890        Type, = m._TYPE_.unpack_from(m._BUF_, m._OFF_)
891        Size1, Size2, Size3 = m._SIZE_.unpack_from(m._BUF_, m._OFF_)
892        Size = Size1 + (Size2 << 8) + (Size3 << 16)
893
894        if Type not in m._SectionSubImages:
895            # no need to extract sub-image, keep all in this Image object
896            m.extend(m._BUF_[m._OFF_ : m._OFF_ + Size])
897        else:
898            # keep header in this Image object
899            m.extend(m._BUF_[m._OFF_ : m._OFF_ + m._HEADER_SIZE_])
900            #
901            # use new Image object to represent payload, which may be another kind
902            # of image such as PE32
903            #
904            PayloadOffset = m._HEADER_SIZE_
905            PayloadLen = m.Size - m._HEADER_SIZE_
906            Payload = m._SectionSubImages[m.Type]()
907            Payload.frombuffer(m._BUF_, m._OFF_ + m._HEADER_SIZE_, PayloadLen)
908            m._SubImages[PayloadOffset] = Payload
909
910        return Size
911
912    def _SetSize(m, Size):
913        Size1 = Size & 0xFF
914        Size2 = (Size & 0xFF00) >> 8
915        Size3 = (Size & 0xFF0000) >> 16
916        m.SetField(m._SIZE_, 0, Size1, Size2, Size3)
917
918    def _GetSize(m):
919        Size1, Size2, Size3 = m.GetField(m._SIZE_)
920        return Size1 + (Size2 << 8) + (Size3 << 16)
921
922    def _SetType(m, Type):
923        m.SetField(m._TYPE_, 0, Type)
924
925    def _GetType(m):
926        return m.GetField(m._TYPE_)[0]
927
928    def _GetAlignment(m):
929        return m._Alignment
930
931    def _SetAlignment(m, Alignment):
932        m._Alignment = Alignment
933        AlignmentMask = Alignment - 1
934        # section alignment is actually for payload, so we need to add header size
935        PayloadOffset = m._OFF_ + m._HEADER_SIZE_
936        if (PayloadOffset & (~AlignmentMask)) == 0:
937            return
938        NewOffset = (PayloadOffset + AlignmentMask) & (~AlignmentMask)
939        while (NewOffset - PayloadOffset) < m._HEADER_SIZE_:
940            NewOffset += m._Alignment
941
942    def tofile(m, f):
943        m.Size = len(m)
944        Image.tofile(m, f)
945        for Offset in m._SubImages:
946            m._SubImages[Offset].tofile(f)
947
948    Type = property(_GetType, _SetType)
949    Size = property(_GetSize, _SetSize)
950    Alignment = property(_GetAlignment, _SetAlignment)
951    # SubTypeGuid = property(_GetGuid, _SetGuid)
952
953## PadSection() class
954#
955#  A class for Pad Section
956#
957class PadSection(Section):
958    def __init__(m, Size):
959        Section.__init__(m)
960        m.Type = 0x19
961        m.Size = Size
962        m.Data = [0] * (Size - m._HEADER_SIZE_)
963
964## Ffs() class
965#
966#  A class for Ffs Section
967#
968class Ffs(Image):
969    _FfsFormat = "24B%(payload_size)sB"
970    # skip IntegrityCheck
971    _HEADER_ = struct.Struct("1I2H8B 2x 1B 1B 3B 1B")
972    _HEADER_SIZE_ = _HEADER_.size
973
974    _NAME_      = struct.Struct("1I2H8B")
975    _INT_CHECK_ = struct.Struct("16x 1H")
976    _TYPE_      = struct.Struct("18x 1B")
977    _ATTR_      = struct.Struct("19x 1B")
978    _SIZE_      = struct.Struct("20x 3B")
979    _STATE_     = struct.Struct("23x 1B")
980
981    VTF_GUID = "1BA0062E-C779-4582-8566-336AE8F78F09"
982
983    FFS_ATTRIB_FIXED              = 0x04
984    FFS_ATTRIB_DATA_ALIGNMENT     = 0x38
985    FFS_ATTRIB_CHECKSUM           = 0x40
986
987    _TypeName = {
988        0x00    :   "<unknown>",
989        0x01    :   "RAW",
990        0x02    :   "FREEFORM",
991        0x03    :   "SECURITY_CORE",
992        0x04    :   "PEI_CORE",
993        0x05    :   "DXE_CORE",
994        0x06    :   "PEIM",
995        0x07    :   "DRIVER",
996        0x08    :   "COMBINED_PEIM_DRIVER",
997        0x09    :   "APPLICATION",
998        0x0A    :   "SMM",
999        0x0B    :   "FIRMWARE_VOLUME_IMAGE",
1000        0x0C    :   "COMBINED_SMM_DXE",
1001        0x0D    :   "SMM_CORE",
1002        0xc0    :   "OEM_MIN",
1003        0xdf    :   "OEM_MAX",
1004        0xe0    :   "DEBUG_MIN",
1005        0xef    :   "DEBUG_MAX",
1006        0xf0    :   "FFS_MIN",
1007        0xff    :   "FFS_MAX",
1008        0xf0    :   "FFS_PAD",
1009    }
1010
1011    def __init__(self):
1012        Image.__init__(self)
1013        self.FreeSpace = 0
1014
1015        self.Sections = sdict()
1016        self.Depex = ''
1017
1018        self.__ID__ = None
1019
1020    def __str__(self):
1021        global gIndention
1022        gIndention += 4
1023        Indention = ' ' * gIndention
1024        FfsInfo = Indention
1025        FfsInfo +=  "[FFS:%s] offset=%x size=%x guid=%s free_space=%x alignment=%s\n" % \
1026                    (Ffs._TypeName[self.Type], self._OFF_, self.Size, self.Guid, self.FreeSpace, self.Alignment)
1027        SectionInfo = '\n'.join([str(self.Sections[Offset]) for Offset in self.Sections])
1028        gIndention -= 4
1029        return FfsInfo + SectionInfo + "\n"
1030
1031    def __len__(self):
1032        return self.Size
1033
1034    def __repr__(self):
1035        return self.__ID__
1036
1037    def _Unpack(self):
1038        Size1, Size2, Size3 = self._SIZE_.unpack_from(self._BUF_, self._OFF_)
1039        Size = Size1 + (Size2 << 8) + (Size3 << 16)
1040        self.empty()
1041        self.extend(self._BUF_[self._OFF_ : self._OFF_ + Size])
1042
1043        # Pad FFS may use the same GUID. We need to avoid it.
1044        if self.Type == 0xf0:
1045            self.__ID__ = str(uuid.uuid1()).upper()
1046        else:
1047            self.__ID__ = self.Guid
1048
1049        # Traverse the SECTION. RAW and PAD do not have sections
1050        if self.Type not in [0xf0, 0x01] and Size > 0 and Size < 0xFFFFFF:
1051            EndOfFfs = Size
1052            SectionStartAddress = self._HEADER_SIZE_
1053            while SectionStartAddress < EndOfFfs:
1054                SectionObj = Section()
1055                SectionObj.frombuffer(self, SectionStartAddress)
1056                #f = open(repr(SectionObj), 'wb')
1057                #SectionObj.Size = 0
1058                #SectionObj.tofile(f)
1059                #f.close()
1060                self.Sections[SectionStartAddress] = SectionObj
1061                SectionStartAddress += len(SectionObj)
1062                SectionStartAddress = (SectionStartAddress + 3) & (~3)
1063
1064    def Pack(self):
1065        pass
1066
1067    def SetFreeSpace(self, Size):
1068        self.FreeSpace = Size
1069
1070    def _GetGuid(self):
1071        return gGuidStringFormat % self.Name
1072
1073    def _SetName(self, Value):
1074        # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11
1075        self.SetField(self._NAME_, 0, Value)
1076
1077    def _GetName(self):
1078        # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11
1079        return self.GetField(self._NAME_)
1080
1081    def _SetSize(m, Size):
1082        Size1 = Size & 0xFF
1083        Size2 = (Size & 0xFF00) >> 8
1084        Size3 = (Size & 0xFF0000) >> 16
1085        m.SetField(m._SIZE_, 0, Size1, Size2, Size3)
1086
1087    def _GetSize(m):
1088        Size1, Size2, Size3 = m.GetField(m._SIZE_)
1089        return Size1 + (Size2 << 8) + (Size3 << 16)
1090
1091    def _SetType(m, Type):
1092        m.SetField(m._TYPE_, 0, Type)
1093
1094    def _GetType(m):
1095        return m.GetField(m._TYPE_)[0]
1096
1097    def _SetAttributes(self, Value):
1098        self.SetField(m._ATTR_, 0, Value)
1099
1100    def _GetAttributes(self):
1101        return self.GetField(self._ATTR_)[0]
1102
1103    def _GetFixed(self):
1104        if (self.Attributes & self.FFS_ATTRIB_FIXED) != 0:
1105            return True
1106        return False
1107
1108    def _GetCheckSum(self):
1109        if (self.Attributes & self.FFS_ATTRIB_CHECKSUM) != 0:
1110            return True
1111        return False
1112
1113    def _GetAlignment(self):
1114        return (self.Attributes & self.FFS_ATTRIB_DATA_ALIGNMENT) >> 3
1115
1116    def _SetState(self, Value):
1117        self.SetField(m._STATE_, 0, Value)
1118
1119    def _GetState(self):
1120        return self.GetField(m._STATE_)[0]
1121
1122    Name = property(_GetName, _SetName)
1123    Guid = property(_GetGuid)
1124    Type = property(_GetType, _SetType)
1125    Size = property(_GetSize, _SetSize)
1126    Attributes = property(_GetAttributes, _SetAttributes)
1127    Fixed = property(_GetFixed)
1128    Checksum = property(_GetCheckSum)
1129    Alignment = property(_GetAlignment)
1130    State = property(_GetState, _SetState)
1131
1132## PeImage() class
1133#
1134#  A class for PE Image
1135#
1136class PeImage:
1137    #
1138    # just extract e_lfanew
1139    #
1140    _DosHeaderFormat = "60x 1I"
1141    #
1142    # Machine
1143    # NumberOfSections
1144    # SizeOfOptionalHeader
1145    #
1146    _FileHeaderFormat = "4x 1H 1H 4x 4x 4x 1H 2x"
1147    #
1148    # Magic
1149    # SizeOfImage
1150    # SizeOfHeaders
1151    # CheckSum
1152    # NumberOfRvaAndSizes
1153    #
1154    _OptionalHeader32Format = "1H 54x 1I 1I 1I 24x 1I"
1155    _OptionalHeader64Format = ""
1156    def __init__(self, Buf, Offset, Size):
1157        self.Offset = Offset
1158        self.Size = Size
1159        self.Machine = 0x014c # IA32
1160        self.NumberOfSections = 0
1161        self.SizeOfImage = 0
1162        self.SizeOfOptionalHeader = 0
1163        self.Checksum = 0
1164        self._PeImageBuf = Buf
1165        self._SectionList = []
1166
1167        self._DosHeader = struct.Struct(PeImage._DosHeaderFormat)
1168        self._FileHeader = struct.Struct(PeImage._FileHeaderFormat)
1169        self._OptionalHeader32 = struct.Struct(PeImage._OptionalHeader32Format)
1170
1171        self.Buffer = None
1172
1173        self._Unpack()
1174
1175    def __str__(self):
1176        pass
1177
1178    def __len__(self):
1179        return self.Size
1180
1181    def _Unpack(self):
1182        # from DOS header, get the offset of PE header
1183        FileHeaderOffset, = self._DosHeader.unpack_from(self._PeImageBuf, self.Offset)
1184        if FileHeaderOffset < struct.calcsize(self._DosHeaderFormat):
1185            EdkLogger.error("PE+", 0, "Invalid offset of IMAGE_FILE_HEADER: %s" % FileHeaderOffset)
1186
1187        # from FILE header, get the optional header size
1188        self.Machine, self.NumberOfSections, self.SizeOfOptionalHeader = \
1189            self._FileHeader.unpack_from(self._PeImageBuf, self.Offset + FileHeaderOffset)
1190
1191        print "Machine=%x NumberOfSections=%x SizeOfOptionalHeader=%x" % (self.Machine, self.NumberOfSections, self.SizeOfOptionalHeader)
1192        # optional header follows the FILE header
1193        OptionalHeaderOffset = FileHeaderOffset + struct.calcsize(self._FileHeaderFormat)
1194        Magic, self.SizeOfImage, SizeOfHeaders, self.Checksum, NumberOfRvaAndSizes = \
1195            self._OptionalHeader32.unpack_from(self._PeImageBuf, self.Offset + OptionalHeaderOffset)
1196        print "Magic=%x SizeOfImage=%x SizeOfHeaders=%x, Checksum=%x, NumberOfRvaAndSizes=%x" % (Magic, self.SizeOfImage, SizeOfHeaders, self.Checksum, NumberOfRvaAndSizes)
1197
1198        PeImageSectionTableOffset = OptionalHeaderOffset + self.SizeOfOptionalHeader
1199        PeSections = PeSectionTable(self._PeImageBuf, self.Offset + PeImageSectionTableOffset, self.NumberOfSections)
1200
1201        print "%x" % PeSections.GetFileAddress(0x3920)
1202
1203## PeSectionTable() class
1204#
1205#  A class for PE Section Table
1206#
1207class PeSectionTable:
1208    def __init__(self, Buf, Offset, NumberOfSections):
1209        self._SectionList = []
1210
1211        SectionHeaderOffset = Offset
1212        for TableIndex in range(0, NumberOfSections):
1213            SectionHeader = PeSectionHeader(Buf, SectionHeaderOffset)
1214            self._SectionList.append(SectionHeader)
1215            SectionHeaderOffset += len(SectionHeader)
1216            print SectionHeader
1217
1218    def GetFileAddress(self, Rva):
1219        for PeSection in self._SectionList:
1220            if Rva in PeSection:
1221                return PeSection[Rva]
1222
1223## PeSectionHeader() class
1224#
1225#  A class for PE Section Header
1226#
1227class PeSectionHeader:
1228    #
1229    # VirtualAddress
1230    # SizeOfRawData
1231    # PointerToRawData
1232    #
1233    _HeaderFormat = "12x 1I 1I 1I 16x"
1234    _HeaderLength = struct.calcsize(_HeaderFormat)
1235
1236    def __init__(self, Buf, Offset):
1237        self.VirtualAddressStart, self.SizeOfRawData, self.PointerToRawData = \
1238            struct.unpack_from(self._HeaderFormat, Buf, Offset)
1239        self.VirtualAddressEnd = self.VirtualAddressStart + self.SizeOfRawData - 1
1240
1241    def __str__(self):
1242        return "VirtualAddress=%x, SizeOfRawData=%x, PointerToRawData=%x" % (self.VirtualAddressStart, self.SizeOfRawData, self.PointerToRawData)
1243
1244    def __len__(self):
1245        return self._HeaderLength
1246
1247    def __contains__(self, Rva):
1248        return Rva >= self.VirtualAddressStart and Rva <= self.VirtualAddressEnd
1249
1250    def __getitem__(self, Rva):
1251        return Rva - self.VirtualAddressStart + self.PointerToRawData
1252
1253## LinkMap() class
1254#
1255#  A class for Link Map
1256#
1257class LinkMap:
1258    _StartFlag = {
1259        "MSFT"  :   re.compile("Address +Publics by Value +Rva\+Base +Lib:Object"),
1260        "GCC"   :   re.compile("^\.(text|bss|data|edata)"),
1261    }
1262
1263    _MappingFormat = {
1264        "MSFT"  :   re.compile("([0-9a-f]+):([0-9a-f]+)\s+_+([0-9A-Za-z]+)\s+([0-9a-f]+)\s+"),
1265        "GCC"   :   re.compile("^(\.\w)?\s+(0x[0-9a-f]+)\s+_+([0-9A-Za-z]+)"),
1266    }
1267
1268    def __init__(self, MapFile, MapType="MSFT"):
1269        self.File = MapFile
1270        self.MapType = MapType
1271        self._Globals = {}  # global:RVA
1272
1273        self._Parse()
1274
1275    def _Parse(self):
1276        MapFile = open(self.File, 'r')
1277        MappingTitle = self._StartFlag[self.MapType]
1278        MappingFormat = self._MappingFormat[self.MapType]
1279        MappingStart = False
1280        try:
1281            for Line in MapFile:
1282                Line = Line.strip()
1283                if not MappingStart:
1284                    if MappingTitle.match(Line) != None:
1285                        MappingStart = True
1286                    continue
1287                ResultList = MappingFormat.findall(Line)
1288                if len(ResultList) == 0 or len(ResultList[0]) != 4:
1289                    continue
1290                self._Globals[ResultList[2]] = int(ResultList[3], 16)
1291                EdkLogger.verbose(ResultList[0])
1292        finally:
1293            MapFile.close()
1294
1295    def __contains__(self, Var):
1296        return Var in self._Globals
1297
1298    def __getitem__(self, Var):
1299        if Var not in self._Globals:
1300            return None
1301        return self._Globals[Var]
1302
1303## MultipleFv() class
1304#
1305#  A class for Multiple FV
1306#
1307class MultipleFv(FirmwareVolume):
1308    def __init__(self, FvList):
1309        FirmwareVolume.__init__(self)
1310        self.BasicInfo = []
1311        for FvPath in FvList:
1312            FvName = os.path.splitext(os.path.split(FvPath)[1])[0]
1313            Fd = open(FvPath, 'rb')
1314            Buf = array('B')
1315            try:
1316                Buf.fromfile(Fd, os.path.getsize(FvPath))
1317            except EOFError:
1318                pass
1319
1320            Fv = FirmwareVolume(FvName)
1321            Fv.frombuffer(Buf, 0, len(Buf))
1322
1323            self.BasicInfo.append([Fv.Name, Fv.FileSystemGuid, Fv.Size])
1324            self.FfsDict.append(Fv.FfsDict)
1325
1326# Version and Copyright
1327__version_number__ = "0.01"
1328__version__ = "%prog Version " + __version_number__
1329__copyright__ = "Copyright (c) 2008, Intel Corporation. All rights reserved."
1330
1331## Parse command line options
1332#
1333# Using standard Python module optparse to parse command line option of this tool.
1334#
1335# @retval Options   A optparse.Values object containing the parsed options
1336# @retval InputFile Path of file to be trimmed
1337#
1338def GetOptions():
1339    OptionList = [
1340        make_option("-a", "--arch", dest="Arch",
1341                          help="The input file is preprocessed source code, including C or assembly code"),
1342        make_option("-p", "--platform", dest="ActivePlatform",
1343                          help="The input file is preprocessed VFR file"),
1344        make_option("-m", "--module", dest="ActiveModule",
1345                          help="Convert standard hex format (0xabcd) to MASM format (abcdh)"),
1346        make_option("-f", "--FDF-file", dest="FdfFile",
1347                          help="Convert standard hex format (0xabcd) to MASM format (abcdh)"),
1348        make_option("-o", "--output", dest="OutputDirectory",
1349                          help="File to store the trimmed content"),
1350        make_option("-t", "--toolchain-tag", dest="ToolChain",
1351                          help=""),
1352        make_option("-k", "--msft", dest="MakefileType", action="store_const", const="nmake",
1353                          help=""),
1354        make_option("-g", "--gcc", dest="MakefileType", action="store_const", const="gmake",
1355                          help=""),
1356        make_option("-v", "--verbose", dest="LogLevel", action="store_const", const=EdkLogger.VERBOSE,
1357                          help="Run verbosely"),
1358        make_option("-d", "--debug", dest="LogLevel", type="int",
1359                          help="Run with debug information"),
1360        make_option("-q", "--quiet", dest="LogLevel", action="store_const", const=EdkLogger.QUIET,
1361                          help="Run quietly"),
1362        make_option("-?", action="help", help="show this help message and exit"),
1363    ]
1364
1365    # use clearer usage to override default usage message
1366    UsageString = "%prog [-a ARCH] [-p PLATFORM] [-m MODULE] [-t TOOLCHAIN_TAG] [-k] [-g] [-v|-d <debug_level>|-q] [-o <output_directory>] [GenC|GenMake]"
1367
1368    Parser = OptionParser(description=__copyright__, version=__version__, option_list=OptionList, usage=UsageString)
1369    Parser.set_defaults(Arch=[])
1370    Parser.set_defaults(ActivePlatform=None)
1371    Parser.set_defaults(ActiveModule=None)
1372    Parser.set_defaults(OutputDirectory="build")
1373    Parser.set_defaults(FdfFile=None)
1374    Parser.set_defaults(ToolChain="MYTOOLS")
1375    if sys.platform == "win32":
1376        Parser.set_defaults(MakefileType="nmake")
1377    else:
1378        Parser.set_defaults(MakefileType="gmake")
1379    Parser.set_defaults(LogLevel=EdkLogger.INFO)
1380
1381    Options, Args = Parser.parse_args()
1382
1383    # error check
1384    if len(Args) == 0:
1385        Options.Target = "genmake"
1386        sys.argv.append("genmake")
1387    elif len(Args) == 1:
1388        Options.Target = Args[0].lower()
1389        if Options.Target not in ["genc", "genmake"]:
1390            EdkLogger.error("AutoGen", OPTION_NOT_SUPPORTED, "Not supported target",
1391                            ExtraData="%s\n\n%s" % (Options.Target, Parser.get_usage()))
1392    else:
1393        EdkLogger.error("AutoGen", OPTION_NOT_SUPPORTED, "Too many targets",
1394                        ExtraData=Parser.get_usage())
1395
1396    return Options
1397
1398## Entrance method
1399#
1400# This method mainly dispatch specific methods per the command line options.
1401# If no error found, return zero value so the caller of this tool can know
1402# if it's executed successfully or not.
1403#
1404# @retval 0     Tool was successful
1405# @retval 1     Tool failed
1406#
1407def Main():
1408    from build import build
1409    try:
1410        Option = GetOptions()
1411        build.main()
1412    except Exception, e:
1413        print e
1414        return 1
1415
1416    return 0
1417
1418# This acts like the main() function for the script, unless it is 'import'ed into another script.
1419if __name__ == '__main__':
1420    EdkLogger.Initialize()
1421    # sys.exit(Main())
1422
1423    if len(sys.argv) > 1:
1424        FilePath = sys.argv[1]
1425        if FilePath.lower().endswith(".fv"):
1426            fd = open(FilePath, 'rb')
1427            buf = array('B')
1428            try:
1429                buf.fromfile(fd, os.path.getsize(FilePath))
1430            except EOFError:
1431                pass
1432
1433            fv = FirmwareVolume("FVRECOVERY")
1434            fv.frombuffer(buf, 0, len(buf))
1435            #fv.Dispatch(None)
1436            print fv
1437        elif FilePath.endswith(".efi"):
1438            fd = open(FilePath, 'rb')
1439            buf = array('B')
1440            Size = os.path.getsize(FilePath)
1441
1442            try:
1443                buf.fromfile(fd, Size)
1444            except EOFError:
1445                pass
1446
1447            PeSection = Section(Type=0x10)
1448            PeSection.Data = buf
1449            sf, ext = os.path.splitext(os.path.basename(FilePath))
1450            sf += ".sec"
1451            PeSection.tofile(open(sf, 'wb'))
1452        elif FilePath.endswith(".map"):
1453            mf = LinkMap(FilePath)
1454