]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py
1bc4938bfcdf8948ad8a73bcbe201f895094faed
3 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 # SPDX-License-Identifier: BSD-2-Clause-Patent
8 from __future__
import print_function
17 return logging
.getLogger('EFI Binary File')
19 class EFIBinaryError(Exception):
20 def __init__(self
, message
):
21 Exception.__init
__(self
)
22 self
._message
= message
28 EFI_FV_HEADER_SIZE
= 0x48
33 def Load(self
, fd
, size
):
35 while (index
+ self
.EFI_FV_HEADER_SIZE
< size
):
39 index
+= fv
.GetHeader().GetFvLength()
40 index
= align(index
, 8)
47 FILE_SYSTEM_GUID
= uuid
.UUID('{8c8ce578-8a3d-4f1c-9935-896185c32dd3}')
49 def __init__(self
, parent
=None):
53 self
._blockentries
= []
56 # following field is for FV in FD
59 self
._raw
= array
.array('B')
62 self
._offset
= fd
.tell()
63 self
._filename
= fd
.name
66 self
._fvheader
= EfiFirmwareVolumeHeader
.Read(fd
)
67 #self._fvheader.Dump()
69 self
._size
= self
._fvheader
.GetFvLength()
71 if self
._fvheader
.GetFileSystemGuid() != self
.FILE_SYSTEM_GUID
:
73 self
._raw
.fromfile(fd
, self
.GetHeader().GetFvLength())
77 blockentry
= BlockMapEntry
.Read(fd
)
78 self
._blockentries
.append(blockentry
)
79 while (blockentry
.GetNumberBlocks() != 0 and blockentry
.GetLength() != 0):
80 self
._blockentries
.append(blockentry
)
81 blockentry
= BlockMapEntry
.Read(fd
)
84 if self
._fvheader
.GetSize() + (len(self
._blockentries
)) * 8 != \
85 self
._fvheader
.GetHeaderLength():
86 raise EFIBinaryError("Volume Header length not consistent with block map!")
88 index
= align(fd
.tell(), 8)
90 while ((index
+ EfiFfs
.FFS_HEADER_SIZE
) < self
._size
):
91 ffs
= EfiFfs
.Read(fd
, self
)
92 if not isValidGuid(ffs
.GetNameGuid()):
96 index
= align(fd
.tell(), 8)
99 self
._raw
.fromfile(fd
, self
.GetHeader().GetFvLength())
105 return self
._fvheader
107 def GetBlockEntries(self
):
108 return self
._blockentries
110 def GetHeaderRawData(self
):
112 ret
+= self
._fvheader
.GetRawData()
113 for block
in self
._blockentries
:
114 ret
+= block
.GetRawData()
120 def GetRawData(self
):
121 return self
._raw
.tolist()
123 class BinaryItem(object):
124 def __init__(self
, parent
=None):
126 self
._arr
= array
.array('B')
127 self
._parent
= parent
130 def Read(cls
, fd
, parent
=None):
139 """should be implemented by inherited class"""
141 def fromfile(self
, fd
):
142 self
._arr
.fromfile(fd
, self
.GetSize())
147 class EfiFirmwareVolumeHeader(BinaryItem
):
151 def GetSigunature(self
):
152 list = self
._arr
.tolist()
154 for x
in list[40:44]:
158 def GetAttribute(self
):
159 return list2int(self
._arr
.tolist()[44:48])
161 def GetErasePolarity(self
):
162 list = self
.GetAttrStrings()
163 if 'EFI_FVB2_ERASE_POLARITY' in list:
167 def GetAttrStrings(self
):
169 value
= self
.GetAttribute()
170 if (value
& 0x01) != 0:
171 list.append('EFI_FVB2_READ_DISABLED_CAP')
172 if (value
& 0x02) != 0:
173 list.append('EFI_FVB2_READ_ENABLED_CAP')
174 if (value
& 0x04) != 0:
175 list.append('EFI_FVB2_READ_STATUS')
176 if (value
& 0x08) != 0:
177 list.append('EFI_FVB2_WRITE_DISABLED_CAP')
178 if (value
& 0x10) != 0:
179 list.append('EFI_FVB2_WRITE_ENABLED_CAP')
180 if (value
& 0x20) != 0:
181 list.append('EFI_FVB2_WRITE_STATUS')
182 if (value
& 0x40) != 0:
183 list.append('EFI_FVB2_LOCK_CAP')
184 if (value
& 0x80) != 0:
185 list.append('EFI_FVB2_LOCK_STATUS')
186 if (value
& 0x200) != 0:
187 list.append('EFI_FVB2_STICKY_WRITE')
188 if (value
& 0x400) != 0:
189 list.append('EFI_FVB2_MEMORY_MAPPED')
190 if (value
& 0x800) != 0:
191 list.append('EFI_FVB2_ERASE_POLARITY')
192 if (value
& 0x1000) != 0:
193 list.append('EFI_FVB2_READ_LOCK_CAP')
194 if (value
& 0x00002000) != 0:
195 list.append('EFI_FVB2_READ_LOCK_STATUS')
196 if (value
& 0x00004000) != 0:
197 list.append('EFI_FVB2_WRITE_LOCK_CAP')
198 if (value
& 0x00008000) != 0:
199 list.append('EFI_FVB2_WRITE_LOCK_STATUS')
202 list.append('EFI_FVB2_ALIGNMENT_1')
203 if (value
& 0x001F0000) == 0x00010000:
204 list.append('EFI_FVB2_ALIGNMENT_2')
205 if (value
& 0x001F0000) == 0x00020000:
206 list.append('EFI_FVB2_ALIGNMENT_4')
207 if (value
& 0x001F0000) == 0x00030000:
208 list.append('EFI_FVB2_ALIGNMENT_8')
209 if (value
& 0x001F0000) == 0x00040000:
210 list.append('EFI_FVB2_ALIGNMENT_16')
211 if (value
& 0x001F0000) == 0x00050000:
212 list.append('EFI_FVB2_ALIGNMENT_32')
213 if (value
& 0x001F0000) == 0x00060000:
214 list.append('EFI_FVB2_ALIGNMENT_64')
215 if (value
& 0x001F0000) == 0x00070000:
216 list.append('EFI_FVB2_ALIGNMENT_128')
217 if (value
& 0x001F0000) == 0x00080000:
218 list.append('EFI_FVB2_ALIGNMENT_256')
219 if (value
& 0x001F0000) == 0x00090000:
220 list.append('EFI_FVB2_ALIGNMENT_512')
221 if (value
& 0x001F0000) == 0x000A0000:
222 list.append('EFI_FVB2_ALIGNMENT_1K')
223 if (value
& 0x001F0000) == 0x000B0000:
224 list.append('EFI_FVB2_ALIGNMENT_2K')
225 if (value
& 0x001F0000) == 0x000C0000:
226 list.append('EFI_FVB2_ALIGNMENT_4K')
227 if (value
& 0x001F0000) == 0x000D0000:
228 list.append('EFI_FVB2_ALIGNMENT_8K')
229 if (value
& 0x001F0000) == 0x000E0000:
230 list.append('EFI_FVB2_ALIGNMENT_16K')
231 if (value
& 0x001F0000) == 0x000F0000:
232 list.append('EFI_FVB2_ALIGNMENT_32K')
233 if (value
& 0x001F0000) == 0x00100000:
234 list.append('EFI_FVB2_ALIGNMENT_64K')
235 if (value
& 0x001F0000) == 0x00110000:
236 list.append('EFI_FVB2_ALIGNMENT_128K')
237 if (value
& 0x001F0000) == 0x00120000:
238 list.append('EFI_FVB2_ALIGNMENT_256K')
239 if (value
& 0x001F0000) == 0x00130000:
240 list.append('EFI_FVB2_ALIGNMENT_512K')
244 def GetHeaderLength(self
):
245 return list2int(self
._arr
.tolist()[48:50])
248 print('Signature: %s' % self
.GetSigunature())
249 print('Attribute: 0x%X' % self
.GetAttribute())
250 print('Header Length: 0x%X' % self
.GetHeaderLength())
251 print('File system Guid: ', self
.GetFileSystemGuid())
252 print('Revision: 0x%X' % self
.GetRevision())
253 print('FvLength: 0x%X' % self
.GetFvLength())
255 def GetFileSystemGuid(self
):
256 list = self
._arr
.tolist()
257 return list2guid(list[16:32])
259 def GetRevision(self
):
260 list = self
._arr
.tolist()
263 def GetFvLength(self
):
264 list = self
._arr
.tolist()
265 return list2int(list[32:40])
267 def GetRawData(self
):
268 return self
._arr
.tolist()
270 class BlockMapEntry(BinaryItem
):
274 def GetNumberBlocks(self
):
275 list = self
._arr
.tolist()
276 return list2int(list[0:4])
279 list = self
._arr
.tolist()
280 return list2int(list[4:8])
282 def GetRawData(self
):
283 return self
._arr
.tolist()
286 return '[BlockEntry] Number = 0x%X, length=0x%X' % (self
.GetNumberBlocks(), self
.GetLength())
288 class EfiFfs(object):
291 def __init__(self
, parent
=None):
294 # following field is for FFS in FV file.
295 self
._parent
= parent
300 self
._offset
= align(fd
.tell(), 8)
302 self
._header
= EfiFfsHeader
.Read(fd
, self
)
304 if not isValidGuid(self
.GetNameGuid()):
308 fileend
= self
._offset
+ self
.GetSize()
309 while (index
+ EfiSection
.EFI_SECTION_HEADER_SIZE
< fileend
):
310 section
= EfiSection(self
)
312 if section
.GetSize() == 0 and section
.GetHeader().GetType() == 0:
314 self
._sections
.append(section
)
317 # rebase file pointer to next ffs file
318 index
= self
._offset
+ self
._header
.GetFfsSize()
319 index
= align(index
, 8)
326 return self
._header
.GetFfsSize()
329 def Read(cls
, fd
, parent
=None):
334 def GetNameGuid(self
):
335 return self
._header
.GetNameGuid()
337 def DumpContent(self
):
338 list = self
._content
.tolist()
343 line
.append('0x%X' % int(item
))
346 print(' '.join(line
))
349 line
.append('0x%X' % int(item
))
358 def GetSections(self
):
359 return self
._sections
361 class EfiFfsHeader(BinaryItem
):
362 ffs_state_map
= {0x01:'EFI_FILE_HEADER_CONSTRUCTION',
363 0x02:'EFI_FILE_HEADER_VALID',
364 0x04:'EFI_FILE_DATA_VALID',
365 0x08:'EFI_FILE_MARKED_FOR_UPDATE',
366 0x10:'EFI_FILE_DELETED',
367 0x20:'EFI_FILE_HEADER_INVALID'}
372 def GetNameGuid(self
):
373 list = self
._arr
.tolist()
374 return list2guid(list[0:16])
377 list = self
._arr
.tolist()
381 def GetTypeString(self
):
382 value
= self
.GetType()
384 return 'EFI_FV_FILETYPE_RAW'
386 return 'EFI_FV_FILETYPE_FREEFORM'
388 return 'EFI_FV_FILETYPE_SECURITY_CORE'
390 return 'EFI_FV_FILETYPE_PEI_CORE'
392 return 'EFI_FV_FILETYPE_DXE_CORE'
394 return 'EFI_FV_FILETYPE_PEIM'
396 return 'EFI_FV_FILETYPE_DRIVER'
398 return 'EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER'
400 return 'EFI_FV_FILETYPE_APPLICATION'
402 return 'EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE'
404 return 'EFI_FV_FILETYPE_OEM_MIN'
406 return 'EFI_FV_FILETYPE_OEM_MAX'
408 return 'EFI_FV_FILETYPE_DEBUG_MIN'
410 return 'EFI_FV_FILETYPE_DEBUG_MAX'
412 return 'EFI_FV_FILETYPE_FFS_PAD'
414 return 'EFI_FV_FILETYPE_FFS_MAX'
415 return 'Unknown FFS Type'
417 def GetAttributes(self
):
418 list = self
._arr
.tolist()
421 def GetFfsSize(self
):
422 list = self
._arr
.tolist()
423 return list2int(list[20:23])
426 list = self
._arr
.tolist()
427 state
= int(list[23])
428 polarity
= self
.GetParent().GetParent().GetHeader().GetErasePolarity()
430 state
= (~state
) & 0xFF
432 while (HighestBit
!= 0) and (HighestBit
& state
) == 0:
433 HighestBit
= HighestBit
>> 1
436 def GetStateString(self
):
437 state
= self
.GetState()
438 if state
in self
.ffs_state_map
.keys():
439 return self
.ffs_state_map
[state
]
440 return 'Unknown Ffs State'
443 print("FFS name: ", self
.GetNameGuid())
444 print("FFS type: ", self
.GetType())
445 print("FFS attr: 0x%X" % self
.GetAttributes())
446 print("FFS size: 0x%X" % self
.GetFfsSize())
447 print("FFS state: 0x%X" % self
.GetState())
449 def GetRawData(self
):
450 return self
._arr
.tolist()
453 class EfiSection(object):
454 EFI_SECTION_HEADER_SIZE
= 4
456 def __init__(self
, parent
=None):
458 self
._parent
= parent
460 self
._contents
= array
.array('B')
463 self
._offset
= align(fd
.tell(), 4)
465 self
._header
= EfiSectionHeader
.Read(fd
, self
)
467 if self
._header
.GetTypeString() == "EFI_SECTION_PE32":
468 pefile
= pe
.PEFile(self
)
469 pefile
.Load(fd
, self
.GetContentSize())
471 fd
.seek(self
._offset
)
472 self
._contents
.fromfile(fd
, self
.GetContentSize())
474 # rebase file pointer to next section
475 index
= self
._offset
+ self
.GetSize()
476 index
= align(index
, 4)
479 def GetContentSize(self
):
480 return self
.GetSize() - self
.EFI_SECTION_HEADER_SIZE
482 def GetContent(self
):
483 return self
._contents
.tolist()
486 return self
._header
.GetSectionSize()
491 def GetSectionOffset(self
):
492 return self
._offset
+ self
.EFI_SECTION_HEADER_SIZE
494 class EfiSectionHeader(BinaryItem
):
495 section_type_map
= {0x01: 'EFI_SECTION_COMPRESSION',
496 0x02: 'EFI_SECTION_GUID_DEFINED',
497 0x10: 'EFI_SECTION_PE32',
498 0x11: 'EFI_SECTION_PIC',
499 0x12: 'EFI_SECTION_TE',
500 0x13: 'EFI_SECTION_DXE_DEPEX',
501 0x14: 'EFI_SECTION_VERSION',
502 0x15: 'EFI_SECTION_USER_INTERFACE',
503 0x16: 'EFI_SECTION_COMPATIBILITY16',
504 0x17: 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE',
505 0x18: 'EFI_SECTION_FREEFORM_SUBTYPE_GUID',
506 0x19: 'EFI_SECTION_RAW',
507 0x1B: 'EFI_SECTION_PEI_DEPEX'}
511 def GetSectionSize(self
):
512 list = self
._arr
.tolist()
513 return list2int(list[0:3])
516 list = self
._arr
.tolist()
519 def GetTypeString(self
):
520 type = self
.GetType()
521 if type not in self
.section_type_map
.keys():
522 return 'Unknown Section Type'
523 return self
.section_type_map
[type]
526 print('size = 0x%X' % self
.GetSectionSize())
527 print('type = 0x%X' % self
.GetType())
531 rMapEntry
= re
.compile('^(\w+)[ \(\w\)]* \(BaseAddress=([0-9a-fA-F]+), EntryPoint=([0-9a-fA-F]+), GUID=([0-9a-fA-F\-]+)')
532 class EfiFvMapFile(object):
534 self
._mapentries
= {}
536 def Load(self
, path
):
537 if not os
.path
.exists(path
):
541 file = open(path
, 'r')
542 lines
= file.readlines()
550 ret
= rMapEntry
.match(line
)
552 name
= ret
.groups()[0]
553 baseaddr
= int(ret
.groups()[1], 16)
554 entry
= int(ret
.groups()[2], 16)
555 guidstr
= '{' + ret
.groups()[3] + '}'
556 guid
= uuid
.UUID(guidstr
)
557 self
._mapentries
[guid
] = EfiFvMapFileEntry(name
, baseaddr
, entry
, guid
)
560 def GetEntry(self
, guid
):
561 if guid
in self
._mapentries
.keys():
562 return self
._mapentries
[guid
]
565 class EfiFvMapFileEntry(object):
566 def __init__(self
, name
, baseaddr
, entry
, guid
):
568 self
._baseaddr
= baseaddr
575 def GetBaseAddress(self
):
576 return self
._baseaddr
578 def GetEntryPoint(self
):
582 val1
= list2int(list[0:4])
583 val2
= list2int(list[4:6])
584 val3
= list2int(list[6:8])
586 for item
in list[8:16]:
587 val4
= (val4
<< 8) |
int(item
)
589 val
= val1
<< 12 * 8 | val2
<< 10 * 8 | val3
<< 8 * 8 | val4
590 guid
= uuid
.UUID(int=val
)
595 for index
in range(len(list) - 1, -1, -1):
596 val
= (val
<< 8) |
int(list[index
])
599 def align(value
, alignment
):
600 return (value
+ ((alignment
- value
) & (alignment
- 1)))
602 gInvalidGuid
= uuid
.UUID(int=0xffffffffffffffffffffffffffffffff)
603 def isValidGuid(guid
):
604 if guid
== gInvalidGuid
: