]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py
3 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 # This program and the accompanying materials are licensed and made available
6 # under the terms and conditions of the BSD License which accompanies this
7 # 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.
14 from __future__
import print_function
23 return logging
.getLogger('EFI Binary File')
25 class EFIBinaryError(Exception):
26 def __init__(self
, message
):
27 Exception.__init
__(self
)
28 self
._message
= message
34 EFI_FV_HEADER_SIZE
= 0x48
39 def Load(self
, fd
, size
):
41 while (index
+ self
.EFI_FV_HEADER_SIZE
< size
):
45 index
+= fv
.GetHeader().GetFvLength()
46 index
= align(index
, 8)
53 FILE_SYSTEM_GUID
= uuid
.UUID('{8c8ce578-8a3d-4f1c-9935-896185c32dd3}')
55 def __init__(self
, parent
=None):
59 self
._blockentries
= []
62 # following field is for FV in FD
65 self
._raw
= array
.array('B')
68 self
._offset
= fd
.tell()
69 self
._filename
= fd
.name
72 self
._fvheader
= EfiFirmwareVolumeHeader
.Read(fd
)
73 #self._fvheader.Dump()
75 self
._size
= self
._fvheader
.GetFvLength()
77 if self
._fvheader
.GetFileSystemGuid() != self
.FILE_SYSTEM_GUID
:
79 self
._raw
.fromfile(fd
, self
.GetHeader().GetFvLength())
83 blockentry
= BlockMapEntry
.Read(fd
)
84 self
._blockentries
.append(blockentry
)
85 while (blockentry
.GetNumberBlocks() != 0 and blockentry
.GetLength() != 0):
86 self
._blockentries
.append(blockentry
)
87 blockentry
= BlockMapEntry
.Read(fd
)
90 if self
._fvheader
.GetSize() + (len(self
._blockentries
)) * 8 != \
91 self
._fvheader
.GetHeaderLength():
92 raise EFIBinaryError("Volume Header length not consistent with block map!")
94 index
= align(fd
.tell(), 8)
96 while ((index
+ EfiFfs
.FFS_HEADER_SIZE
) < self
._size
):
97 ffs
= EfiFfs
.Read(fd
, self
)
98 if not isValidGuid(ffs
.GetNameGuid()):
100 self
._ffs
.append(ffs
)
102 index
= align(fd
.tell(), 8)
104 fd
.seek(self
._offset
)
105 self
._raw
.fromfile(fd
, self
.GetHeader().GetFvLength())
111 return self
._fvheader
113 def GetBlockEntries(self
):
114 return self
._blockentries
116 def GetHeaderRawData(self
):
118 ret
+= self
._fvheader
.GetRawData()
119 for block
in self
._blockentries
:
120 ret
+= block
.GetRawData()
126 def GetRawData(self
):
127 return self
._raw
.tolist()
129 class BinaryItem(object):
130 def __init__(self
, parent
=None):
132 self
._arr
= array
.array('B')
133 self
._parent
= parent
136 def Read(cls
, fd
, parent
=None):
145 """should be implemented by inherited class"""
147 def fromfile(self
, fd
):
148 self
._arr
.fromfile(fd
, self
.GetSize())
153 class EfiFirmwareVolumeHeader(BinaryItem
):
157 def GetSigunature(self
):
158 list = self
._arr
.tolist()
160 for x
in list[40:44]:
164 def GetAttribute(self
):
165 return list2int(self
._arr
.tolist()[44:48])
167 def GetErasePolarity(self
):
168 list = self
.GetAttrStrings()
169 if 'EFI_FVB2_ERASE_POLARITY' in list:
173 def GetAttrStrings(self
):
175 value
= self
.GetAttribute()
176 if (value
& 0x01) != 0:
177 list.append('EFI_FVB2_READ_DISABLED_CAP')
178 if (value
& 0x02) != 0:
179 list.append('EFI_FVB2_READ_ENABLED_CAP')
180 if (value
& 0x04) != 0:
181 list.append('EFI_FVB2_READ_STATUS')
182 if (value
& 0x08) != 0:
183 list.append('EFI_FVB2_WRITE_DISABLED_CAP')
184 if (value
& 0x10) != 0:
185 list.append('EFI_FVB2_WRITE_ENABLED_CAP')
186 if (value
& 0x20) != 0:
187 list.append('EFI_FVB2_WRITE_STATUS')
188 if (value
& 0x40) != 0:
189 list.append('EFI_FVB2_LOCK_CAP')
190 if (value
& 0x80) != 0:
191 list.append('EFI_FVB2_LOCK_STATUS')
192 if (value
& 0x200) != 0:
193 list.append('EFI_FVB2_STICKY_WRITE')
194 if (value
& 0x400) != 0:
195 list.append('EFI_FVB2_MEMORY_MAPPED')
196 if (value
& 0x800) != 0:
197 list.append('EFI_FVB2_ERASE_POLARITY')
198 if (value
& 0x1000) != 0:
199 list.append('EFI_FVB2_READ_LOCK_CAP')
200 if (value
& 0x00002000) != 0:
201 list.append('EFI_FVB2_READ_LOCK_STATUS')
202 if (value
& 0x00004000) != 0:
203 list.append('EFI_FVB2_WRITE_LOCK_CAP')
204 if (value
& 0x00008000) != 0:
205 list.append('EFI_FVB2_WRITE_LOCK_STATUS')
208 list.append('EFI_FVB2_ALIGNMENT_1')
209 if (value
& 0x001F0000) == 0x00010000:
210 list.append('EFI_FVB2_ALIGNMENT_2')
211 if (value
& 0x001F0000) == 0x00020000:
212 list.append('EFI_FVB2_ALIGNMENT_4')
213 if (value
& 0x001F0000) == 0x00030000:
214 list.append('EFI_FVB2_ALIGNMENT_8')
215 if (value
& 0x001F0000) == 0x00040000:
216 list.append('EFI_FVB2_ALIGNMENT_16')
217 if (value
& 0x001F0000) == 0x00050000:
218 list.append('EFI_FVB2_ALIGNMENT_32')
219 if (value
& 0x001F0000) == 0x00060000:
220 list.append('EFI_FVB2_ALIGNMENT_64')
221 if (value
& 0x001F0000) == 0x00070000:
222 list.append('EFI_FVB2_ALIGNMENT_128')
223 if (value
& 0x001F0000) == 0x00080000:
224 list.append('EFI_FVB2_ALIGNMENT_256')
225 if (value
& 0x001F0000) == 0x00090000:
226 list.append('EFI_FVB2_ALIGNMENT_512')
227 if (value
& 0x001F0000) == 0x000A0000:
228 list.append('EFI_FVB2_ALIGNMENT_1K')
229 if (value
& 0x001F0000) == 0x000B0000:
230 list.append('EFI_FVB2_ALIGNMENT_2K')
231 if (value
& 0x001F0000) == 0x000C0000:
232 list.append('EFI_FVB2_ALIGNMENT_4K')
233 if (value
& 0x001F0000) == 0x000D0000:
234 list.append('EFI_FVB2_ALIGNMENT_8K')
235 if (value
& 0x001F0000) == 0x000E0000:
236 list.append('EFI_FVB2_ALIGNMENT_16K')
237 if (value
& 0x001F0000) == 0x000F0000:
238 list.append('EFI_FVB2_ALIGNMENT_32K')
239 if (value
& 0x001F0000) == 0x00100000:
240 list.append('EFI_FVB2_ALIGNMENT_64K')
241 if (value
& 0x001F0000) == 0x00110000:
242 list.append('EFI_FVB2_ALIGNMENT_128K')
243 if (value
& 0x001F0000) == 0x00120000:
244 list.append('EFI_FVB2_ALIGNMENT_256K')
245 if (value
& 0x001F0000) == 0x00130000:
246 list.append('EFI_FVB2_ALIGNMENT_512K')
250 def GetHeaderLength(self
):
251 return list2int(self
._arr
.tolist()[48:50])
254 print('Signature: %s' % self
.GetSigunature())
255 print('Attribute: 0x%X' % self
.GetAttribute())
256 print('Header Length: 0x%X' % self
.GetHeaderLength())
257 print('File system Guid: ', self
.GetFileSystemGuid())
258 print('Revision: 0x%X' % self
.GetRevision())
259 print('FvLength: 0x%X' % self
.GetFvLength())
261 def GetFileSystemGuid(self
):
262 list = self
._arr
.tolist()
263 return list2guid(list[16:32])
265 def GetRevision(self
):
266 list = self
._arr
.tolist()
269 def GetFvLength(self
):
270 list = self
._arr
.tolist()
271 return list2int(list[32:40])
273 def GetRawData(self
):
274 return self
._arr
.tolist()
276 class BlockMapEntry(BinaryItem
):
280 def GetNumberBlocks(self
):
281 list = self
._arr
.tolist()
282 return list2int(list[0:4])
285 list = self
._arr
.tolist()
286 return list2int(list[4:8])
288 def GetRawData(self
):
289 return self
._arr
.tolist()
292 return '[BlockEntry] Number = 0x%X, length=0x%X' % (self
.GetNumberBlocks(), self
.GetLength())
294 class EfiFfs(object):
297 def __init__(self
, parent
=None):
300 # following field is for FFS in FV file.
301 self
._parent
= parent
306 self
._offset
= align(fd
.tell(), 8)
308 self
._header
= EfiFfsHeader
.Read(fd
, self
)
310 if not isValidGuid(self
.GetNameGuid()):
314 fileend
= self
._offset
+ self
.GetSize()
315 while (index
+ EfiSection
.EFI_SECTION_HEADER_SIZE
< fileend
):
316 section
= EfiSection(self
)
318 if section
.GetSize() == 0 and section
.GetHeader().GetType() == 0:
320 self
._sections
.append(section
)
323 # rebase file pointer to next ffs file
324 index
= self
._offset
+ self
._header
.GetFfsSize()
325 index
= align(index
, 8)
332 return self
._header
.GetFfsSize()
335 def Read(cls
, fd
, parent
=None):
340 def GetNameGuid(self
):
341 return self
._header
.GetNameGuid()
343 def DumpContent(self
):
344 list = self
._content
.tolist()
349 line
.append('0x%X' % int(item
))
352 print(' '.join(line
))
355 line
.append('0x%X' % int(item
))
364 def GetSections(self
):
365 return self
._sections
367 class EfiFfsHeader(BinaryItem
):
368 ffs_state_map
= {0x01:'EFI_FILE_HEADER_CONSTRUCTION',
369 0x02:'EFI_FILE_HEADER_VALID',
370 0x04:'EFI_FILE_DATA_VALID',
371 0x08:'EFI_FILE_MARKED_FOR_UPDATE',
372 0x10:'EFI_FILE_DELETED',
373 0x20:'EFI_FILE_HEADER_INVALID'}
378 def GetNameGuid(self
):
379 list = self
._arr
.tolist()
380 return list2guid(list[0:16])
383 list = self
._arr
.tolist()
387 def GetTypeString(self
):
388 value
= self
.GetType()
390 return 'EFI_FV_FILETYPE_RAW'
392 return 'EFI_FV_FILETYPE_FREEFORM'
394 return 'EFI_FV_FILETYPE_SECURITY_CORE'
396 return 'EFI_FV_FILETYPE_PEI_CORE'
398 return 'EFI_FV_FILETYPE_DXE_CORE'
400 return 'EFI_FV_FILETYPE_PEIM'
402 return 'EFI_FV_FILETYPE_DRIVER'
404 return 'EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER'
406 return 'EFI_FV_FILETYPE_APPLICATION'
408 return 'EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE'
410 return 'EFI_FV_FILETYPE_OEM_MIN'
412 return 'EFI_FV_FILETYPE_OEM_MAX'
414 return 'EFI_FV_FILETYPE_DEBUG_MIN'
416 return 'EFI_FV_FILETYPE_DEBUG_MAX'
418 return 'EFI_FV_FILETYPE_FFS_PAD'
420 return 'EFI_FV_FILETYPE_FFS_MAX'
421 return 'Unknown FFS Type'
423 def GetAttributes(self
):
424 list = self
._arr
.tolist()
427 def GetFfsSize(self
):
428 list = self
._arr
.tolist()
429 return list2int(list[20:23])
432 list = self
._arr
.tolist()
433 state
= int(list[23])
434 polarity
= self
.GetParent().GetParent().GetHeader().GetErasePolarity()
436 state
= (~state
) & 0xFF
438 while (HighestBit
!= 0) and (HighestBit
& state
) == 0:
439 HighestBit
= HighestBit
>> 1
442 def GetStateString(self
):
443 state
= self
.GetState()
444 if state
in self
.ffs_state_map
.keys():
445 return self
.ffs_state_map
[state
]
446 return 'Unknown Ffs State'
449 print("FFS name: ", self
.GetNameGuid())
450 print("FFS type: ", self
.GetType())
451 print("FFS attr: 0x%X" % self
.GetAttributes())
452 print("FFS size: 0x%X" % self
.GetFfsSize())
453 print("FFS state: 0x%X" % self
.GetState())
455 def GetRawData(self
):
456 return self
._arr
.tolist()
459 class EfiSection(object):
460 EFI_SECTION_HEADER_SIZE
= 4
462 def __init__(self
, parent
=None):
464 self
._parent
= parent
466 self
._contents
= array
.array('B')
469 self
._offset
= align(fd
.tell(), 4)
471 self
._header
= EfiSectionHeader
.Read(fd
, self
)
473 if self
._header
.GetTypeString() == "EFI_SECTION_PE32":
474 pefile
= pe
.PEFile(self
)
475 pefile
.Load(fd
, self
.GetContentSize())
477 fd
.seek(self
._offset
)
478 self
._contents
.fromfile(fd
, self
.GetContentSize())
480 # rebase file pointer to next section
481 index
= self
._offset
+ self
.GetSize()
482 index
= align(index
, 4)
485 def GetContentSize(self
):
486 return self
.GetSize() - self
.EFI_SECTION_HEADER_SIZE
488 def GetContent(self
):
489 return self
._contents
.tolist()
492 return self
._header
.GetSectionSize()
497 def GetSectionOffset(self
):
498 return self
._offset
+ self
.EFI_SECTION_HEADER_SIZE
500 class EfiSectionHeader(BinaryItem
):
501 section_type_map
= {0x01: 'EFI_SECTION_COMPRESSION',
502 0x02: 'EFI_SECTION_GUID_DEFINED',
503 0x10: 'EFI_SECTION_PE32',
504 0x11: 'EFI_SECTION_PIC',
505 0x12: 'EFI_SECTION_TE',
506 0x13: 'EFI_SECTION_DXE_DEPEX',
507 0x14: 'EFI_SECTION_VERSION',
508 0x15: 'EFI_SECTION_USER_INTERFACE',
509 0x16: 'EFI_SECTION_COMPATIBILITY16',
510 0x17: 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE',
511 0x18: 'EFI_SECTION_FREEFORM_SUBTYPE_GUID',
512 0x19: 'EFI_SECTION_RAW',
513 0x1B: 'EFI_SECTION_PEI_DEPEX'}
517 def GetSectionSize(self
):
518 list = self
._arr
.tolist()
519 return list2int(list[0:3])
522 list = self
._arr
.tolist()
525 def GetTypeString(self
):
526 type = self
.GetType()
527 if type not in self
.section_type_map
.keys():
528 return 'Unknown Section Type'
529 return self
.section_type_map
[type]
532 print('size = 0x%X' % self
.GetSectionSize())
533 print('type = 0x%X' % self
.GetType())
537 rMapEntry
= re
.compile('^(\w+)[ \(\w\)]* \(BaseAddress=([0-9a-fA-F]+), EntryPoint=([0-9a-fA-F]+), GUID=([0-9a-fA-F\-]+)')
538 class EfiFvMapFile(object):
540 self
._mapentries
= {}
542 def Load(self
, path
):
543 if not os
.path
.exists(path
):
547 file = open(path
, 'r')
548 lines
= file.readlines()
556 ret
= rMapEntry
.match(line
)
558 name
= ret
.groups()[0]
559 baseaddr
= int(ret
.groups()[1], 16)
560 entry
= int(ret
.groups()[2], 16)
561 guidstr
= '{' + ret
.groups()[3] + '}'
562 guid
= uuid
.UUID(guidstr
)
563 self
._mapentries
[guid
] = EfiFvMapFileEntry(name
, baseaddr
, entry
, guid
)
566 def GetEntry(self
, guid
):
567 if guid
in self
._mapentries
.keys():
568 return self
._mapentries
[guid
]
571 class EfiFvMapFileEntry(object):
572 def __init__(self
, name
, baseaddr
, entry
, guid
):
574 self
._baseaddr
= baseaddr
581 def GetBaseAddress(self
):
582 return self
._baseaddr
584 def GetEntryPoint(self
):
588 val1
= list2int(list[0:4])
589 val2
= list2int(list[4:6])
590 val3
= list2int(list[6:8])
592 for item
in list[8:16]:
593 val4
= (val4
<< 8) |
int(item
)
595 val
= val1
<< 12 * 8 | val2
<< 10 * 8 | val3
<< 8 * 8 | val4
596 guid
= uuid
.UUID(int=val
)
601 for index
in range(len(list) - 1, -1, -1):
602 val
= (val
<< 8) |
int(list[index
])
605 def align(value
, alignment
):
606 return (value
+ ((alignment
- value
) & (alignment
- 1)))
608 gInvalidGuid
= uuid
.UUID(int=0xffffffffffffffffffffffffffffffff)
609 def isValidGuid(guid
):
610 if guid
== gInvalidGuid
: