4 # Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials
6 # are licensed and made available under the terms and conditions of the BSD License
7 # which accompanies this distribution. The full text of the license may be found at
8 # http://opensource.org/licenses/bsd-license.php
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.
16 import Common
.LongFilePathOs
as os
24 from UserDict
import IterableUserDict
25 from cStringIO
import StringIO
26 from array
import array
27 from Common
.LongFilePathSupport
import OpenLongFilePath
as open
28 from CommonDataClass
import *
29 from Common
.Misc
import sdict
, GuidStructureStringToGuidString
31 import Common
.EdkLogger
as EdkLogger
36 gFfsPrintTitle
= "%-36s %-21s %8s %8s %8s %-4s %-36s" % ("GUID", "TYPE", "OFFSET", "SIZE", "FREE", "ALIGN", "NAME")
37 gFfsPrintFormat
= "%36s %-21s %8X %8X %8X %4s %-36s"
38 gGuidStringFormat
= "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X"
39 gPeiAprioriFileNameGuid
= '1b45cc0a-156a-428a-af62-49864da0e6e6'
40 gAprioriGuid
= 'fc510ee7-ffdc-11d4-bd41-0080c73c8881'
48 _HEADER_
= struct
.Struct("")
49 _HEADER_SIZE_
= _HEADER_
.size
51 def __new__(cls
, *args
, **kwargs
):
52 return array
.__new
__(cls
, 'B')
54 def __init__(m
, ID
=None):
56 m
._ID
_ = str(uuid
.uuid1()).upper()
63 m
._SubImages
= sdict() # {offset: Image()}
65 array
.__init
__(m
, 'B')
71 Len
= array
.__len
__(m
)
72 for Offset
in m
._SubImages
:
73 Len
+= len(m
._SubImages
[Offset
])
77 m
.extend(m
._BUF
_[m
._OFF
_ : m
._OFF
_ + m
._LEN
_])
80 def _Pack(m
, PadByte
=0xFF):
81 raise NotImplementedError
83 def frombuffer(m
, Buffer
, Offset
=0, Size
=None):
86 # we may need the Size information in advance if it's given
93 def GetField(m
, FieldStruct
, Offset
=0):
94 return FieldStruct
.unpack_from(m
, Offset
)
96 def SetField(m
, FieldStruct
, Offset
, *args
):
97 # check if there's enough space
98 Size
= FieldStruct
.size
100 m
.extend([0] * (Size
- len(m
)))
101 FieldStruct
.pack_into(m
, Offset
, *args
)
103 def _SetData(m
, Data
):
104 if len(m
) < m
._HEADER
_SIZE
_:
105 m
.extend([0] * (m
._HEADER
_SIZE
_ - len(m
)))
107 del m
[m
._HEADER
_SIZE
_:]
111 if len(m
) > m
._HEADER
_SIZE
_:
112 return m
[m
._HEADER
_SIZE
_:]
115 Data
= property(_GetData
, _SetData
)
117 ## FirmwareVolume() class
119 # A class for Firmware Volume
121 class FirmwareVolume(Image
):
122 # Read FvLength, Attributes, HeaderLength, Checksum
123 _HEADER_
= struct
.Struct("16x 1I2H8B 1Q 4x 1I 1H 1H")
124 _HEADER_SIZE_
= _HEADER_
.size
126 _FfsGuid
= "8C8CE578-8A3D-4F1C-9935-896185C32DD3"
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")
135 def __init__(self
, Name
=''):
138 self
.FfsDict
= sdict()
139 self
.OrderedFfsDict
= sdict()
140 self
.UnDispatchedFfsDict
= sdict()
141 self
.ProtocolList
= sdict()
143 def CheckArchProtocol(self
):
144 for Item
in EotGlobalData
.gArchProtocolGuids
:
145 if Item
.lower() not in EotGlobalData
.gProtocolList
:
151 def ParseDepex(self
, Depex
, Type
):
154 List
= EotGlobalData
.gPpiList
155 if Type
== 'Protocol':
156 List
= EotGlobalData
.gProtocolList
162 for Index
in range(0, len(Depex
.Expression
)):
163 Item
= Depex
.Expression
[Index
]
166 Guid
= gGuidStringFormat
% Depex
.Expression
[Index
]
167 if Guid
in self
.OrderedFfsDict
and Depex
.Expression
[Index
+ 1] == 0x08:
168 return (True, 'BEFORE %s' % Guid
, [Guid
, 'BEFORE'])
171 Guid
= gGuidStringFormat
% Depex
.Expression
[Index
]
172 if Guid
in self
.OrderedFfsDict
and Depex
.Expression
[Index
+ 1] == 0x08:
173 return (True, 'AFTER %s' % Guid
, [Guid
, 'AFTER'])
176 Guid
= gGuidStringFormat
% Depex
.Expression
[Index
]
177 if Guid
.lower() in List
:
178 DepexStack
.append(True)
179 DepexList
.append(Guid
)
181 DepexStack
.append(False)
182 DepexList
.append(Guid
)
184 elif Item
== 0x03 or Item
== 0x04:
185 DepexStack
.append(eval(str(DepexStack
.pop()) + ' ' + Depex
._OPCODE
_STRING
_[Item
].lower() + ' ' + str(DepexStack
.pop())))
186 DepexList
.append(str(DepexList
.pop()) + ' ' + Depex
._OPCODE
_STRING
_[Item
].upper() + ' ' + str(DepexList
.pop()))
188 DepexStack
.append(eval(Depex
._OPCODE
_STRING
_[Item
].lower() + ' ' + str(DepexStack
.pop())))
189 DepexList
.append(Depex
._OPCODE
_STRING
_[Item
].lower() + ' ' + str(DepexList
.pop()))
191 DepexStack
.append(True)
192 DepexList
.append('TRUE')
193 DepexString
= DepexString
+ 'TRUE' + ' '
195 DepexStack
.append(False)
196 DepexList
.append('False')
197 DepexString
= DepexString
+ 'FALSE' + ' '
199 if Index
!= len(Depex
.Expression
) - 1:
200 CouldBeLoaded
= False
202 CouldBeLoaded
= DepexStack
.pop()
204 CouldBeLoaded
= False
206 DepexString
= DepexList
[0].strip()
207 return (CouldBeLoaded
, DepexString
, FileDepex
)
209 def Dispatch(self
, Db
= None):
212 self
.UnDispatchedFfsDict
= copy
.copy(self
.FfsDict
)
213 # Find PeiCore, DexCore, PeiPriori, DxePriori first
214 FfsSecCoreGuid
= None
215 FfsPeiCoreGuid
= None
216 FfsDxeCoreGuid
= None
217 FfsPeiPrioriGuid
= None
218 FfsDxePrioriGuid
= None
219 for FfsID
in self
.UnDispatchedFfsDict
:
220 Ffs
= self
.UnDispatchedFfsDict
[FfsID
]
222 FfsSecCoreGuid
= FfsID
225 FfsPeiCoreGuid
= FfsID
228 FfsDxeCoreGuid
= FfsID
230 if Ffs
.Guid
.lower() == gPeiAprioriFileNameGuid
:
231 FfsPeiPrioriGuid
= FfsID
233 if Ffs
.Guid
.lower() == gAprioriGuid
:
234 FfsDxePrioriGuid
= FfsID
237 # Parse SEC_CORE first
238 if FfsSecCoreGuid
is not None:
239 self
.OrderedFfsDict
[FfsSecCoreGuid
] = self
.UnDispatchedFfsDict
.pop(FfsSecCoreGuid
)
240 self
.LoadPpi(Db
, FfsSecCoreGuid
)
243 if FfsPeiCoreGuid
is not None:
244 self
.OrderedFfsDict
[FfsPeiCoreGuid
] = self
.UnDispatchedFfsDict
.pop(FfsPeiCoreGuid
)
245 self
.LoadPpi(Db
, FfsPeiCoreGuid
)
246 if FfsPeiPrioriGuid
is not None:
247 # Load PEIM described in priori file
248 FfsPeiPriori
= self
.UnDispatchedFfsDict
.pop(FfsPeiPrioriGuid
)
249 if len(FfsPeiPriori
.Sections
) == 1:
250 Section
= FfsPeiPriori
.Sections
.popitem()[1]
251 if Section
.Type
== 0x19:
252 GuidStruct
= struct
.Struct('1I2H8B')
254 while len(Section
) > Start
:
255 Guid
= GuidStruct
.unpack_from(Section
[Start
: Start
+ 16])
256 GuidString
= gGuidStringFormat
% Guid
258 if GuidString
in self
.UnDispatchedFfsDict
:
259 self
.OrderedFfsDict
[GuidString
] = self
.UnDispatchedFfsDict
.pop(GuidString
)
260 self
.LoadPpi(Db
, GuidString
)
265 if FfsDxeCoreGuid
is not None:
266 self
.OrderedFfsDict
[FfsDxeCoreGuid
] = self
.UnDispatchedFfsDict
.pop(FfsDxeCoreGuid
)
267 self
.LoadProtocol(Db
, FfsDxeCoreGuid
)
268 if FfsDxePrioriGuid
is not None:
269 # Load PEIM described in priori file
270 FfsDxePriori
= self
.UnDispatchedFfsDict
.pop(FfsDxePrioriGuid
)
271 if len(FfsDxePriori
.Sections
) == 1:
272 Section
= FfsDxePriori
.Sections
.popitem()[1]
273 if Section
.Type
== 0x19:
274 GuidStruct
= struct
.Struct('1I2H8B')
276 while len(Section
) > Start
:
277 Guid
= GuidStruct
.unpack_from(Section
[Start
: Start
+ 16])
278 GuidString
= gGuidStringFormat
% Guid
280 if GuidString
in self
.UnDispatchedFfsDict
:
281 self
.OrderedFfsDict
[GuidString
] = self
.UnDispatchedFfsDict
.pop(GuidString
)
282 self
.LoadProtocol(Db
, GuidString
)
286 def LoadProtocol(self
, Db
, ModuleGuid
):
287 SqlCommand
= """select GuidValue from Report
288 where SourceFileFullPath in
289 (select Value1 from Inf where BelongsToFile =
290 (select BelongsToFile from Inf
291 where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
293 and ItemType = 'Protocol' and ItemMode = 'Produced'""" \
294 % (ModuleGuid
, 5001, 3007)
295 RecordSet
= Db
.TblReport
.Exec(SqlCommand
)
296 for Record
in RecordSet
:
297 SqlCommand
= """select Value2 from Inf where BelongsToFile =
298 (select DISTINCT BelongsToFile from Inf
300 (select SourceFileFullPath from Report
301 where GuidValue like '%s' and ItemMode = 'Callback'))
302 and Value1 = 'FILE_GUID'""" % Record
[0]
303 CallBackSet
= Db
.TblReport
.Exec(SqlCommand
)
304 if CallBackSet
!= []:
305 EotGlobalData
.gProtocolList
[Record
[0].lower()] = ModuleGuid
307 EotGlobalData
.gProtocolList
[Record
[0].lower()] = ModuleGuid
309 def LoadPpi(self
, Db
, ModuleGuid
):
310 SqlCommand
= """select GuidValue from Report
311 where SourceFileFullPath in
312 (select Value1 from Inf where BelongsToFile =
313 (select BelongsToFile from Inf
314 where Value1 = 'FILE_GUID' and Value2 like '%s' and Model = %s)
316 and ItemType = 'Ppi' and ItemMode = 'Produced'""" \
317 % (ModuleGuid
, 5001, 3007)
318 RecordSet
= Db
.TblReport
.Exec(SqlCommand
)
319 for Record
in RecordSet
:
320 EotGlobalData
.gPpiList
[Record
[0].lower()] = ModuleGuid
322 def DisPatchDxe(self
, Db
):
324 ScheduleList
= sdict()
325 for FfsID
in self
.UnDispatchedFfsDict
:
326 CouldBeLoaded
= False
329 Ffs
= self
.UnDispatchedFfsDict
[FfsID
]
333 for Section
in Ffs
.Sections
.values():
335 if Section
.Type
== 0x13:
337 CouldBeLoaded
, DepexString
, FileDepex
= self
.ParseDepex(Section
._SubImages
[4], 'Protocol')
339 if Section
.Type
== 0x01:
340 CompressSections
= Section
._SubImages
[4]
341 for CompressSection
in CompressSections
.Sections
:
342 if CompressSection
.Type
== 0x13:
344 CouldBeLoaded
, DepexString
, FileDepex
= self
.ParseDepex(CompressSection
._SubImages
[4], 'Protocol')
346 if CompressSection
.Type
== 0x02:
347 NewSections
= CompressSection
._SubImages
[4]
348 for NewSection
in NewSections
.Sections
:
349 if NewSection
.Type
== 0x13:
351 CouldBeLoaded
, DepexString
, FileDepex
= self
.ParseDepex(NewSection
._SubImages
[4], 'Protocol')
356 CouldBeLoaded
= self
.CheckArchProtocol()
363 NewFfs
= self
.UnDispatchedFfsDict
.pop(FfsID
)
364 NewFfs
.Depex
= DepexString
365 if FileDepex
is not None:
366 ScheduleList
.insert(FileDepex
[1], FfsID
, NewFfs
, FileDepex
[0])
368 ScheduleList
[FfsID
] = NewFfs
370 self
.UnDispatchedFfsDict
[FfsID
].Depex
= DepexString
372 for FfsID
in ScheduleList
:
373 NewFfs
= ScheduleList
.pop(FfsID
)
375 self
.OrderedFfsDict
[FfsID
] = NewFfs
376 self
.LoadProtocol(Db
, FfsID
)
378 SqlCommand
= """select Value2 from Inf
379 where BelongsToFile = (select BelongsToFile from Inf where Value1 = 'FILE_GUID' and lower(Value2) = lower('%s') and Model = %s)
380 and Model = %s and Value1='BASE_NAME'""" % (FfsID
, 5001, 5001)
381 RecordSet
= Db
.TblReport
.Exec(SqlCommand
)
383 FfsName
= RecordSet
[0][0]
388 def DisPatchPei(self
, Db
):
390 for FfsID
in self
.UnDispatchedFfsDict
:
394 Ffs
= self
.UnDispatchedFfsDict
[FfsID
]
395 if Ffs
.Type
== 0x06 or Ffs
.Type
== 0x08:
397 for Section
in Ffs
.Sections
.values():
398 if Section
.Type
== 0x1B:
399 CouldBeLoaded
, DepexString
, FileDepex
= self
.ParseDepex(Section
._SubImages
[4], 'Ppi')
402 if Section
.Type
== 0x01:
403 CompressSections
= Section
._SubImages
[4]
404 for CompressSection
in CompressSections
.Sections
:
405 if CompressSection
.Type
== 0x1B:
406 CouldBeLoaded
, DepexString
, FileDepex
= self
.ParseDepex(CompressSection
._SubImages
[4], 'Ppi')
408 if CompressSection
.Type
== 0x02:
409 NewSections
= CompressSection
._SubImages
[4]
410 for NewSection
in NewSections
.Sections
:
411 if NewSection
.Type
== 0x1B:
412 CouldBeLoaded
, DepexString
, FileDepex
= self
.ParseDepex(NewSection
._SubImages
[4], 'Ppi')
418 NewFfs
= self
.UnDispatchedFfsDict
.pop(FfsID
)
419 NewFfs
.Depex
= DepexString
420 self
.OrderedFfsDict
[FfsID
] = NewFfs
421 self
.LoadPpi(Db
, FfsID
)
423 self
.UnDispatchedFfsDict
[FfsID
].Depex
= DepexString
432 FvInfo
= '\n' + ' ' * gIndention
433 FvInfo
+= "[FV:%s] file_system=%s size=%x checksum=%s\n" % (self
.Name
, self
.FileSystemGuid
, self
.Size
, self
.Checksum
)
434 FfsInfo
= "\n".join([str(self
.FfsDict
[FfsId
]) for FfsId
in self
.FfsDict
])
436 return FvInfo
+ FfsInfo
439 Size
= self
._LENGTH
_.unpack_from(self
._BUF
_, self
._OFF
_)[0]
441 self
.extend(self
._BUF
_[self
._OFF
_:self
._OFF
_+Size
])
445 FfsStartAddress
= self
.HeaderSize
447 while FfsStartAddress
< EndOfFv
:
449 FfsObj
.frombuffer(self
, FfsStartAddress
)
451 if ((self
.Attributes
& 0x00000800) != 0 and len(FfsObj
) == 0xFFFFFF) \
452 or ((self
.Attributes
& 0x00000800) == 0 and len(FfsObj
) == 0):
453 if LastFfsObj
is not None:
454 LastFfsObj
.FreeSpace
= EndOfFv
- LastFfsObj
._OFF
_ - len(LastFfsObj
)
456 if FfsId
in self
.FfsDict
:
457 EdkLogger
.error("FV", 0, "Duplicate GUID in FFS",
458 ExtraData
="\t%s @ %s\n\t%s @ %s" \
459 % (FfsObj
.Guid
, FfsObj
.Offset
,
460 self
.FfsDict
[FfsId
].Guid
, self
.FfsDict
[FfsId
].Offset
))
461 self
.FfsDict
[FfsId
] = FfsObj
462 if LastFfsObj
is not None:
463 LastFfsObj
.FreeSpace
= FfsStartAddress
- LastFfsObj
._OFF
_ - len(LastFfsObj
)
465 FfsStartAddress
+= len(FfsObj
)
467 # align to next 8-byte aligned address: A = (A + 8 - 1) & (~(8 - 1))
468 # The next FFS must be at the latest next 8-byte aligned address
470 FfsStartAddress
= (FfsStartAddress
+ 7) & (~
7)
473 def _GetAttributes(self
):
474 return self
.GetField(self
._ATTR
_, 0)[0]
477 return self
.GetField(self
._LENGTH
_, 0)[0]
479 def _GetChecksum(self
):
480 return self
.GetField(self
._CHECKSUM
_, 0)[0]
482 def _GetHeaderLength(self
):
483 return self
.GetField(self
._HLEN
_, 0)[0]
485 def _GetFileSystemGuid(self
):
486 return gGuidStringFormat
% self
.GetField(self
._GUID
_, 0)
488 Attributes
= property(_GetAttributes
)
489 Size
= property(_GetSize
)
490 Checksum
= property(_GetChecksum
)
491 HeaderSize
= property(_GetHeaderLength
)
492 FileSystemGuid
= property(_GetFileSystemGuid
)
494 ## CompressedImage() class
496 # A class for Compressed Image
498 class CompressedImage(Image
):
499 # UncompressedLength = 4-byte
500 # CompressionType = 1-byte
501 _HEADER_
= struct
.Struct("1I 1B")
502 _HEADER_SIZE_
= _HEADER_
.size
504 _ORIG_SIZE_
= struct
.Struct("1I")
505 _CMPRS_TYPE_
= struct
.Struct("4x 1B")
507 def __init__(m
, CompressedData
=None, CompressionType
=None, UncompressedLength
=None):
509 if UncompressedLength
is not None:
510 m
.UncompressedLength
= UncompressedLength
511 if CompressionType
is not None:
512 m
.CompressionType
= CompressionType
513 if CompressedData
is not None:
514 m
.Data
= CompressedData
518 S
= "algorithm=%s uncompressed=%x" % (m
.CompressionType
, m
.UncompressedLength
)
519 for Sec
in m
.Sections
:
524 def _SetOriginalSize(m
, Size
):
525 m
.SetField(m
._ORIG
_SIZE
_, 0, Size
)
527 def _GetOriginalSize(m
):
528 return m
.GetField(m
._ORIG
_SIZE
_)[0]
530 def _SetCompressionType(m
, Type
):
531 m
.SetField(m
._CMPRS
_TYPE
_, 0, Type
)
533 def _GetCompressionType(m
):
534 return m
.GetField(m
._CMPRS
_TYPE
_)[0]
539 TmpData
= EfiCompressor
.FrameworkDecompress(
541 len(m
) - m
._HEADER
_SIZE
_
544 DecData
.fromstring(TmpData
)
547 TmpData
= EfiCompressor
.UefiDecompress(
549 len(m
) - m
._HEADER
_SIZE
_
552 DecData
.fromstring(TmpData
)
556 while Offset
< len(DecData
):
559 Sec
.frombuffer(DecData
, Offset
)
561 # the section is aligned to 4-byte boundary
564 SectionList
.append(Sec
)
567 UncompressedLength
= property(_GetOriginalSize
, _SetOriginalSize
)
568 CompressionType
= property(_GetCompressionType
, _SetCompressionType
)
569 Sections
= property(_GetSections
)
571 ## GuidDefinedImage() class
573 # A class for GUID Defined Image
575 class GuidDefinedImage(Image
):
576 _HEADER_
= struct
.Struct("1I2H8B 1H 1H")
577 _HEADER_SIZE_
= _HEADER_
.size
579 _GUID_
= struct
.Struct("1I2H8B")
580 _DATA_OFFSET_
= struct
.Struct("16x 1H")
581 _ATTR_
= struct
.Struct("18x 1H")
583 CRC32_GUID
= "FC1BCDB0-7D31-49AA-936A-A4600D9DD083"
584 TIANO_COMPRESS_GUID
= 'A31280AD-481E-41B6-95E8-127F4C984779'
585 LZMA_COMPRESS_GUID
= 'EE4E5898-3914-4259-9D6E-DC7BD79403CF'
587 def __init__(m
, SectionDefinitionGuid
=None, DataOffset
=None, Attributes
=None, Data
=None):
589 if SectionDefinitionGuid
is not None:
590 m
.SectionDefinitionGuid
= SectionDefinitionGuid
591 if DataOffset
is not None:
592 m
.DataOffset
= DataOffset
593 if Attributes
is not None:
594 m
.Attributes
= Attributes
599 S
= "guid=%s" % (gGuidStringFormat
% m
.SectionDefinitionGuid
)
600 for Sec
in m
.Sections
:
605 # keep header in this Image object
607 m
.extend(m
._BUF
_[m
._OFF
_ : m
._OFF
_ + m
._LEN
_])
610 def _SetAttribute(m
, Attribute
):
611 m
.SetField(m
._ATTR
_, 0, Attribute
)
613 def _GetAttribute(m
):
614 return m
.GetField(m
._ATTR
_)[0]
616 def _SetGuid(m
, Guid
):
617 m
.SetField(m
._GUID
_, 0, Guid
)
620 return m
.GetField(m
._GUID
_)
622 def _SetDataOffset(m
, Offset
):
623 m
.SetField(m
._DATA
_OFFSET
_, 0, Offset
)
625 def _GetDataOffset(m
):
626 return m
.GetField(m
._DATA
_OFFSET
_)[0]
630 Guid
= gGuidStringFormat
% m
.SectionDefinitionGuid
631 if Guid
== m
.CRC32_GUID
:
632 # skip the CRC32 value, we don't do CRC32 verification here
633 Offset
= m
.DataOffset
- 4
634 while Offset
< len(m
):
637 Sec
.frombuffer(m
, Offset
)
639 # the section is aligned to 4-byte boundary
640 Offset
= (Offset
+ 3) & (~
3)
643 SectionList
.append(Sec
)
644 elif Guid
== m
.TIANO_COMPRESS_GUID
:
648 Offset
= m
.DataOffset
- 4
649 TmpData
= EfiCompressor
.FrameworkDecompress(m
[Offset
:], len(m
)-Offset
)
651 DecData
.fromstring(TmpData
)
653 while Offset
< len(DecData
):
656 Sec
.frombuffer(DecData
, Offset
)
658 # the section is aligned to 4-byte boundary
659 Offset
= (Offset
+ 3) & (~
3)
662 SectionList
.append(Sec
)
665 elif Guid
== m
.LZMA_COMPRESS_GUID
:
667 import LzmaCompressor
669 Offset
= m
.DataOffset
- 4
670 TmpData
= LzmaCompressor
.LzmaDecompress(m
[Offset
:], len(m
)-Offset
)
672 DecData
.fromstring(TmpData
)
674 while Offset
< len(DecData
):
677 Sec
.frombuffer(DecData
, Offset
)
679 # the section is aligned to 4-byte boundary
680 Offset
= (Offset
+ 3) & (~
3)
683 SectionList
.append(Sec
)
689 Attributes
= property(_GetAttribute
, _SetAttribute
)
690 SectionDefinitionGuid
= property(_GetGuid
, _SetGuid
)
691 DataOffset
= property(_GetDataOffset
, _SetDataOffset
)
692 Sections
= property(_GetSections
)
699 _HEADER_
= struct
.Struct("")
702 _GUID_
= struct
.Struct("1I2H8B")
703 _OPCODE_
= struct
.Struct("1B")
719 -1 : _OPCODE_
, # first one in depex must be an opcdoe
720 0x00 : _GUID_
, #"BEFORE",
721 0x01 : _GUID_
, #"AFTER",
722 0x02 : _GUID_
, #"PUSH",
723 0x03 : _OPCODE_
, #"AND",
724 0x04 : _OPCODE_
, #"OR",
725 0x05 : _OPCODE_
, #"NOT",
726 0x06 : _OPCODE_
, #"TRUE",
727 0x07 : _OPCODE_
, #"FALSE",
729 0x09 : _OPCODE_
, #"SOR"
739 Indention
= ' ' * gIndention
741 for T
in m
.Expression
:
742 if T
in m
._OPCODE
_STRING
_:
743 S
+= Indention
+ m
._OPCODE
_STRING
_[T
]
744 if T
not in [0x00, 0x01, 0x02]:
747 S
+= ' ' + gGuidStringFormat
% T
+ '\n'
752 # keep header in this Image object
754 m
.extend(m
._BUF
_[m
._OFF
_ : m
._OFF
_ + m
._LEN
_])
757 def _GetExpression(m
):
758 if m
._ExprList
== []:
760 CurrentData
= m
._OPCODE
_
761 while Offset
< len(m
):
762 Token
= CurrentData
.unpack_from(m
, Offset
)
763 Offset
+= CurrentData
.size
766 if Token
in m
._NEXT
_:
767 CurrentData
= m
._NEXT
_[Token
]
769 CurrentData
= m
._GUID
_
771 CurrentData
= m
._OPCODE
_
772 m
._ExprList
.append(Token
)
773 if CurrentData
is None:
777 Expression
= property(_GetExpression
)
784 _HEADER_
= struct
.Struct("")
794 # keep header in this Image object
796 m
.extend(m
._BUF
_[m
._OFF
_ : m
._OFF
_ + m
._LEN
_])
800 return codecs
.utf_16_decode(m
[0:-2].tostring())[0]
802 String
= property(_GetUiString
)
806 # A class for Section
808 class Section(Image
):
811 0x01 : "COMPRESSION",
812 0x02 : "GUID_DEFINED",
818 0x15 : "USER_INTERFACE",
819 0x16 : "COMPATIBILITY16",
820 0x17 : "FIRMWARE_VOLUME_IMAGE",
821 0x18 : "FREEFORM_SUBTYPE_GUID",
826 _SectionSubImages
= {
827 0x01 : CompressedImage
,
828 0x02 : GuidDefinedImage
,
829 0x17 : FirmwareVolume
,
837 _HEADER_
= struct
.Struct("3B 1B")
838 _HEADER_SIZE_
= _HEADER_
.size
841 # _FREE_FORM_SUBTYPE_GUID_HEADER_ = struct.Struct("1I2H8B")
843 _SIZE_
= struct
.Struct("3B")
844 _TYPE_
= struct
.Struct("3x 1B")
846 def __init__(m
, Type
=None, Size
=None):
857 SectionInfo
= ' ' * gIndention
858 if m
.Type
in m
._TypeName
:
859 SectionInfo
+= "[SECTION:%s] offset=%x size=%x" % (m
._TypeName
[m
.Type
], m
._OFF
_, m
.Size
)
861 SectionInfo
+= "[SECTION:%x<unknown>] offset=%x size=%x " % (m
.Type
, m
._OFF
_, m
.Size
)
862 for Offset
in m
._SubImages
:
863 SectionInfo
+= ", " + str(m
._SubImages
[Offset
])
869 Type
, = m
._TYPE
_.unpack_from(m
._BUF
_, m
._OFF
_)
870 Size1
, Size2
, Size3
= m
._SIZE
_.unpack_from(m
._BUF
_, m
._OFF
_)
871 Size
= Size1
+ (Size2
<< 8) + (Size3
<< 16)
873 if Type
not in m
._SectionSubImages
:
874 # no need to extract sub-image, keep all in this Image object
875 m
.extend(m
._BUF
_[m
._OFF
_ : m
._OFF
_ + Size
])
877 # keep header in this Image object
878 m
.extend(m
._BUF
_[m
._OFF
_ : m
._OFF
_ + m
._HEADER
_SIZE
_])
880 # use new Image object to represent payload, which may be another kind
881 # of image such as PE32
883 PayloadOffset
= m
._HEADER
_SIZE
_
884 PayloadLen
= m
.Size
- m
._HEADER
_SIZE
_
885 Payload
= m
._SectionSubImages
[m
.Type
]()
886 Payload
.frombuffer(m
._BUF
_, m
._OFF
_ + m
._HEADER
_SIZE
_, PayloadLen
)
887 m
._SubImages
[PayloadOffset
] = Payload
891 def _SetSize(m
, Size
):
893 Size2
= (Size
& 0xFF00) >> 8
894 Size3
= (Size
& 0xFF0000) >> 16
895 m
.SetField(m
._SIZE
_, 0, Size1
, Size2
, Size3
)
898 Size1
, Size2
, Size3
= m
.GetField(m
._SIZE
_)
899 return Size1
+ (Size2
<< 8) + (Size3
<< 16)
901 def _SetType(m
, Type
):
902 m
.SetField(m
._TYPE
_, 0, Type
)
905 return m
.GetField(m
._TYPE
_)[0]
907 def _GetAlignment(m
):
910 def _SetAlignment(m
, Alignment
):
911 m
._Alignment
= Alignment
912 AlignmentMask
= Alignment
- 1
913 # section alignment is actually for payload, so we need to add header size
914 PayloadOffset
= m
._OFF
_ + m
._HEADER
_SIZE
_
915 if (PayloadOffset
& (~AlignmentMask
)) == 0:
917 NewOffset
= (PayloadOffset
+ AlignmentMask
) & (~AlignmentMask
)
918 while (NewOffset
- PayloadOffset
) < m
._HEADER
_SIZE
_:
919 NewOffset
+= m
._Alignment
924 for Offset
in m
._SubImages
:
925 m
._SubImages
[Offset
].tofile(f
)
927 Type
= property(_GetType
, _SetType
)
928 Size
= property(_GetSize
, _SetSize
)
929 Alignment
= property(_GetAlignment
, _SetAlignment
)
930 # SubTypeGuid = property(_GetGuid, _SetGuid)
932 ## PadSection() class
934 # A class for Pad Section
936 class PadSection(Section
):
937 def __init__(m
, Size
):
941 m
.Data
= [0] * (Size
- m
._HEADER
_SIZE
_)
945 # A class for Ffs Section
948 _FfsFormat
= "24B%(payload_size)sB"
949 # skip IntegrityCheck
950 _HEADER_
= struct
.Struct("1I2H8B 2x 1B 1B 3B 1B")
951 _HEADER_SIZE_
= _HEADER_
.size
953 _NAME_
= struct
.Struct("1I2H8B")
954 _INT_CHECK_
= struct
.Struct("16x 1H")
955 _TYPE_
= struct
.Struct("18x 1B")
956 _ATTR_
= struct
.Struct("19x 1B")
957 _SIZE_
= struct
.Struct("20x 3B")
958 _STATE_
= struct
.Struct("23x 1B")
960 VTF_GUID
= "1BA0062E-C779-4582-8566-336AE8F78F09"
962 FFS_ATTRIB_FIXED
= 0x04
963 FFS_ATTRIB_DATA_ALIGNMENT
= 0x38
964 FFS_ATTRIB_CHECKSUM
= 0x40
970 0x03 : "SECURITY_CORE",
975 0x08 : "COMBINED_PEIM_DRIVER",
976 0x09 : "APPLICATION",
978 0x0B : "FIRMWARE_VOLUME_IMAGE",
979 0x0C : "COMBINED_SMM_DXE",
981 0x0E : "MM_STANDALONE",
982 0x0F : "MM_CORE_STANDALONE",
996 self
.Sections
= sdict()
1004 Indention
= ' ' * gIndention
1006 FfsInfo
+= "[FFS:%s] offset=%x size=%x guid=%s free_space=%x alignment=%s\n" % \
1007 (Ffs
._TypeName
[self
.Type
], self
._OFF
_, self
.Size
, self
.Guid
, self
.FreeSpace
, self
.Alignment
)
1008 SectionInfo
= '\n'.join([str(self
.Sections
[Offset
]) for Offset
in self
.Sections
])
1010 return FfsInfo
+ SectionInfo
+ "\n"
1019 Size1
, Size2
, Size3
= self
._SIZE
_.unpack_from(self
._BUF
_, self
._OFF
_)
1020 Size
= Size1
+ (Size2
<< 8) + (Size3
<< 16)
1022 self
.extend(self
._BUF
_[self
._OFF
_ : self
._OFF
_ + Size
])
1024 # Pad FFS may use the same GUID. We need to avoid it.
1025 if self
.Type
== 0xf0:
1026 self
.__ID
__ = str(uuid
.uuid1()).upper()
1028 self
.__ID
__ = self
.Guid
1030 # Traverse the SECTION. RAW and PAD do not have sections
1031 if self
.Type
not in [0xf0, 0x01] and Size
> 0 and Size
< 0xFFFFFF:
1033 SectionStartAddress
= self
._HEADER
_SIZE
_
1034 while SectionStartAddress
< EndOfFfs
:
1035 SectionObj
= Section()
1036 SectionObj
.frombuffer(self
, SectionStartAddress
)
1037 #f = open(repr(SectionObj), 'wb')
1038 #SectionObj.Size = 0
1039 #SectionObj.tofile(f)
1041 self
.Sections
[SectionStartAddress
] = SectionObj
1042 SectionStartAddress
+= len(SectionObj
)
1043 SectionStartAddress
= (SectionStartAddress
+ 3) & (~
3)
1048 def SetFreeSpace(self
, Size
):
1049 self
.FreeSpace
= Size
1052 return gGuidStringFormat
% self
.Name
1054 def _SetName(self
, Value
):
1055 # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11
1056 self
.SetField(self
._NAME
_, 0, Value
)
1059 # Guid1, Guid2, Guid3, Guid4, Guid5, Guid6, Guid7, Guid8, Guid9, Guid10, Guid11
1060 return self
.GetField(self
._NAME
_)
1062 def _SetSize(m
, Size
):
1064 Size2
= (Size
& 0xFF00) >> 8
1065 Size3
= (Size
& 0xFF0000) >> 16
1066 m
.SetField(m
._SIZE
_, 0, Size1
, Size2
, Size3
)
1069 Size1
, Size2
, Size3
= m
.GetField(m
._SIZE
_)
1070 return Size1
+ (Size2
<< 8) + (Size3
<< 16)
1072 def _SetType(m
, Type
):
1073 m
.SetField(m
._TYPE
_, 0, Type
)
1076 return m
.GetField(m
._TYPE
_)[0]
1078 def _SetAttributes(self
, Value
):
1079 self
.SetField(m
._ATTR
_, 0, Value
)
1081 def _GetAttributes(self
):
1082 return self
.GetField(self
._ATTR
_)[0]
1084 def _GetFixed(self
):
1085 if (self
.Attributes
& self
.FFS_ATTRIB_FIXED
) != 0:
1089 def _GetCheckSum(self
):
1090 if (self
.Attributes
& self
.FFS_ATTRIB_CHECKSUM
) != 0:
1094 def _GetAlignment(self
):
1095 return (self
.Attributes
& self
.FFS_ATTRIB_DATA_ALIGNMENT
) >> 3
1097 def _SetState(self
, Value
):
1098 self
.SetField(m
._STATE
_, 0, Value
)
1100 def _GetState(self
):
1101 return self
.GetField(m
._STATE
_)[0]
1103 Name
= property(_GetName
, _SetName
)
1104 Guid
= property(_GetGuid
)
1105 Type
= property(_GetType
, _SetType
)
1106 Size
= property(_GetSize
, _SetSize
)
1107 Attributes
= property(_GetAttributes
, _SetAttributes
)
1108 Fixed
= property(_GetFixed
)
1109 Checksum
= property(_GetCheckSum
)
1110 Alignment
= property(_GetAlignment
)
1111 State
= property(_GetState
, _SetState
)
1115 # A class for PE Image
1119 # just extract e_lfanew
1121 _DosHeaderFormat
= "60x 1I"
1125 # SizeOfOptionalHeader
1127 _FileHeaderFormat
= "4x 1H 1H 4x 4x 4x 1H 2x"
1133 # NumberOfRvaAndSizes
1135 _OptionalHeader32Format
= "1H 54x 1I 1I 1I 24x 1I"
1136 _OptionalHeader64Format
= ""
1137 def __init__(self
, Buf
, Offset
, Size
):
1138 self
.Offset
= Offset
1140 self
.Machine
= 0x014c # IA32
1141 self
.NumberOfSections
= 0
1142 self
.SizeOfImage
= 0
1143 self
.SizeOfOptionalHeader
= 0
1145 self
._PeImageBuf
= Buf
1146 self
._SectionList
= []
1148 self
._DosHeader
= struct
.Struct(PeImage
._DosHeaderFormat
)
1149 self
._FileHeader
= struct
.Struct(PeImage
._FileHeaderFormat
)
1150 self
._OptionalHeader
32 = struct
.Struct(PeImage
._OptionalHeader
32Format
)
1163 # from DOS header, get the offset of PE header
1164 FileHeaderOffset
, = self
._DosHeader
.unpack_from(self
._PeImageBuf
, self
.Offset
)
1165 if FileHeaderOffset
< struct
.calcsize(self
._DosHeaderFormat
):
1166 EdkLogger
.error("PE+", 0, "Invalid offset of IMAGE_FILE_HEADER: %s" % FileHeaderOffset
)
1168 # from FILE header, get the optional header size
1169 self
.Machine
, self
.NumberOfSections
, self
.SizeOfOptionalHeader
= \
1170 self
._FileHeader
.unpack_from(self
._PeImageBuf
, self
.Offset
+ FileHeaderOffset
)
1172 print "Machine=%x NumberOfSections=%x SizeOfOptionalHeader=%x" % (self
.Machine
, self
.NumberOfSections
, self
.SizeOfOptionalHeader
)
1173 # optional header follows the FILE header
1174 OptionalHeaderOffset
= FileHeaderOffset
+ struct
.calcsize(self
._FileHeaderFormat
)
1175 Magic
, self
.SizeOfImage
, SizeOfHeaders
, self
.Checksum
, NumberOfRvaAndSizes
= \
1176 self
._OptionalHeader
32.unpack_from(self
._PeImageBuf
, self
.Offset
+ OptionalHeaderOffset
)
1177 print "Magic=%x SizeOfImage=%x SizeOfHeaders=%x, Checksum=%x, NumberOfRvaAndSizes=%x" % (Magic
, self
.SizeOfImage
, SizeOfHeaders
, self
.Checksum
, NumberOfRvaAndSizes
)
1179 PeImageSectionTableOffset
= OptionalHeaderOffset
+ self
.SizeOfOptionalHeader
1180 PeSections
= PeSectionTable(self
._PeImageBuf
, self
.Offset
+ PeImageSectionTableOffset
, self
.NumberOfSections
)
1182 print "%x" % PeSections
.GetFileAddress(0x3920)
1184 ## PeSectionTable() class
1186 # A class for PE Section Table
1188 class PeSectionTable
:
1189 def __init__(self
, Buf
, Offset
, NumberOfSections
):
1190 self
._SectionList
= []
1192 SectionHeaderOffset
= Offset
1193 for TableIndex
in range(0, NumberOfSections
):
1194 SectionHeader
= PeSectionHeader(Buf
, SectionHeaderOffset
)
1195 self
._SectionList
.append(SectionHeader
)
1196 SectionHeaderOffset
+= len(SectionHeader
)
1199 def GetFileAddress(self
, Rva
):
1200 for PeSection
in self
._SectionList
:
1201 if Rva
in PeSection
:
1202 return PeSection
[Rva
]
1204 ## PeSectionHeader() class
1206 # A class for PE Section Header
1208 class PeSectionHeader
:
1214 _HeaderFormat
= "12x 1I 1I 1I 16x"
1215 _HeaderLength
= struct
.calcsize(_HeaderFormat
)
1217 def __init__(self
, Buf
, Offset
):
1218 self
.VirtualAddressStart
, self
.SizeOfRawData
, self
.PointerToRawData
= \
1219 struct
.unpack_from(self
._HeaderFormat
, Buf
, Offset
)
1220 self
.VirtualAddressEnd
= self
.VirtualAddressStart
+ self
.SizeOfRawData
- 1
1223 return "VirtualAddress=%x, SizeOfRawData=%x, PointerToRawData=%x" % (self
.VirtualAddressStart
, self
.SizeOfRawData
, self
.PointerToRawData
)
1226 return self
._HeaderLength
1228 def __contains__(self
, Rva
):
1229 return Rva
>= self
.VirtualAddressStart
and Rva
<= self
.VirtualAddressEnd
1231 def __getitem__(self
, Rva
):
1232 return Rva
- self
.VirtualAddressStart
+ self
.PointerToRawData
1236 # A class for Link Map
1240 "MSFT" : re
.compile("Address +Publics by Value +Rva\+Base +Lib:Object"),
1241 "GCC" : re
.compile("^\.(text|bss|data|edata)"),
1245 "MSFT" : re
.compile("([0-9a-f]+):([0-9a-f]+)\s+_+([0-9A-Za-z]+)\s+([0-9a-f]+)\s+"),
1246 "GCC" : re
.compile("^(\.\w)?\s+(0x[0-9a-f]+)\s+_+([0-9A-Za-z]+)"),
1249 def __init__(self
, MapFile
, MapType
="MSFT"):
1251 self
.MapType
= MapType
1252 self
._Globals
= {} # global:RVA
1257 MapFile
= open(self
.File
, 'r')
1258 MappingTitle
= self
._StartFlag
[self
.MapType
]
1259 MappingFormat
= self
._MappingFormat
[self
.MapType
]
1260 MappingStart
= False
1262 for Line
in MapFile
:
1264 if not MappingStart
:
1265 if MappingTitle
.match(Line
) is not None:
1268 ResultList
= MappingFormat
.findall(Line
)
1269 if len(ResultList
) == 0 or len(ResultList
[0]) != 4:
1271 self
._Globals
[ResultList
[2]] = int(ResultList
[3], 16)
1272 EdkLogger
.verbose(ResultList
[0])
1276 def __contains__(self
, Var
):
1277 return Var
in self
._Globals
1279 def __getitem__(self
, Var
):
1280 if Var
not in self
._Globals
:
1282 return self
._Globals
[Var
]
1284 ## MultipleFv() class
1286 # A class for Multiple FV
1288 class MultipleFv(FirmwareVolume
):
1289 def __init__(self
, FvList
):
1290 FirmwareVolume
.__init
__(self
)
1292 for FvPath
in FvList
:
1293 FvName
= os
.path
.splitext(os
.path
.split(FvPath
)[1])[0]
1294 Fd
= open(FvPath
, 'rb')
1297 Buf
.fromfile(Fd
, os
.path
.getsize(FvPath
))
1301 Fv
= FirmwareVolume(FvName
)
1302 Fv
.frombuffer(Buf
, 0, len(Buf
))
1304 self
.BasicInfo
.append([Fv
.Name
, Fv
.FileSystemGuid
, Fv
.Size
])
1305 self
.FfsDict
.append(Fv
.FfsDict
)
1307 # Version and Copyright
1308 __version_number__
= "0.01"
1309 __version__
= "%prog Version " + __version_number__
1310 __copyright__
= "Copyright (c) 2008, Intel Corporation. All rights reserved."
1312 ## Parse command line options
1314 # Using standard Python module optparse to parse command line option of this tool.
1316 # @retval Options A optparse.Values object containing the parsed options
1317 # @retval InputFile Path of file to be trimmed
1321 make_option("-a", "--arch", dest
="Arch",
1322 help="The input file is preprocessed source code, including C or assembly code"),
1323 make_option("-p", "--platform", dest
="ActivePlatform",
1324 help="The input file is preprocessed VFR file"),
1325 make_option("-m", "--module", dest
="ActiveModule",
1326 help="Convert standard hex format (0xabcd) to MASM format (abcdh)"),
1327 make_option("-f", "--FDF-file", dest
="FdfFile",
1328 help="Convert standard hex format (0xabcd) to MASM format (abcdh)"),
1329 make_option("-o", "--output", dest
="OutputDirectory",
1330 help="File to store the trimmed content"),
1331 make_option("-t", "--toolchain-tag", dest
="ToolChain",
1333 make_option("-k", "--msft", dest
="MakefileType", action
="store_const", const
="nmake",
1335 make_option("-g", "--gcc", dest
="MakefileType", action
="store_const", const
="gmake",
1337 make_option("-v", "--verbose", dest
="LogLevel", action
="store_const", const
=EdkLogger
.VERBOSE
,
1338 help="Run verbosely"),
1339 make_option("-d", "--debug", dest
="LogLevel", type="int",
1340 help="Run with debug information"),
1341 make_option("-q", "--quiet", dest
="LogLevel", action
="store_const", const
=EdkLogger
.QUIET
,
1342 help="Run quietly"),
1343 make_option("-?", action
="help", help="show this help message and exit"),
1346 # use clearer usage to override default usage message
1347 UsageString
= "%prog [-a ARCH] [-p PLATFORM] [-m MODULE] [-t TOOLCHAIN_TAG] [-k] [-g] [-v|-d <debug_level>|-q] [-o <output_directory>] [GenC|GenMake]"
1349 Parser
= OptionParser(description
=__copyright__
, version
=__version__
, option_list
=OptionList
, usage
=UsageString
)
1350 Parser
.set_defaults(Arch
=[])
1351 Parser
.set_defaults(ActivePlatform
=None)
1352 Parser
.set_defaults(ActiveModule
=None)
1353 Parser
.set_defaults(OutputDirectory
="build")
1354 Parser
.set_defaults(FdfFile
=None)
1355 Parser
.set_defaults(ToolChain
="MYTOOLS")
1356 if sys
.platform
== "win32":
1357 Parser
.set_defaults(MakefileType
="nmake")
1359 Parser
.set_defaults(MakefileType
="gmake")
1360 Parser
.set_defaults(LogLevel
=EdkLogger
.INFO
)
1362 Options
, Args
= Parser
.parse_args()
1366 Options
.Target
= "genmake"
1367 sys
.argv
.append("genmake")
1368 elif len(Args
) == 1:
1369 Options
.Target
= Args
[0].lower()
1370 if Options
.Target
not in ["genc", "genmake"]:
1371 EdkLogger
.error("AutoGen", OPTION_NOT_SUPPORTED
, "Not supported target",
1372 ExtraData
="%s\n\n%s" % (Options
.Target
, Parser
.get_usage()))
1374 EdkLogger
.error("AutoGen", OPTION_NOT_SUPPORTED
, "Too many targets",
1375 ExtraData
=Parser
.get_usage())
1381 # This method mainly dispatch specific methods per the command line options.
1382 # If no error found, return zero value so the caller of this tool can know
1383 # if it's executed successfully or not.
1385 # @retval 0 Tool was successful
1386 # @retval 1 Tool failed
1389 from build
import build
1391 Option
= GetOptions()
1393 except Exception, e
:
1399 # This acts like the main() function for the script, unless it is 'import'ed into another script.
1400 if __name__
== '__main__':
1401 EdkLogger
.Initialize()
1404 if len(sys
.argv
) > 1:
1405 FilePath
= sys
.argv
[1]
1406 if FilePath
.lower().endswith(".fv"):
1407 fd
= open(FilePath
, 'rb')
1410 buf
.fromfile(fd
, os
.path
.getsize(FilePath
))
1414 fv
= FirmwareVolume("FVRECOVERY")
1415 fv
.frombuffer(buf
, 0, len(buf
))
1418 elif FilePath
.endswith(".efi"):
1419 fd
= open(FilePath
, 'rb')
1421 Size
= os
.path
.getsize(FilePath
)
1424 buf
.fromfile(fd
, Size
)
1428 PeSection
= Section(Type
=0x10)
1429 PeSection
.Data
= buf
1430 sf
, ext
= os
.path
.splitext(os
.path
.basename(FilePath
))
1432 PeSection
.tofile(open(sf
, 'wb'))
1433 elif FilePath
.endswith(".map"):
1434 mf
= LinkMap(FilePath
)