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