summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py')
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py606
1 files changed, 606 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py b/src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py
new file mode 100755
index 00000000..44ab7511
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/BaseTools/Scripts/PackageDocumentTools/plugins/EdkPlugins/basemodel/efibinary.py
@@ -0,0 +1,606 @@
+## @file
+#
+# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+from __future__ import print_function
+import array
+import uuid
+import re
+import os
+import logging
+import core.pe as pe
+
+def GetLogger():
+ return logging.getLogger('EFI Binary File')
+
+class EFIBinaryError(Exception):
+ def __init__(self, message):
+ Exception.__init__(self)
+ self._message = message
+
+ def GetMessage(self):
+ return self._message
+
+class EfiFd(object):
+ EFI_FV_HEADER_SIZE = 0x48
+
+ def __init__(self):
+ self._fvs = []
+
+ def Load(self, fd, size):
+ index = fd.tell()
+ while (index + self.EFI_FV_HEADER_SIZE < size):
+ fv = EfiFv(self)
+ fv.Load(fd)
+ self._fvs.append(fv)
+ index += fv.GetHeader().GetFvLength()
+ index = align(index, 8)
+ fd.seek(index)
+
+ def GetFvs(self):
+ return self._fvs
+
+class EfiFv(object):
+ FILE_SYSTEM_GUID = uuid.UUID('{8c8ce578-8a3d-4f1c-9935-896185c32dd3}')
+
+ def __init__(self, parent=None):
+ self._size = 0
+ self._filename = None
+ self._fvheader = None
+ self._blockentries = []
+ self._ffs = []
+
+ # following field is for FV in FD
+ self._parent = parent
+ self._offset = 0
+ self._raw = array.array('B')
+
+ def Load(self, fd):
+ self._offset = fd.tell()
+ self._filename = fd.name
+
+ # get file header
+ self._fvheader = EfiFirmwareVolumeHeader.Read(fd)
+ #self._fvheader.Dump()
+
+ self._size = self._fvheader.GetFvLength()
+
+ if self._fvheader.GetFileSystemGuid() != self.FILE_SYSTEM_GUID:
+ fd.seek(self._offset)
+ self._raw.fromfile(fd, self.GetHeader().GetFvLength())
+ return
+
+ # read block map
+ blockentry = BlockMapEntry.Read(fd)
+ self._blockentries.append(blockentry)
+ while (blockentry.GetNumberBlocks() != 0 and blockentry.GetLength() != 0):
+ self._blockentries.append(blockentry)
+ blockentry = BlockMapEntry.Read(fd)
+
+
+ if self._fvheader.GetSize() + (len(self._blockentries)) * 8 != \
+ self._fvheader.GetHeaderLength():
+ raise EFIBinaryError("Volume Header length not consistent with block map!")
+
+ index = align(fd.tell(), 8)
+ count = 0
+ while ((index + EfiFfs.FFS_HEADER_SIZE) < self._size):
+ ffs = EfiFfs.Read(fd, self)
+ if not isValidGuid(ffs.GetNameGuid()):
+ break
+ self._ffs.append(ffs)
+ count += 1
+ index = align(fd.tell(), 8)
+
+ fd.seek(self._offset)
+ self._raw.fromfile(fd, self.GetHeader().GetFvLength())
+
+ def GetFfs(self):
+ return self._ffs
+
+ def GetHeader(self):
+ return self._fvheader
+
+ def GetBlockEntries(self):
+ return self._blockentries
+
+ def GetHeaderRawData(self):
+ ret = []
+ ret += self._fvheader.GetRawData()
+ for block in self._blockentries:
+ ret += block.GetRawData()
+ return ret
+
+ def GetOffset(self):
+ return 0
+
+ def GetRawData(self):
+ return self._raw.tolist()
+
+class BinaryItem(object):
+ def __init__(self, parent=None):
+ self._size = 0
+ self._arr = array.array('B')
+ self._parent = parent
+
+ @classmethod
+ def Read(cls, fd, parent=None):
+ item = cls(parent)
+ item.fromfile(fd)
+ return item
+
+ def Load(self, fd):
+ self.fromfile(fd)
+
+ def GetSize(self):
+ """should be implemented by inherited class"""
+
+ def fromfile(self, fd):
+ self._arr.fromfile(fd, self.GetSize())
+
+ def GetParent(self):
+ return self._parent
+
+class EfiFirmwareVolumeHeader(BinaryItem):
+ def GetSize(self):
+ return 56
+
+ def GetSigunature(self):
+ list = self._arr.tolist()
+ sig = ''
+ for x in list[40:44]:
+ sig += chr(x)
+ return sig
+
+ def GetAttribute(self):
+ return list2int(self._arr.tolist()[44:48])
+
+ def GetErasePolarity(self):
+ list = self.GetAttrStrings()
+ if 'EFI_FVB2_ERASE_POLARITY' in list:
+ return True
+ return False
+
+ def GetAttrStrings(self):
+ list = []
+ value = self.GetAttribute()
+ if (value & 0x01) != 0:
+ list.append('EFI_FVB2_READ_DISABLED_CAP')
+ if (value & 0x02) != 0:
+ list.append('EFI_FVB2_READ_ENABLED_CAP')
+ if (value & 0x04) != 0:
+ list.append('EFI_FVB2_READ_STATUS')
+ if (value & 0x08) != 0:
+ list.append('EFI_FVB2_WRITE_DISABLED_CAP')
+ if (value & 0x10) != 0:
+ list.append('EFI_FVB2_WRITE_ENABLED_CAP')
+ if (value & 0x20) != 0:
+ list.append('EFI_FVB2_WRITE_STATUS')
+ if (value & 0x40) != 0:
+ list.append('EFI_FVB2_LOCK_CAP')
+ if (value & 0x80) != 0:
+ list.append('EFI_FVB2_LOCK_STATUS')
+ if (value & 0x200) != 0:
+ list.append('EFI_FVB2_STICKY_WRITE')
+ if (value & 0x400) != 0:
+ list.append('EFI_FVB2_MEMORY_MAPPED')
+ if (value & 0x800) != 0:
+ list.append('EFI_FVB2_ERASE_POLARITY')
+ if (value & 0x1000) != 0:
+ list.append('EFI_FVB2_READ_LOCK_CAP')
+ if (value & 0x00002000) != 0:
+ list.append('EFI_FVB2_READ_LOCK_STATUS')
+ if (value & 0x00004000) != 0:
+ list.append('EFI_FVB2_WRITE_LOCK_CAP')
+ if (value & 0x00008000) != 0:
+ list.append('EFI_FVB2_WRITE_LOCK_STATUS')
+
+ if (value == 0):
+ list.append('EFI_FVB2_ALIGNMENT_1')
+ if (value & 0x001F0000) == 0x00010000:
+ list.append('EFI_FVB2_ALIGNMENT_2')
+ if (value & 0x001F0000) == 0x00020000:
+ list.append('EFI_FVB2_ALIGNMENT_4')
+ if (value & 0x001F0000) == 0x00030000:
+ list.append('EFI_FVB2_ALIGNMENT_8')
+ if (value & 0x001F0000) == 0x00040000:
+ list.append('EFI_FVB2_ALIGNMENT_16')
+ if (value & 0x001F0000) == 0x00050000:
+ list.append('EFI_FVB2_ALIGNMENT_32')
+ if (value & 0x001F0000) == 0x00060000:
+ list.append('EFI_FVB2_ALIGNMENT_64')
+ if (value & 0x001F0000) == 0x00070000:
+ list.append('EFI_FVB2_ALIGNMENT_128')
+ if (value & 0x001F0000) == 0x00080000:
+ list.append('EFI_FVB2_ALIGNMENT_256')
+ if (value & 0x001F0000) == 0x00090000:
+ list.append('EFI_FVB2_ALIGNMENT_512')
+ if (value & 0x001F0000) == 0x000A0000:
+ list.append('EFI_FVB2_ALIGNMENT_1K')
+ if (value & 0x001F0000) == 0x000B0000:
+ list.append('EFI_FVB2_ALIGNMENT_2K')
+ if (value & 0x001F0000) == 0x000C0000:
+ list.append('EFI_FVB2_ALIGNMENT_4K')
+ if (value & 0x001F0000) == 0x000D0000:
+ list.append('EFI_FVB2_ALIGNMENT_8K')
+ if (value & 0x001F0000) == 0x000E0000:
+ list.append('EFI_FVB2_ALIGNMENT_16K')
+ if (value & 0x001F0000) == 0x000F0000:
+ list.append('EFI_FVB2_ALIGNMENT_32K')
+ if (value & 0x001F0000) == 0x00100000:
+ list.append('EFI_FVB2_ALIGNMENT_64K')
+ if (value & 0x001F0000) == 0x00110000:
+ list.append('EFI_FVB2_ALIGNMENT_128K')
+ if (value & 0x001F0000) == 0x00120000:
+ list.append('EFI_FVB2_ALIGNMENT_256K')
+ if (value & 0x001F0000) == 0x00130000:
+ list.append('EFI_FVB2_ALIGNMENT_512K')
+
+ return list
+
+ def GetHeaderLength(self):
+ return list2int(self._arr.tolist()[48:50])
+
+ def Dump(self):
+ print('Signature: %s' % self.GetSigunature())
+ print('Attribute: 0x%X' % self.GetAttribute())
+ print('Header Length: 0x%X' % self.GetHeaderLength())
+ print('File system Guid: ', self.GetFileSystemGuid())
+ print('Revision: 0x%X' % self.GetRevision())
+ print('FvLength: 0x%X' % self.GetFvLength())
+
+ def GetFileSystemGuid(self):
+ list = self._arr.tolist()
+ return list2guid(list[16:32])
+
+ def GetRevision(self):
+ list = self._arr.tolist()
+ return int(list[55])
+
+ def GetFvLength(self):
+ list = self._arr.tolist()
+ return list2int(list[32:40])
+
+ def GetRawData(self):
+ return self._arr.tolist()
+
+class BlockMapEntry(BinaryItem):
+ def GetSize(self):
+ return 8
+
+ def GetNumberBlocks(self):
+ list = self._arr.tolist()
+ return list2int(list[0:4])
+
+ def GetLength(self):
+ list = self._arr.tolist()
+ return list2int(list[4:8])
+
+ def GetRawData(self):
+ return self._arr.tolist()
+
+ def __str__(self):
+ return '[BlockEntry] Number = 0x%X, length=0x%X' % (self.GetNumberBlocks(), self.GetLength())
+
+class EfiFfs(object):
+ FFS_HEADER_SIZE = 24
+
+ def __init__(self, parent=None):
+ self._header = None
+
+ # following field is for FFS in FV file.
+ self._parent = parent
+ self._offset = 0
+ self._sections = []
+
+ def Load(self, fd):
+ self._offset = align(fd.tell(), 8)
+
+ self._header = EfiFfsHeader.Read(fd, self)
+
+ if not isValidGuid(self.GetNameGuid()):
+ return
+
+ index = self._offset
+ fileend = self._offset + self.GetSize()
+ while (index + EfiSection.EFI_SECTION_HEADER_SIZE < fileend):
+ section = EfiSection(self)
+ section.Load(fd)
+ if section.GetSize() == 0 and section.GetHeader().GetType() == 0:
+ break
+ self._sections.append(section)
+ index = fd.tell()
+
+ # rebase file pointer to next ffs file
+ index = self._offset + self._header.GetFfsSize()
+ index = align(index, 8)
+ fd.seek(index)
+
+ def GetOffset(self):
+ return self._offset
+
+ def GetSize(self):
+ return self._header.GetFfsSize()
+
+ @classmethod
+ def Read(cls, fd, parent=None):
+ item = cls(parent)
+ item.Load(fd)
+ return item
+
+ def GetNameGuid(self):
+ return self._header.GetNameGuid()
+
+ def DumpContent(self):
+ list = self._content.tolist()
+ line = []
+ count = 0
+ for item in list:
+ if count < 32:
+ line.append('0x%X' % int(item))
+ count += 1
+ else:
+ print(' '.join(line))
+ count = 0
+ line = []
+ line.append('0x%X' % int(item))
+ count += 1
+
+ def GetHeader(self):
+ return self._header
+
+ def GetParent(self):
+ return self._parent
+
+ def GetSections(self):
+ return self._sections
+
+class EfiFfsHeader(BinaryItem):
+ ffs_state_map = {0x01:'EFI_FILE_HEADER_CONSTRUCTION',
+ 0x02:'EFI_FILE_HEADER_VALID',
+ 0x04:'EFI_FILE_DATA_VALID',
+ 0x08:'EFI_FILE_MARKED_FOR_UPDATE',
+ 0x10:'EFI_FILE_DELETED',
+ 0x20:'EFI_FILE_HEADER_INVALID'}
+
+ def GetSize(self):
+ return 24
+
+ def GetNameGuid(self):
+ list = self._arr.tolist()
+ return list2guid(list[0:16])
+
+ def GetType(self):
+ list = self._arr.tolist()
+ return int(list[18])
+
+
+ def GetTypeString(self):
+ value = self.GetType()
+ if value == 0x01:
+ return 'EFI_FV_FILETYPE_RAW'
+ if value == 0x02:
+ return 'EFI_FV_FILETYPE_FREEFORM'
+ if value == 0x03:
+ return 'EFI_FV_FILETYPE_SECURITY_CORE'
+ if value == 0x04:
+ return 'EFI_FV_FILETYPE_PEI_CORE'
+ if value == 0x05:
+ return 'EFI_FV_FILETYPE_DXE_CORE'
+ if value == 0x06:
+ return 'EFI_FV_FILETYPE_PEIM'
+ if value == 0x07:
+ return 'EFI_FV_FILETYPE_DRIVER'
+ if value == 0x08:
+ return 'EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER'
+ if value == 0x09:
+ return 'EFI_FV_FILETYPE_APPLICATION'
+ if value == 0x0B:
+ return 'EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE'
+ if value == 0xc0:
+ return 'EFI_FV_FILETYPE_OEM_MIN'
+ if value == 0xdf:
+ return 'EFI_FV_FILETYPE_OEM_MAX'
+ if value == 0xe0:
+ return 'EFI_FV_FILETYPE_DEBUG_MIN'
+ if value == 0xef:
+ return 'EFI_FV_FILETYPE_DEBUG_MAX'
+ if value == 0xf0:
+ return 'EFI_FV_FILETYPE_FFS_PAD'
+ if value == 0xff:
+ return 'EFI_FV_FILETYPE_FFS_MAX'
+ return 'Unknown FFS Type'
+
+ def GetAttributes(self):
+ list = self._arr.tolist()
+ return int(list[19])
+
+ def GetFfsSize(self):
+ list = self._arr.tolist()
+ return list2int(list[20:23])
+
+ def GetState(self):
+ list = self._arr.tolist()
+ state = int(list[23])
+ polarity = self.GetParent().GetParent().GetHeader().GetErasePolarity()
+ if polarity:
+ state = (~state) & 0xFF
+ HighestBit = 0x80
+ while (HighestBit != 0) and (HighestBit & state) == 0:
+ HighestBit = HighestBit >> 1
+ return HighestBit
+
+ def GetStateString(self):
+ state = self.GetState()
+ if state in self.ffs_state_map.keys():
+ return self.ffs_state_map[state]
+ return 'Unknown Ffs State'
+
+ def Dump(self):
+ print("FFS name: ", self.GetNameGuid())
+ print("FFS type: ", self.GetType())
+ print("FFS attr: 0x%X" % self.GetAttributes())
+ print("FFS size: 0x%X" % self.GetFfsSize())
+ print("FFS state: 0x%X" % self.GetState())
+
+ def GetRawData(self):
+ return self._arr.tolist()
+
+
+class EfiSection(object):
+ EFI_SECTION_HEADER_SIZE = 4
+
+ def __init__(self, parent=None):
+ self._size = 0
+ self._parent = parent
+ self._offset = 0
+ self._contents = array.array('B')
+
+ def Load(self, fd):
+ self._offset = align(fd.tell(), 4)
+
+ self._header = EfiSectionHeader.Read(fd, self)
+
+ if self._header.GetTypeString() == "EFI_SECTION_PE32":
+ pefile = pe.PEFile(self)
+ pefile.Load(fd, self.GetContentSize())
+
+ fd.seek(self._offset)
+ self._contents.fromfile(fd, self.GetContentSize())
+
+ # rebase file pointer to next section
+ index = self._offset + self.GetSize()
+ index = align(index, 4)
+ fd.seek(index)
+
+ def GetContentSize(self):
+ return self.GetSize() - self.EFI_SECTION_HEADER_SIZE
+
+ def GetContent(self):
+ return self._contents.tolist()
+
+ def GetSize(self):
+ return self._header.GetSectionSize()
+
+ def GetHeader(self):
+ return self._header
+
+ def GetSectionOffset(self):
+ return self._offset + self.EFI_SECTION_HEADER_SIZE
+
+class EfiSectionHeader(BinaryItem):
+ section_type_map = {0x01: 'EFI_SECTION_COMPRESSION',
+ 0x02: 'EFI_SECTION_GUID_DEFINED',
+ 0x10: 'EFI_SECTION_PE32',
+ 0x11: 'EFI_SECTION_PIC',
+ 0x12: 'EFI_SECTION_TE',
+ 0x13: 'EFI_SECTION_DXE_DEPEX',
+ 0x14: 'EFI_SECTION_VERSION',
+ 0x15: 'EFI_SECTION_USER_INTERFACE',
+ 0x16: 'EFI_SECTION_COMPATIBILITY16',
+ 0x17: 'EFI_SECTION_FIRMWARE_VOLUME_IMAGE',
+ 0x18: 'EFI_SECTION_FREEFORM_SUBTYPE_GUID',
+ 0x19: 'EFI_SECTION_RAW',
+ 0x1B: 'EFI_SECTION_PEI_DEPEX'}
+ def GetSize(self):
+ return 4
+
+ def GetSectionSize(self):
+ list = self._arr.tolist()
+ return list2int(list[0:3])
+
+ def GetType(self):
+ list = self._arr.tolist()
+ return int(list[3])
+
+ def GetTypeString(self):
+ type = self.GetType()
+ if type not in self.section_type_map.keys():
+ return 'Unknown Section Type'
+ return self.section_type_map[type]
+
+ def Dump(self):
+ print('size = 0x%X' % self.GetSectionSize())
+ print('type = 0x%X' % self.GetType())
+
+
+
+rMapEntry = re.compile('^(\w+)[ \(\w\)]* \(BaseAddress=([0-9a-fA-F]+), EntryPoint=([0-9a-fA-F]+), GUID=([0-9a-fA-F\-]+)')
+class EfiFvMapFile(object):
+ def __init__(self):
+ self._mapentries = {}
+
+ def Load(self, path):
+ if not os.path.exists(path):
+ return False
+
+ try:
+ file = open(path, 'r')
+ lines = file.readlines()
+ file.close()
+ except:
+ return False
+
+ for line in lines:
+ if line[0] != ' ':
+ # new entry
+ ret = rMapEntry.match(line)
+ if ret is not None:
+ name = ret.groups()[0]
+ baseaddr = int(ret.groups()[1], 16)
+ entry = int(ret.groups()[2], 16)
+ guidstr = '{' + ret.groups()[3] + '}'
+ guid = uuid.UUID(guidstr)
+ self._mapentries[guid] = EfiFvMapFileEntry(name, baseaddr, entry, guid)
+ return True
+
+ def GetEntry(self, guid):
+ if guid in self._mapentries.keys():
+ return self._mapentries[guid]
+ return None
+
+class EfiFvMapFileEntry(object):
+ def __init__(self, name, baseaddr, entry, guid):
+ self._name = name
+ self._baseaddr = baseaddr
+ self._entry = entry
+ self._guid = guid
+
+ def GetName(self):
+ return self._name
+
+ def GetBaseAddress(self):
+ return self._baseaddr
+
+ def GetEntryPoint(self):
+ return self._entry
+
+def list2guid(list):
+ val1 = list2int(list[0:4])
+ val2 = list2int(list[4:6])
+ val3 = list2int(list[6:8])
+ val4 = 0
+ for item in list[8:16]:
+ val4 = (val4 << 8) | int(item)
+
+ val = val1 << 12 * 8 | val2 << 10 * 8 | val3 << 8 * 8 | val4
+ guid = uuid.UUID(int=val)
+ return guid
+
+def list2int(list):
+ val = 0
+ for index in range(len(list) - 1, -1, -1):
+ val = (val << 8) | int(list[index])
+ return val
+
+def align(value, alignment):
+ return (value + ((alignment - value) & (alignment - 1)))
+
+gInvalidGuid = uuid.UUID(int=0xffffffffffffffffffffffffffffffff)
+def isValidGuid(guid):
+ if guid == gInvalidGuid:
+ return False
+ return True