├── LICENSE ├── README.md ├── requirements.txt └── siiptool ├── common ├── __init__.py ├── banner.py ├── configparser.py ├── firmware_volume.py ├── ifwi.py ├── ip_options.json ├── ip_options_sample.json ├── logger.py ├── siip_constants.py ├── subregion_descriptor.py ├── subregion_image.py ├── tools_path.py └── utilities.py ├── release.py ├── scripts ├── __init__.py ├── macgen.py ├── siip_sign.py ├── siip_stitch.py ├── subregion_capsule.py ├── subregion_fv.py └── subregion_sign.py └── thirdparty ├── Bin ├── Linux │ ├── FMMT │ ├── FmmtConf.ini │ ├── GenFfs │ ├── GenFv │ ├── GenSec │ ├── LzmaCompress │ └── rsa_helper.py └── Win32 │ ├── FMMT.exe │ ├── FmmtConf.ini │ ├── GenFfs.exe │ ├── GenFv.exe │ ├── GenSec.exe │ ├── LzmaCompress.exe │ └── rsa_helper.py └── edk2_capsule_tool ├── Common ├── Edk2 │ ├── Capsule │ │ ├── FmpPayloadHeader.py │ │ └── __init__.py │ └── __init__.py ├── Uefi │ ├── Capsule │ │ ├── FmpAuthHeader.py │ │ ├── FmpCapsuleHeader.py │ │ ├── UefiCapsuleHeader.py │ │ └── __init__.py │ └── __init__.py └── __init__.py ├── CommonDataClass ├── CommonClass.py ├── DataClass.py ├── Exceptions.py ├── FdfClass.py ├── ModuleClass.py ├── PackageClass.py ├── PlatformClass.py └── __init__.py ├── GenerateCapsule.py └── __init__.py /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, Intel Corporation 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DISCONTINUATION OF PROJECT 2 | 3 | This project will no longer be maintained by Intel. 4 | 5 | Intel has ceased development and contributions including, but not limited to, maintenance, bug fixes, new releases, or updates, to this project. 6 | 7 | Intel no longer accepts patches to this project. 8 | 9 | If you have an ongoing need to use this project, are interested in independently developing it, or would like to maintain patches for the open source software community, please create your own fork of this project. 10 | 11 | Contact: webadmin@linux.intel.com 12 | # Firmware and BIOS Utilities (FBU) 13 | 14 | The project contains command line Python scripts to stitch sub-region images to Intel FirmWare Image (IFWI) and create UEFI capsule images. Optionally, signing tool is 15 | included to generate signed sub-region image. 16 | 17 | It supports Windows 10, Ubuntu Linux, or Yocto Linux. 18 | 19 | - [Firmware and BIOS Utilities (FBU)](#firmware-and-bios-utilities-fbu) 20 | - [Guidelines for Using Signing Keys](#guidelines-for-using-signing-keys) 21 | - [Installation](#installation) 22 | - [Usage](#usage) 23 | - [Sub-region capsule tool](#sub-region-capsule-tool) 24 | - [JSON Input Format](#json-input-format) 25 | - [Certificate files](#certificate-files) 26 | - [Create capsule image](#create-capsule-image) 27 | - [Stitching tool](#stitching-tool) 28 | - [Signing tool](#signing-tool) 29 | - [License](#license) 30 | 31 | ## Guidelines for Using Signing Keys 32 | 33 | SIIP tools supports signing method using asymmetric algorithms with RSA key. The following guidelines should be followed in performing digital signatures: 34 | 35 | * RSA-3072 with hash function SHA384,512 and message formatting PSS 36 | * Use appropriately sized keys and key parameters 37 | * For Integer Factorization or Discrete Logarithm algorithms use modulus size of at least 3072 bits. 38 | * Use RSA public exponent value equal to 65537 39 | * Use approved curve for EC algorithms: NIST P-384, NIST P-521 or Ed448 40 | 41 | > **_NOTE:_** This repository does NOT provide any keys for security reasons. 42 | 43 | 44 | ## Installation 45 | 46 | * Install Python v3.6 and additional [modules](requirements.txt) 47 | 48 | ``` 49 | pip install -r requirements.txt 50 | ``` 51 | 52 | * Install openssl 53 | 54 | Manually install OpenSSL to the host and add it to the system environment variable **PATH**. 55 | 56 | Pre-compiled OpenSSL for Windows can be downloaded from [here](https://wiki.openssl.org/index.php/Binaries). You may use `apt-get` to install openssl on Ubuntu Linux. 57 | 58 | ## Usage 59 | 60 | ### Sub-region capsule tool 61 | 62 | #### JSON Input Format 63 | 64 | Input file to run sub-region capsule requires a JSON format that describes the data structure and field values to be serialized into binary format. 65 | 66 | Format of the JSON payload descriptor file: 67 | 68 | ```json 69 | { 70 | "FmpGuid": , 71 | "Version": , 72 | "FV" : 73 | { 74 | "FvGuid": , 75 | "FfsFiles": 76 | [ 77 | { 78 | "FileGuid": , 79 | "Compression": , 80 | 81 | "signingKey": , 82 | "VendorGuid": , 83 | "signerType": , 84 | 85 | "Data" : 86 | [ 87 | [, , , ], 88 | ... 89 | ] 90 | } 91 | ] 92 | } 93 | } 94 | ``` 95 | 96 | Supported `data_type` values are "DECIMAL", "HEXADECIMAL", "STRING" or "FILE". 97 | 98 | signingKey is optional, but if set VendorGuid and signerType must be set as well and then subregion will be built from Data and signed using signingKey, VendorGuid, and signerType. 99 | 100 | #### Certificate files 101 | 102 | If the signed capsule is required, you shall provide certificates from the command line. For testing purpose, they can be downloaded from [here](https://github.com/tianocore/edk2/tree/master/BaseTools/Source/Python/Pkcs7Sign). 103 | 104 | ``` 105 | TestCert.pem 106 | TestSub.pub.pem 107 | TestRoot.pub.pem 108 | ``` 109 | 110 | > **_NOTE:_** if certificate files does not match the ones built in BIOS, the capsule cannot be updated. 111 | 112 | 113 | #### Create capsule image 114 | 115 | > **_NOTE:_** JSON_FILE should be obtained from the owners of sub-region data. 116 | 117 | 118 | ```shell 119 | $ python3 subregion_capsule.py -o capsule.out.bin -s TestCert.pem -p TestSub.pub.pem -t TestRoot.pub.pem 120 | 121 | Output messages : 122 | Read binary input file ./SubRegionFv.fv 123 | FMP_PAYLOAD_HEADER.Signature = 3153534D (MSS1) 124 | FMP_PAYLOAD_HEADER.HeaderSize = 00000010 125 | FMP_PAYLOAD_HEADER.FwVersion = 00000001 126 | FMP_PAYLOAD_HEADER.LowestSupportedVersion = 00000000 127 | ... 128 | ... 129 | EFI_CAPSULE_HEADER.CapsuleImageSize = 00001B5D 130 | sizeof (Payload) = 00001B3D 131 | Write binary output file capsule.out.bin 132 | Success 133 | ``` 134 | 135 | The capsule file `capsule.out.bin` is generated and should be used as input file for [fwupdate](https://github.com/rhboot/fwupdate) tool on the target device to trigger capsule update. 136 | 137 | ### Stitching tool 138 | 139 | The stitch tool can change or merge a supported sub-region file inside a full IFWI image based on UEFI Firmware Volume format. 140 | 141 | To get a list of supported sub-regions, run: 142 | 143 | ``` 144 | $ python3 siip_stitch.py -h 145 | 146 | usage: siip_stitch [-h] -ip ipname [-k PRIVATE_KEY] [-v] [-o FileName] 147 | IFWI_IN IPNAME_IN 148 | 149 | ... 150 | ... 151 | Supported Sub-Region Names: ['pse', 'fkm', 'tmac', 'tsnip', 'tsn', 'tcc', 152 | 'oob', 'oob_rootca', 'vbt', 'gop', 'gfxpeim'] 153 | ``` 154 | 155 | To stitch a sub-region, provide the sub-region name (e.g. `pse`), IFWI image to be updated, and the sub-region file. For example: 156 | 157 | ``` 158 | $python3 siip_stitch.py -ip pse -o new.ifwi.bin ifwi.bin pse.bin 159 | 160 | ... 161 | siip_stitch INFO *** Replacing pse ... 162 | ... 163 | ... 164 | Decoding 165 | Decoding 166 | Decoding 167 | Decoding 168 | Decoding 169 | Decoding 170 | Decoding 171 | Decoding 172 | Create New FD file successfully. 173 | 174 | Done! 175 | 176 | ``` 177 | 178 | ### SIIP Signing tool 179 | 180 | The SIIP Signing tool generates security signatures and auxiliary data for a _payload_ file. When BIOS loads the payload (code or data) during boot, it verifies the payload authenticity and integrity first. 181 | 182 | For example, to sign an image with `priv3k.pem` which is a RSA-PSS private key with SHA384 hashing, run: 183 | 184 | ``` 185 | python3 siip_sign.py sign -i pse.bin -k priv3k.pem -s sha384 -m pss -o pse.signed.bin 186 | ``` 187 | 188 | The signed image (e.g. `pse.signed.bin`), is the input file to be either stitched into IFWI image, or for creating a capsule image for firmware update. 189 | 190 | > **_NOTE:_** SIIP signing tool supports only PSE firmware signing. 191 | 192 | ### Sub-region Signing tool 193 | 194 | The Sub-region Signing tool allows users to generate a signed BIOS Sub-Region before loading it into the BIOS UEFI to enhance the security of the sub-region firmware. 195 | 196 | For example, to sign a TCC sub-region provided by a vendor with the given Vendor GUID 7F6AD829-15E9-4FDE-9DD3-0548BB7F56F3 using RSA private key `signing.pem`, run: 197 | 198 | ``` 199 | python3 subregion_sign.py --name tcc --signer signing.pem --signer_type rsa 200 | --vendor-guid 7F6AD829-15E9-4FDE-9DD3-0548BB7F56F3 201 | TccConfigData_Raw.bin --output TccConfigData_signed.bin 202 | 203 | ``` 204 | 205 | > **_NOTE 1_:** Vendor GUID is specific value given by the vendor to the subregion being signed. Check BIOS implementation for the correct value. 206 | 207 | > **_NOTE 2_:** The Vendor GUID used above is a default non-production GUID for sub-region. 208 | 209 | The signed image (e.g. `TccConfigData_signed`), is the input file to be either stitched into IFWI image, or for creating a capsule image for firmware update. 210 | 211 | > **_NOTE 3_:** Sub-region signing tool only test with a TCC sub-region. The PKCS#7 signing has not been tested at this time. 212 | 213 | ## License 214 | 215 | See [LICENSE](LICENSE) for details. 216 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cryptography 2 | click -------------------------------------------------------------------------------- /siiptool/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/common/__init__.py -------------------------------------------------------------------------------- /siiptool/common/banner.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Copyright (c) 2019, Intel Corporation. All rights reserved. 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | import platform 8 | COPYRIGHT = "2020" 9 | 10 | def banner(name, ver_str, extra=""): 11 | """Create a simple header with version and host information""" 12 | 13 | print("\n" + "#" * 75) 14 | print("Intel (R) {}. Version: {}".format(name, ver_str)) 15 | print("Copyright (c) {}, Intel Corporation. All rights reserved.\n"\ 16 | .format(COPYRIGHT)) 17 | 18 | print("Running on {} with Python {}".format(platform.platform(), 19 | platform.python_version())) 20 | print("#" * 75 + "\n") 21 | print(extra) 22 | -------------------------------------------------------------------------------- /siiptool/common/configparser.py: -------------------------------------------------------------------------------- 1 | from collections.abc import MutableMapping 2 | import warnings 3 | import json 4 | from configparser import * 5 | from configparser import __all__ 6 | 7 | __all__.append("JSONConfigParser") 8 | 9 | _ConfigParser = ConfigParser 10 | 11 | 12 | class ConfigParser: 13 | """Accepts extra keyword config_type and returns the instance based on it""" 14 | def __new__(cls, *args, **kwds): 15 | config_type = kwds.pop("config_type", "ini") 16 | if config_type == "json": 17 | return JSONConfigParser() 18 | return _ConfigParser(*args, **kwds) 19 | 20 | 21 | class JSONConfigParser(MutableMapping): 22 | """A ConfigParser that works with json file.""" 23 | def __init__(self): 24 | self._dict = {} 25 | 26 | def defaults(self): 27 | raise NotImplementedError 28 | 29 | def sections(self): 30 | """Return a list of section names""" 31 | return list(self._dict) 32 | 33 | def add_section(self, section): 34 | """Create a new section in the configuration. 35 | 36 | Raise DuplicateSectionError if a section by the specified name 37 | already exists. 38 | """ 39 | if self.has_section(section): 40 | raise DuplicateSectionError(section) 41 | self._dict[section] = {} 42 | 43 | def has_section(self, section): 44 | """Indicate whether the named section is present in the configuration.""" 45 | if section in self._dict: 46 | return True 47 | return False 48 | 49 | def options(self, section): 50 | """Return a list of option names for the given section name.""" 51 | try: 52 | return list(self._dict[section]) 53 | except KeyError as e: 54 | raise NoSectionError(str(e)) from None 55 | 56 | def read(self, filenames, encoding=None): 57 | """Read and parse a filename or a list of filenames. 58 | 59 | Files that cannot be opened are silently ignored; this is 60 | designed so that you can specify a list of potential 61 | configuration file locations (e.g. current directory, user's 62 | home directory, systemwide directory), and all existing 63 | configuration files in the list will be read. A single 64 | filename may also be given. 65 | 66 | Return list of successfully read files. 67 | """ 68 | if isinstance(filenames, str): 69 | filenames = [filenames] 70 | read_ok = [] 71 | for filename in filenames: 72 | try: 73 | with open(filename, encoding=encoding) as f: 74 | self.read_file(f) 75 | except OSError: 76 | continue 77 | read_ok.append(filename) 78 | return read_ok 79 | 80 | def read_file(self, f, **kwds): 81 | """Like read() but the argument must be a file-like object. 82 | 83 | The 'f' argument must be a json document. 84 | """ 85 | dictionary = json.load(f) 86 | self.read_dict(dictionary) 87 | 88 | def read_string(self, string, **kwds): 89 | """Read configuration from a given string that contain json document.""" 90 | self._dict.update(json.loads(string)) 91 | 92 | def read_dict(self, dictionary, **kwds): 93 | """Read configuration from a dictionary.""" 94 | self._dict.update(dictionary) 95 | 96 | def readfp(self, fp, **kwds): 97 | """Deprecated, use read_file instead.""" 98 | warnings.warn( 99 | "This method will be removed in future versions. " 100 | "Use 'parser.read_file()' instead.", 101 | DeprecationWarning, stacklevel=2 102 | ) 103 | self.read_file(fp, **kwds) 104 | pass 105 | 106 | def has_option(self, section, option): 107 | """Check for the existence of a given option in a given section.""" 108 | try: 109 | if option in self._dict[section]: 110 | return True 111 | return False 112 | except KeyError as e: 113 | raise NoSectionError(str(e)) from None 114 | 115 | def set(self, section, option, value=None): 116 | """Set an option.""" 117 | self._dict[section][option] = value 118 | 119 | def write(self, fp, **kwds): 120 | """Write an .json-format representation of the configuration state.""" 121 | json.dump(self._dict, fp) 122 | 123 | def remove_option(self, section, option): 124 | """Remove an option.""" 125 | try: 126 | del(self._dict[section][option]) 127 | except KeyError as e: 128 | if str(e) == section: 129 | raise NoSectionError(section) from None 130 | else: 131 | raise NoOptionError(option) from None 132 | 133 | def remove_section(self, section): 134 | """Remove a file section.""" 135 | try: 136 | del(self._dict[section]) 137 | except KeyError: 138 | raise NoSectionError(section) from None 139 | 140 | def __getitem__(self, key): 141 | return self._dict[key] 142 | 143 | def __setitem__(self, key, value): 144 | self._dict[key] = value 145 | 146 | def __delitem__(self, key): 147 | del(self._dict[key]) 148 | 149 | def __iter__(self): 150 | return iter(self._dict) 151 | 152 | def __len__(self): 153 | return len(self._dict.keys) 154 | 155 | # These methods provided directly for campatibility with orginal ConfigParser 156 | def getint(self, section, option, **kwds): 157 | try: 158 | return int(self._dict[section][option]) 159 | except KeyError as e: 160 | error_key = str(e) 161 | if error_key == section: 162 | raise NoSectionError(error_key) from None 163 | else: 164 | raise NoOptionError(error_key) from None 165 | 166 | def getfloat(self, section, option, **kwds): 167 | try: 168 | return float(self._dict[section][option]) 169 | except KeyError as e: 170 | error_key = str(e) 171 | if error_key == section: 172 | raise NoSectionError(error_key) from None 173 | else: 174 | raise NoOptionError(error_key) from None 175 | 176 | def getboolean(self, section, option, **kwds): 177 | try: 178 | val = self._dict[section][option] 179 | if isinstance(val, bool): 180 | return val 181 | raise ValueError("value is not boolean") 182 | except KeyError as e: 183 | error_key = str(e) 184 | if error_key == section: 185 | raise NoSectionError(error_key) from None 186 | else: 187 | raise NoOptionError(error_key) from None 188 | 189 | # To do:implement for this class 190 | def optionxform(self, optionstr): 191 | raise NotImplementedError 192 | 193 | @property 194 | def converters(self): 195 | raise NotImplementedError 196 | -------------------------------------------------------------------------------- /siiptool/common/firmware_volume.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2019, Intel Corporation. All rights reserved. 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | """A simple UEFI firmware volume parser""" 8 | 9 | # import os 10 | import sys 11 | import uuid 12 | 13 | from ctypes import Structure 14 | from ctypes import c_char, c_uint32, c_uint8, c_uint64, c_uint16, sizeof, ARRAY 15 | from functools import reduce 16 | 17 | 18 | class EFI_FV_FILETYPE: 19 | ALL = 0x00 20 | RAW = 0x01 21 | FREEFORM = 0x02 22 | SECURITY_CORE = 0x03 23 | PEI_CORE = 0x04 24 | DXE_CORE = 0x05 25 | PEIM = 0x06 26 | DRIVER = 0x07 27 | COMBINED_PEIM_DRIVER = 0x08 28 | APPLICATION = 0x09 29 | SMM = 0x0A 30 | FIRMWARE_VOLUME_IMAGE = 0x0B 31 | COMBINED_SMM_DXE = 0x0C 32 | SMM_CORE = 0x0D 33 | OEM_MIN = 0xC0 34 | OEM_MAX = 0xDF 35 | DEBUG_MIN = 0xE0 36 | DEBUG_MAX = 0xEF 37 | FFS_MIN = 0xF0 38 | FFS_MAX = 0xFF 39 | FFS_PAD = 0xF0 40 | 41 | 42 | class EFI_SECTION_TYPE: 43 | """Enumeration of all valid firmware file section types.""" 44 | 45 | ALL = 0x00 46 | COMPRESSION = 0x01 47 | GUID_DEFINED = 0x02 48 | DISPOSABLE = 0x03 49 | PE32 = 0x10 50 | PIC = 0x11 51 | TE = 0x12 52 | DXE_DEPEX = 0x13 53 | VERSION = 0x14 54 | USER_INTERFACE = 0x15 55 | COMPATIBILITY16 = 0x16 56 | FIRMWARE_VOLUME_IMAGE = 0x17 57 | FREEFORM_SUBTYPE_GUID = 0x18 58 | RAW = 0x19 59 | PEI_DEPEX = 0x1B 60 | SMM_DEPEX = 0x1C 61 | 62 | 63 | def align(offset, alignment=8): 64 | return (offset + alignment - 1) & ~(alignment - 1) 65 | 66 | 67 | def bytes2val(bytes): 68 | return reduce(lambda x, y: (x << 8) | y, bytes[::-1]) 69 | 70 | 71 | def valu2bytes(value, blen): 72 | return [(value >> (i * 8) & 0xFF) for i in range(blen)] 73 | 74 | 75 | class c_uint24(Structure): 76 | """Little-Endian 24-bit Unsigned Integer""" 77 | 78 | _pack_ = 1 79 | _fields_ = [("Data", (c_uint8 * 3))] 80 | 81 | def __init__(self, val=0): 82 | self.set_value(val) 83 | 84 | def __str__(self, indent=0): 85 | return "0x%.6x" % self.value 86 | 87 | def __int__(self): 88 | return self.get_value() 89 | 90 | def set_value(self, val): 91 | self.Data[0:3] = valu2bytes(val, 3) 92 | 93 | def get_value(self): 94 | return bytes2val(self.Data[0:3]) 95 | 96 | value = property(get_value, set_value) 97 | 98 | 99 | class EFI_FIRMWARE_VOLUME_HEADER(Structure): 100 | _fields_ = [ 101 | ("ZeroVector", ARRAY(c_uint8, 16)), 102 | ("FileSystemGuid", ARRAY(c_uint8, 16)), 103 | ("FvLength", c_uint64), 104 | ("Signature", ARRAY(c_char, 4)), 105 | ("Attributes", c_uint32), 106 | ("HeaderLength", c_uint16), 107 | ("Checksum", c_uint16), 108 | ("ExtHeaderOffset", c_uint16), 109 | ("Reserved", c_uint8), 110 | ("Revision", c_uint8), 111 | ] 112 | 113 | 114 | class EFI_FIRMWARE_VOLUME_EXT_HEADER(Structure): 115 | _fields_ = [("FvName", ARRAY(c_uint8, 16)), ("ExtHeaderSize", c_uint32)] 116 | 117 | 118 | class EFI_FFS_INTEGRITY_CHECK(Structure): 119 | _fields_ = [("Header", c_uint8), ("File", c_uint8)] 120 | 121 | 122 | class EFI_FFS_FILE_HEADER(Structure): 123 | _fields_ = [ 124 | ("Name", ARRAY(c_uint8, 16)), 125 | ("IntegrityCheck", EFI_FFS_INTEGRITY_CHECK), 126 | ("Type", c_uint8), 127 | ("Attributes", c_uint8), 128 | ("Size", c_uint24), 129 | ("State", c_uint8), 130 | ] 131 | 132 | 133 | class EFI_COMMON_SECTION_HEADER(Structure): 134 | _fields_ = [("Size", c_uint24), 135 | ("Type", c_uint8)] 136 | 137 | 138 | class EFI_GUID_DEFINED_SECTION(Structure): 139 | _fields_ = [ 140 | ("SectionDefinitionGuid", ARRAY(c_uint8, 16)), 141 | ("DataOffset", c_uint16), 142 | ("Attributes", c_uint16), 143 | ("Type", c_uint8), 144 | ("Attributes", c_uint8), 145 | ] 146 | 147 | 148 | class EFI_COMPRESSED_SECTION(Structure): 149 | _fields_ = [ 150 | ("UncompressedLength", c_uint32), 151 | ("CompressionType", c_uint8), 152 | ] 153 | 154 | 155 | class VARIABLE_STORE_HEADER(Structure): 156 | _fields_ = [ 157 | ("Signature", ARRAY(c_uint8, 16)), 158 | ("Size", c_uint32), 159 | ("Format", c_uint8), 160 | ("State", c_uint8), 161 | ("Reserved", c_uint16), 162 | ("Reserved1", c_uint32), 163 | ] 164 | 165 | 166 | class FTW_HEADER(Structure): 167 | _fields_ = [ 168 | ("Signature", ARRAY(c_uint8, 16)), 169 | ("Crc", c_uint32), 170 | ("Reserved", c_uint32), 171 | ("WriteQueueSize", c_uint64), 172 | ] 173 | 174 | 175 | GUIDED_SECTION_COMPRESSED = uuid.UUID("ee4e5898-3914-4259-9d6e-dc7bd79403cf") 176 | GUIDED_SECTION_RSASHA256 = uuid.UUID("a7717414-c616-4977-9420-844712a735bf") 177 | 178 | GUID_VARIABLE_STORE_SIGNATURE = uuid.UUID("aaf32c78-947b-439a-a180-2e144ec37792") 179 | GUID_FTW_WORKING_BLOCK_SIGNATURE = uuid.UUID("9e58292b-7c68-497d-a0ce-6500fd9f1b95") 180 | GUID_MICROCODE_SIGNATURE = uuid.UUID("197DB236-F856-4924-90F8-CDF12FB875F3") 181 | GUID_FSP_INFO_HEADER = uuid.UUID("912740BE-2284-4734-B971-84B027353F0C") 182 | GUID_EMPTY = uuid.UUID("FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF") 183 | 184 | class FirmwareDevice: 185 | def __init__(self, offset, data): 186 | self.FvList = [] 187 | self.Offset = 0 188 | self.FdData = bytearray(data) 189 | 190 | def ParseFd(self): 191 | offset = 0 192 | fdsize = len(self.FdData) 193 | self.FvList = [] 194 | padding_size = 0 195 | while offset < fdsize: 196 | fvh = EFI_FIRMWARE_VOLUME_HEADER.from_buffer(self.FdData, offset) 197 | if b"_FVH" != fvh.Signature: # TODO: need more work to determine padding 198 | offset += 0x1000 # Advance 4KB 199 | padding_size += 0x1000 200 | continue 201 | if padding_size > 0: 202 | print( 203 | "WARNING: Invalid FV header signature. Possible filler data between FVs" 204 | ) 205 | fv_gap_file = PaddingFile( 206 | offset - padding_size, self.FdData[offset - padding_size : offset] 207 | ) 208 | self.FvList.append(fv_gap_file) 209 | padding_size = 0 210 | 211 | fv = FirmwareVolume(offset, self.FdData[offset : offset + fvh.FvLength]) 212 | print( 213 | "\n=== FV {} @ {:x} len:{:x} ===".format( 214 | len(self.FvList), offset, len(fv.FvData) 215 | ) 216 | ) 217 | fv.ParseFv() 218 | self.FvList.append(fv) 219 | offset += fv.FvHdr.FvLength 220 | 221 | def get_fv_index_by_guid(self, guid): 222 | """Return the index of FV within FvList, -1 if not found""" 223 | for idx, fv in enumerate(self.FvList): 224 | if isinstance(guid, bytes) and isinstance(fv, FirmwareVolume): 225 | if guid == fv.Name: 226 | return idx 227 | return -1 228 | 229 | def is_fsp_wrapper(self): 230 | for i in self.FvList: 231 | if isinstance(i, FirmwareVolume) and i.FspExists: 232 | return True 233 | return False 234 | 235 | 236 | class MiscFile: 237 | def __init__(self, name, offset, data): 238 | self.Name = name[:] 239 | self.Offset = offset 240 | self.Data = data[:] 241 | 242 | 243 | class PaddingFile: 244 | def __init__(self, offset, data): 245 | self.Offset = offset 246 | self.Data = data[:] 247 | 248 | 249 | class FirmwareVolume: 250 | def __init__(self, offset, fvdata): 251 | self.FvHdr = EFI_FIRMWARE_VOLUME_HEADER.from_buffer(fvdata, 0) 252 | self.FvData = fvdata[0 : self.FvHdr.FvLength] 253 | self.Offset = offset 254 | self.FspExists = False 255 | self.FfsList = [] 256 | if self.FvHdr.ExtHeaderOffset > 0: 257 | self.FvExtHdr = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer( 258 | self.FvData, self.FvHdr.ExtHeaderOffset 259 | ) 260 | self.Name = bytes(self.FvExtHdr.FvName) 261 | else: 262 | self.FvExtHdr = None 263 | self.Name = bytes(self.FvHdr.FileSystemGuid) 264 | 265 | def ParseFv(self): 266 | fvsize = len(self.FvData) 267 | if self.FvExtHdr: 268 | offset = self.FvHdr.ExtHeaderOffset + self.FvExtHdr.ExtHeaderSize 269 | else: 270 | offset = self.FvHdr.HeaderLength 271 | offset = align(offset) 272 | while offset < fvsize: 273 | ffshdr = EFI_FFS_FILE_HEADER.from_buffer(self.FvData, offset) 274 | ffs_name = uuid.UUID(bytes_le=bytes(ffshdr.Name)) 275 | if (ffs_name == GUID_EMPTY) and (ffshdr.Type == EFI_FV_FILETYPE.FFS_PAD): 276 | print( 277 | " Padding file (off:{:x} len:{:x})".format( 278 | offset, int(ffshdr.Size) 279 | ) 280 | ) 281 | pad_file = PaddingFile( 282 | offset, self.FvData[offset : offset + int(ffshdr.Size)] 283 | ) 284 | self.FfsList.append(pad_file) 285 | offset += int(ffshdr.Size) 286 | elif (ffs_name == GUID_EMPTY) and (int(ffshdr.Size) == 0xFFFFFF): 287 | print( 288 | " Free space (off: {:x} len: {:x})".format(offset, fvsize - offset) 289 | ) 290 | pad_file = PaddingFile(offset, self.FvData[offset:fvsize]) 291 | self.FfsList.append(pad_file) 292 | offset = fvsize 293 | elif ffs_name == GUID_VARIABLE_STORE_SIGNATURE: 294 | print(" VSS file") 295 | vsshdr = VARIABLE_STORE_HEADER.from_buffer(self.FvData, offset) 296 | vss = MiscFile( 297 | vsshdr.Signature, offset, self.FvData[offset : offset + vsshdr.Size] 298 | ) 299 | self.FfsList.append(vss) 300 | offset += vsshdr.Size 301 | elif ffs_name == GUID_FTW_WORKING_BLOCK_SIGNATURE: 302 | print(" FTW file") 303 | ftwhdr = FTW_HEADER.from_buffer(self.FvData, offset) 304 | ftw = MiscFile( 305 | ftwhdr.Signature, 306 | offset, 307 | self.FvData[ 308 | offset : offset + ftwhdr.WriteQueueSize + sizeof(FTW_HEADER) 309 | ], 310 | ) 311 | self.FfsList.append(ftw) 312 | offset += ftwhdr.WriteQueueSize + sizeof(FTW_HEADER) 313 | elif ffs_name == GUID_MICROCODE_SIGNATURE: 314 | print(" Microcode file") 315 | ucode = MiscFile( 316 | ffshdr.Name, offset, self.FvData[offset : offset + int(ffshdr.Size)] 317 | ) 318 | self.FfsList.append(ucode) 319 | offset += int(ffshdr.Size) 320 | elif ffs_name == GUID_FSP_INFO_HEADER: 321 | print(" FSP Info Header file") 322 | self.FspExists = True 323 | ffs = FirmwareFile(offset, self.FvData[offset : offset + int(ffshdr.Size)]) 324 | self.FfsList.append(ffs) 325 | offset += int(ffshdr.Size) 326 | else: 327 | print(" FFS file") 328 | ffs = FirmwareFile( 329 | offset, self.FvData[offset : offset + int(ffshdr.Size)] 330 | ) 331 | ffs.ParseFfs() 332 | self.FfsList.append(ffs) 333 | offset += int(ffshdr.Size) 334 | 335 | # Make sure 8-byte aligned 336 | offset = align(offset) 337 | 338 | 339 | class FirmwareFile: 340 | def __init__(self, offset, filedata): 341 | self.FfsHdr = EFI_FFS_FILE_HEADER.from_buffer(filedata, 0) 342 | self.FfsData = filedata[0 : int(self.FfsHdr.Size)] 343 | self.Offset = offset 344 | self.SecList = [] 345 | self.Name = self.FfsHdr.Name 346 | 347 | def ParseFfs(self): 348 | ffssize = len(self.FfsData) 349 | offset = sizeof(self.FfsHdr) 350 | if self.FfsHdr.Name != "\xff" * 16: 351 | while offset < ffssize: 352 | sechdr = EFI_COMMON_SECTION_HEADER.from_buffer(self.FfsData, offset) 353 | sec = Section(offset, self.FfsData[offset : offset + int(sechdr.Size)]) 354 | self.SecList.append(sec) 355 | offset += int(sechdr.Size) 356 | offset = align(offset, 4) 357 | 358 | 359 | class Section: 360 | def __init__(self, offset, secdata): 361 | self.SecHdr = EFI_COMMON_SECTION_HEADER.from_buffer(secdata, 0) 362 | self.SecData = secdata[0 : int(self.SecHdr.Size)] 363 | self.Offset = offset 364 | self.Type = self.SecHdr.Type 365 | if self.SecHdr.Type == EFI_SECTION_TYPE.USER_INTERFACE: 366 | self.Name = self.SecData[4:].decode("utf-16le").rstrip("\0") 367 | elif self.SecHdr.Type == EFI_SECTION_TYPE.FIRMWARE_VOLUME_IMAGE: 368 | fv_sec = EFI_FIRMWARE_VOLUME_HEADER.from_buffer( 369 | self.SecData, 370 | sizeof(EFI_COMMON_SECTION_HEADER)) 371 | self.Name = fv_sec.FileSystemGuid 372 | elif self.SecHdr.Type == EFI_SECTION_TYPE.GUID_DEFINED: 373 | guided_sec = EFI_GUID_DEFINED_SECTION.from_buffer( 374 | self.SecData, 375 | sizeof(EFI_COMMON_SECTION_HEADER)) 376 | self.Name = guided_sec.SectionDefinitionGuid 377 | else: 378 | self.Name = self.SecData[4:20] # Any data 379 | 380 | def __str__(self, indent=0): 381 | if (self.Type == EFI_SECTION_TYPE.FIRMWARE_VOLUME_IMAGE): 382 | name = uuid.UUID(bytes_le=bytes(self.Name)) 383 | name = "Volume Image ({})".format(name) 384 | elif (self.Type == EFI_SECTION_TYPE.GUID_DEFINED): 385 | name = uuid.UUID(bytes_le=bytes(self.Name)) 386 | if (name == GUIDED_SECTION_COMPRESSED): 387 | name = "LZMA Compressed".format(name) 388 | elif (name == GUIDED_SECTION_RSASHA256): 389 | name = "RSA Signed".format(name) 390 | elif (self.Type == EFI_SECTION_TYPE.USER_INTERFACE): 391 | name = self.Name 392 | elif (self.Type == EFI_SECTION_TYPE.RAW): 393 | name = "Raw Data" 394 | elif (self.Type == EFI_SECTION_TYPE.FREEFORM_SUBTYPE_GUID): 395 | name = "Free Form" 396 | else: 397 | name = "TBD" 398 | 399 | return "Type:%02x Size:%x Info:%s" % ( 400 | self.Type, 401 | len(self.SecData), 402 | name) 403 | 404 | 405 | def main(): 406 | with open(sys.argv[1], "rb") as input_fd: 407 | data = input_fd.read() 408 | fd = FirmwareDevice(0, data) 409 | fd.ParseFd() 410 | 411 | print("\nFound total {} Firmware Volumes:".format(len(fd.FvList))) 412 | for idx, fv in enumerate(fd.FvList): 413 | if isinstance(fv, PaddingFile): 414 | print("PAD%d:" % idx) 415 | print(" Offset : 0x%08X" % fv.Offset) 416 | print(" Length : 0x%08X" % len(fv.Data)) 417 | continue 418 | 419 | if not fv.FvExtHdr: 420 | name = fv.FvHdr.FileSystemGuid 421 | else: 422 | name = fv.FvExtHdr.FvName 423 | if not name: 424 | name = "\xff" * 16 425 | 426 | if sys.version_info[0] < 3: 427 | name = str(bytearray(name)) 428 | else: 429 | name = bytes(name) 430 | 431 | guid = uuid.UUID(bytes_le=name) 432 | print("\n\nFV%d:" % idx) 433 | print(" GUID : %s" % str(guid).upper()) 434 | print(" Offset : 0x%08X" % fv.Offset) 435 | print(" Length : 0x%08X" % fv.FvHdr.FvLength) 436 | for j, ffs in enumerate(fv.FfsList): 437 | if isinstance(ffs, FirmwareFile): 438 | print( 439 | " [%d] FFS (len:%x sections:%d guid:%s)" 440 | % ( 441 | j, 442 | len(ffs.FfsData), 443 | len(ffs.SecList), 444 | uuid.UUID(bytes_le=bytes(ffs.Name)), 445 | ) 446 | ) 447 | for k, sec in enumerate(ffs.SecList): 448 | print(" | SEC%d (%s)" % (k, sec)) 449 | elif isinstance(ffs, PaddingFile): 450 | print(" [%d] FREE (len:%x)" % (j, len(ffs.Data))) 451 | elif isinstance(ffs, MiscFile): 452 | print( 453 | " [%d] MISC (len:%x guid:%s)" 454 | % (j, len(ffs.Data), uuid.UUID(bytes_le=bytes(ffs.Name))) 455 | ) 456 | 457 | print("\n") 458 | 459 | 460 | if __name__ == "__main__": 461 | sys.exit(main()) 462 | -------------------------------------------------------------------------------- /siiptool/common/ifwi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2019, Intel Corporation. All rights reserved. 4 | # SPDX-License-Identifier: BSD-2-Clause 5 | # 6 | 7 | """A simple IFWI image parser""" 8 | 9 | import sys 10 | import uuid 11 | from ctypes import Structure 12 | from ctypes import c_char, c_uint32, c_uint8, c_uint64, c_uint16, sizeof, ARRAY 13 | from functools import reduce 14 | 15 | from common.firmware_volume import FirmwareDevice 16 | 17 | 18 | class SPI_DESCRIPTOR(Structure): 19 | DESC_SIGNATURE = 0x0FF0A55A 20 | FLASH_REGIONS = { 21 | "descriptor": 0x00, 22 | "bios": 0x04, 23 | "txe": 0x08, 24 | "gbe": 0x0C, 25 | "pdr": 0x10, 26 | "dev_expansion": 0x14, 27 | } 28 | _pack_ = 1 29 | _fields_ = [ 30 | ("reserved", ARRAY(c_char, 16)), 31 | ("fl_val_sig", c_uint32), 32 | ("fl_map0", c_uint32), 33 | ("fl_map1", c_uint32), 34 | ("fl_map2", c_uint32), 35 | ("remaining", ARRAY(c_char, 0x1000 - 0x20)), 36 | ] 37 | 38 | 39 | class IFWI_IMAGE: 40 | def __init__(self, filename): 41 | self.region_list = [] 42 | with open(filename, "rb") as fd: 43 | self.data = bytearray(fd.read()) 44 | self.spi_desc = SPI_DESCRIPTOR.from_buffer(self.data) 45 | 46 | def is_ifwi_image(self): 47 | return self.spi_desc.fl_val_sig == self.spi_desc.DESC_SIGNATURE 48 | 49 | def find_ifwi_region(self, rgn_name): 50 | frba = ((self.spi_desc.fl_map0 >> 16) & 0xFF) << 4 51 | fl_reg = self.spi_desc.FLASH_REGIONS[rgn_name] + frba 52 | rgn_off = c_uint32.from_buffer(self.spi_desc, fl_reg) 53 | rgn_base = (rgn_off.value & 0x7FFF) << 12 54 | rgn_limit = ((rgn_off.value & 0x7FFF0000) >> 4) | 0xFFF 55 | if rgn_limit <= rgn_base: 56 | return None, None 57 | else: 58 | return (rgn_base, rgn_limit) 59 | 60 | def parse_bios_region(self): 61 | pass 62 | 63 | def parse(self): 64 | if len(self.data) < 0x1000: 65 | return None 66 | 67 | rgn_dict = sorted( 68 | SPI_DESCRIPTOR.FLASH_REGIONS, key=SPI_DESCRIPTOR.FLASH_REGIONS.get 69 | ) 70 | for rgn in rgn_dict: 71 | rgn_start, rgn_limit = self.find_ifwi_region(rgn) 72 | if rgn_start is None: 73 | continue 74 | print( 75 | "Found region {}: off {:x} len {:x}".format( 76 | rgn, rgn_start, rgn_limit + 1 - rgn_start 77 | ) 78 | ) 79 | self.region_list.append((rgn, rgn_start, rgn_limit)) 80 | 81 | 82 | def main(): 83 | 84 | # Sample code 85 | ifwi = IFWI_IMAGE(sys.argv[1]) 86 | if not ifwi.is_ifwi_image(): 87 | print("Bad IFWI image") 88 | exit(1) 89 | 90 | ifwi.parse() 91 | bios_start = ifwi.region_list[1][1] 92 | bios_limit = ifwi.region_list[1][2] 93 | 94 | print("Parsing BIOS ...") 95 | bios = FirmwareDevice(0, ifwi.data[bios_start : bios_limit + 1]) 96 | bios.ParseFd() 97 | 98 | 99 | if __name__ == "__main__": 100 | sys.exit(main()) 101 | -------------------------------------------------------------------------------- /siiptool/common/ip_options.json: -------------------------------------------------------------------------------- 1 | { 2 | "pse": 3 | [ 4 | ["ui", "IntelPseFw"], 5 | ["raw", "PI_NONE"], 6 | [null], 7 | ["lzma", "-e"], 8 | ["guid", "EE4E5898-3914-4259-9D6E-DC7BD79403CF", "PROCESSING_REQUIRED"], 9 | ["free", "EBA4A247-42C0-4C11-A167-A4058BC9D423", "1K"] 10 | ], 11 | "fkm": 12 | [ 13 | ["ui", "SiipFkm"], 14 | ["raw", "PI_NONE"], 15 | [null], 16 | ["lzma", "-e"], 17 | ["guid", "EE4E5898-3914-4259-9D6E-DC7BD79403CF", "PROCESSING_REQUIRED"], 18 | ["free", "8AFFBA0F-C312-4717-9DD5-6AB1FE5FCB47", "1K"] 19 | ], 20 | "tmac": 21 | [ 22 | ["ui", "IntelFvTsnMacAddr"], 23 | ["raw", "PI_NONE"], 24 | [null], 25 | ["free", "12E29FB4-AA56-4172-B34E-DD5F4B440AA9", null] 26 | ], 27 | "tsnip": 28 | [ 29 | ["ui", "IntelPseTsnIpConfig"], 30 | ["raw", "PI_NONE"], 31 | [null], 32 | ["free", "40BD5BCD-094F-43B3-8D8D-1D72F850C3CB", null] 33 | ], 34 | "tsn": 35 | [ 36 | ["ui", "IntelTsnConfig"], 37 | ["raw", "PI_NONE"], 38 | [null], 39 | ["free", "4FB7994D-D878-4BD1-8FE0-777B732D0A31", null] 40 | ], 41 | "tcc": 42 | [ 43 | ["ui", "IntelTccConfig"], 44 | ["raw", "PI_NONE"], 45 | [null], 46 | ["free", "7F6AD829-15E9-4FDE-9DD3-0548BB7F56F3", null] 47 | ], 48 | "tccs": 49 | [ 50 | ["ui", "IntelFvTccStreamCfg"], 51 | ["raw", "PI_NONE"], 52 | [null], 53 | ["free", "7F6AD829-15E9-4FDE-9DD3-0548BB7F56F3", null] 54 | ], 55 | "tccc": 56 | [ 57 | ["ui", "IntelFvTccCacheCfg"], 58 | ["raw", "PI_NONE"], 59 | [null], 60 | ["free", "0C1A77B3-FD36-46F9-8AD0-598367053641", null] 61 | ], 62 | "tccb": 63 | [ 64 | ["ui", "IntelFvTccBuffer"], 65 | ["raw", "PI_NONE"], 66 | [null], 67 | ["free", "F20527A7-B7B0-4630-A6BD-ED10CD48B94F", null] 68 | ], 69 | "tccp": 70 | [ 71 | ["ui", "IntelFvPtcmBinary"], 72 | ["raw", "PI_NONE"], 73 | [null], 74 | ["lzma", "-e"], 75 | ["guid", "EE4E5898-3914-4259-9D6E-DC7BD79403CF", "PROCESSING_REQUIRED"], 76 | ["free", "0240AD7B-00DA-43AF-9ED4-73B8DF48CD0B", null] 77 | ], 78 | "tcrl": 79 | [ 80 | ["ui", "IntelFvTccCrlBinary"], 81 | ["raw", "PI_NONE"], 82 | [null], 83 | ["lzma", "-e"], 84 | ["guid", "EE4E5898-3914-4259-9D6E-DC7BD79403CF", "PROCESSING_REQUIRED"], 85 | ["free", "0240AD7B-00DA-43AF-9ED4-73B8DF48CD0B", null] 86 | ], 87 | "oob": 88 | [ 89 | ["ui", "IntelOobConfig"], 90 | ["raw", "PI_NONE"], 91 | [null], 92 | ["free", "4DB2A373-C936-4544-AA6D-8A194AA9CA7F", null] 93 | ], 94 | "oob_rootca": 95 | [ 96 | ["ui", "IntelOobRootCA"], 97 | ["raw", "PI_NONE"], 98 | [null], 99 | ["free", "2F4DE35A-0D52-44FC-ABF3-75B8AA51F434", null] 100 | ], 101 | "vbt": 102 | [ 103 | ["ui", "IntelGopVbt"], 104 | ["raw", "PI_NONE"], 105 | [null], 106 | ["free", "56752da9-de6b-4895-8819-1945b6b76c22", null] 107 | ], 108 | "obbpei_digest": 109 | [ 110 | ["ui", "ObbPeiDigest"], 111 | ["raw", "PI_NONE"], 112 | [null], 113 | ["free", "F57757FC-2603-404F-AAE2-34C6232388E8", null] 114 | ], 115 | "obbdxe_digest": 116 | [ 117 | ["ui", "ObbDxeDigest"], 118 | ["raw", "PI_NONE"], 119 | [null], 120 | ["free", "32198477-7337-40E4-897D-BC33F018B42F", null] 121 | ], 122 | "gop": 123 | [ 124 | ["ui", "IntelGopDriver"], 125 | ["pe32", null], 126 | [null], 127 | ["dxe", "FF0C8745-3270-4439-B74F-3E45F8C77064", null] 128 | ], 129 | "gfxpeim": 130 | [ 131 | ["ui", "IntelGraphicsPeim"], 132 | ["pe32", null], 133 | [null, "32", "1"], 134 | ["cmprs", "PI_STD"], 135 | ["peim", "76ED893A-B2F9-4C7D-A05F-1EA170ECF6CD", null] 136 | ], 137 | "isi": 138 | [ 139 | ["ui", "IntelIsiConfig"], 140 | ["raw", "PI_NONE"], 141 | [null], 142 | ["free", "6714A5AD-024D-42E0-883A-2FBD0A311C24", null] 143 | ], 144 | "undi": 145 | [ 146 | ["ui", "IntelGbeUndi"], 147 | ["pe32", null], 148 | [null], 149 | ["dxe", "720E6687-43C4-84EA-E1B5-23AAED359840", null] 150 | ] 151 | } 152 | -------------------------------------------------------------------------------- /siiptool/common/ip_options_sample.json: -------------------------------------------------------------------------------- 1 | [ 2 | "": [ 3 | ["ui", ""], # UI name, must be the first section 4 | ["raw", ""], # creates EFI_SECTION_RAW 5 | # Type: Compress method type can be PI_NONE or PI_STD. 6 | ["lzma", "-e"], # Compressed section, optional 7 | # "-e": compress, "-d": decompress 8 | ["||", "", "FileAlign"], # Firmware file system type 9 | # free: EFI_FV_FILETYPE_FREEFORM 10 | # dxe: EFI_FV_FILETYPE_DRIVER 11 | # peim: EFI_FV_FILETYPE_PEIM 12 | # FileGuid: is one module guid, 13 | # Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 14 | # FileAlign points to file alignment 15 | # [None|2|4|8|16|128|512|1K|4K|32K|64K] 16 | ["None", ""] # Generates the all section 17 | # SectionAlign points to section alignment, 18 | # which support the alignment scope 1~64K. 19 | ["guid", "", ""], # Generates the GUID defined section 20 | # GuidValue is one specific vendor guid value. 21 | # Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 22 | # GuidAttr is guid section atttributes, which may be 23 | # PROCESSING_REQUIRED, AUTH_STATUS_VALID and NONE. 24 | ["pe32", "None"], # Creates EFI_SECTION_PE32 25 | ["cmprs", ""], # Creates EFI_SECTION_COMPRESSION 26 | # Type: Compress method type can be PI_NONE or PI_STD. 27 | ["depex", "None"] # Creates EFI_SECTION_PEI_DEPEX 28 | 29 | ] 30 | ] 31 | -------------------------------------------------------------------------------- /siiptool/common/logger.py: -------------------------------------------------------------------------------- 1 | from logging import * 2 | import logging.config as config 3 | import logging.handlers as handlers 4 | from click import style, echo 5 | from logging import __all__ 6 | 7 | __all__.extend(["SUCCESS", "success", "ClickHandler", "SuppressExceptionFormatter"]) 8 | 9 | # adding a new level SUCCESS 10 | SUCCESS = 25 11 | addLevelName(SUCCESS, "SUCCESS") 12 | 13 | def success(self, msg, *args, **kwargs): 14 | """ 15 | Log 'msg % args' with level 'SUCCESS'. 16 | """ 17 | if self.isEnabledFor(SUCCESS): 18 | self._log(SUCCESS, msg, args, **kwargs) 19 | 20 | Logger.success = success 21 | 22 | 23 | class ClickHandler(StreamHandler): 24 | '''This class colors the console output''' 25 | 26 | def __init__(self, stream=None, levelcolor={}): 27 | super().__init__(stream) 28 | self.levelcolor = levelcolor 29 | 30 | def emit(self, record): 31 | """ 32 | Emit a record. 33 | 34 | If a formatter is specified, it is used to format the record. 35 | The record is then written to console using click.echo(). Foregorund 36 | color is chosen according to level and set using click.style(msg, fg). 37 | """ 38 | try: 39 | msg = self.format(record) 40 | # fg = self._LEVELCOLOR[record.levelno] 41 | fg = self.levelcolor.get(record.levelname, None) 42 | echo(style(msg, fg=fg)) 43 | except Exception: 44 | self.handleError(record) 45 | 46 | 47 | class SuppressExceptionFormatter(Formatter): 48 | '''Supresses the Traceback of error''' 49 | def format(self, record): 50 | """ 51 | Format the specified record as text. 52 | 53 | The record's attribute dictionary is used as the operand to a 54 | string formatting operation which yields the returned string. 55 | Before formatting the dictionary, a couple of preparatory steps 56 | are carried out. The message attribute of the record is computed 57 | using LogRecord.getMessage(). If the formatting string uses the 58 | time (as determined by a call to usesTime(), formatTime() is 59 | called to format the event time. If there is exception information, 60 | it is discarded. 61 | """ 62 | record.message = record.getMessage() 63 | if self.usesTime(): 64 | record.asctime = self.formatTime(record, self.datefmt) 65 | s = self.formatMessage(record) 66 | return s 67 | 68 | 69 | _getLogger = getLogger 70 | 71 | logging_default_cfg = { 72 | "version": 1, 73 | "disable_existing_loggers": True, 74 | "formatters": { 75 | "default": { 76 | "format": "%(name)s %(levelname)s %(message)s" 77 | } 78 | }, 79 | "handlers": { 80 | "console": { 81 | "class": "common.logger.StreamHandler", 82 | "level": "DEBUG", 83 | "formatter": "default" 84 | }, 85 | }, 86 | "root": {"handlers": ["console"], "level": "DEBUG"} 87 | } 88 | 89 | def getLogger(name, *, logging_cfg=logging_default_cfg): 90 | if logging_cfg: 91 | config.dictConfig(logging_cfg) 92 | logger = _getLogger(name) 93 | return logger 94 | -------------------------------------------------------------------------------- /siiptool/common/siip_constants.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2019, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | """ Tool Version Number """ 9 | 10 | VERSION = "0.8.2" 11 | 12 | """Sub-region configuration for different types of code/data 13 | """ 14 | 15 | 16 | GUID_DEFINED_LZMA = "EE4E5898-3914-4259-9D6E-DC7BD79403CF" 17 | -------------------------------------------------------------------------------- /siiptool/common/subregion_descriptor.py: -------------------------------------------------------------------------------- 1 | # @file 2 | # Descriptor definition for BIOS Sub Regions 3 | # 4 | # Copyright (c) 2019, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | import json 9 | import uuid 10 | import os 11 | 12 | FMP_CAPSULE_TSN_MAC_ADDRESS_FILE_GUID = uuid.UUID("6fee88ff-49ed-48f1-b77b-ead15771abe7") 13 | FMP_CAPSULE_TSN_IP_CONFIG_FILE_GUID = uuid.UUID("697f0ea1-b630-4b93-9b08-eaffc5d5fc45") 14 | FMP_CAPSULE_PSE_TSN_MAC_CONFIG_FILE_GUID = uuid.UUID("90c9751d-fa74-4ea6-8c4b-f44d2be8cd4b") 15 | FMP_CAPSULE_PSE_FW_FILE_GUID = uuid.UUID("aad1e926-23b8-4c3a-8b44-0c9a031664f2") 16 | FMP_CAPSULE_PSE_FKM_FILE_GUID = uuid.UUID("4789B506-5E9A-4C0F-8646-8BE99E87D766") 17 | FMP_CAPSULE_TCC_ARB_FILE_GUID = uuid.UUID("a7ee90b1-fb4a-4478-b868-367ee9ec97e2") 18 | FMP_CAPSULE_OOB_MANAGEABILITY_FILE_GUID = uuid.UUID("bf2ae378-01e0-4605-9e3b-2ee2fc7339de") 19 | FMP_CAPSULE_TCC_STREAM = uuid.UUID("BF2AE378-01E0-4605-9E3B-2EE2FC7339DE") 20 | FMP_CAPSULE_TCC_CONFIG = uuid.UUID("9A069A23-836F-41DF-AF02-F14BEC97DE72") 21 | FMP_CAPSULE_TCC_BUFF = uuid.UUID("3A6F667B-CED4-481B-8FC3-C087A0F2DD53") 22 | FMP_CAPSULE_TCC_PTCMB = uuid.UUID("B0D0314D-57C3-4453-9486-18822D8C81BA") 23 | FMP_CAPSULE_ISI_CONFIG = uuid.UUID("F5098FFB-0B47-4619-8D29-2550836E085A") 24 | 25 | class EnumDataTypes(set): 26 | def __getattr__(self, name): 27 | if name in self: 28 | return name 29 | raise AttributeError 30 | 31 | 32 | data_types = EnumDataTypes(["DECIMAL", "HEXADECIMAL", "STRING", "FILE"]) 33 | 34 | 35 | class UnknownSubRegionError(Exception): 36 | def __init__(self): 37 | pass 38 | 39 | def __str__(self): 40 | return repr("Sub Region is unknown.") 41 | 42 | 43 | class SubRegionDescSyntaxError(Exception): 44 | def __init__(self, key): 45 | self.key = key 46 | pass 47 | 48 | def __str__(self): 49 | return repr( 50 | "Sub Region descriptor invalid syntax. Problem with {} field in " 51 | "JSON file.".format(self.key) 52 | ) 53 | 54 | 55 | class SubRegionFfsFile(object): 56 | def __init__(self, ffs_guid, data, 57 | signing_key = None, vendor_guid = None, signer_type = 'rsa'): 58 | self.s_ffs_guid = ffs_guid 59 | try: 60 | self.ffs_guid = uuid.UUID(self.s_ffs_guid) 61 | except ValueError: 62 | raise SubRegionDescSyntaxError("ffs_guid") 63 | self.ffs_guid = ffs_guid 64 | self.data = [] 65 | self.signing_key = signing_key 66 | self.vendor_guid = vendor_guid 67 | self.signer_type = signer_type 68 | for data_field in data: 69 | self.data.append(SubRegionDataField(data_field)) 70 | 71 | 72 | class SubRegionDataField(object): 73 | def __init__(self, data_field): 74 | self.name = data_field[0] 75 | self.Type = data_field[1] 76 | self.ByteSize = data_field[2] 77 | self.Value = data_field[3] 78 | if self.Type == data_types.DECIMAL: 79 | if data_field[3] is not None: 80 | self.dValue = int(data_field[3]) 81 | self.sValue = str(data_field[3]) 82 | elif self.Type == data_types.HEXADECIMAL: 83 | if data_field[3] is not None: 84 | self.sValue = str(data_field[3]) 85 | self.dValue = int(self.sValue, 16) 86 | else: 87 | self.dValue = None 88 | self.sValue = str(data_field[3]) 89 | 90 | 91 | class SubRegionDescriptor(object): 92 | ValidGuidList = [ 93 | FMP_CAPSULE_TSN_MAC_ADDRESS_FILE_GUID, 94 | FMP_CAPSULE_PSE_TSN_MAC_CONFIG_FILE_GUID, 95 | FMP_CAPSULE_PSE_FW_FILE_GUID, 96 | FMP_CAPSULE_PSE_FKM_FILE_GUID, 97 | FMP_CAPSULE_TCC_ARB_FILE_GUID, 98 | FMP_CAPSULE_OOB_MANAGEABILITY_FILE_GUID, 99 | FMP_CAPSULE_TSN_IP_CONFIG_FILE_GUID, 100 | FMP_CAPSULE_TCC_STREAM, 101 | FMP_CAPSULE_TCC_CONFIG, 102 | FMP_CAPSULE_TCC_BUFF, 103 | FMP_CAPSULE_TCC_PTCMB, 104 | FMP_CAPSULE_ISI_CONFIG, 105 | ] 106 | 107 | def __init__(self): 108 | self.s_fmp_guid = None 109 | self.fmp_guid = None 110 | self.version = None 111 | self.fv = None 112 | self.s_fv_guid = None 113 | self.fv_guid = None 114 | self.s_fv_block_size = None 115 | self.s_fv_num_block = None 116 | self.ffs_files = [] 117 | self.signer_prv_cert_file = None 118 | self.other_pub_cert_file = None 119 | self.trusted_pub_cert_file = None 120 | 121 | def parse_json_data(self, json_file): 122 | with open(json_file, "r") as file_handle: 123 | desc_buffer = json.loads(file_handle.read()) 124 | try: 125 | json_dir = os.path.dirname(os.path.abspath(json_file)) 126 | self.s_fmp_guid = desc_buffer["FmpGuid"] 127 | try: 128 | self.fmp_guid = uuid.UUID(self.s_fmp_guid) 129 | if not self.is_known_guid(self.fmp_guid): 130 | raise UnknownSubRegionError 131 | except ValueError: 132 | raise SubRegionDescSyntaxError("FmpGuid") 133 | self.version = desc_buffer["Version"] 134 | 135 | if "OpenSSLSignerPrivateCertFile" in desc_buffer: 136 | self.signer_prv_cert_file = desc_buffer["OpenSSLSignerPrivateCertFile"] 137 | if not os.path.isabs(self.signer_prv_cert_file): 138 | self.signer_prv_cert_file = os.path.join(json_dir, self.signer_prv_cert_file) 139 | if "OpenSSLOtherPublicCertFile" in desc_buffer: 140 | self.other_pub_cert_file = desc_buffer["OpenSSLOtherPublicCertFile"] 141 | if not os.path.isabs(self.other_pub_cert_file): 142 | self.other_pub_cert_file = os.path.join(json_dir, self.other_pub_cert_file) 143 | if "OpenSSLTrustedPublicCertFile" in desc_buffer: 144 | self.trusted_pub_cert_file = desc_buffer["OpenSSLTrustedPublicCertFile"] 145 | if not os.path.isabs(self.trusted_pub_cert_file): 146 | self.trusted_pub_cert_file = os.path.join(json_dir, self.trusted_pub_cert_file) 147 | 148 | self.fv = desc_buffer["FV"] 149 | self.s_fv_guid = self.fv["FvGuid"] 150 | if "FvBlockSize" in self.fv: 151 | self.s_fv_block_size = self.fv["FvBlockSize"] 152 | if "FvNumBlock" in self.fv: 153 | self.s_fv_num_block = self.fv["FvNumBlock"] 154 | 155 | try: 156 | self.fv_guid = uuid.UUID(self.s_fv_guid) 157 | except ValueError: 158 | raise SubRegionDescSyntaxError("FvGuid") 159 | except TypeError: 160 | raise SubRegionDescSyntaxError("FvGuid") 161 | 162 | ffs_file_list = self.fv["FfsFiles"] 163 | for ffs_file in ffs_file_list: 164 | ffs_guid = ffs_file["FileGuid"] 165 | data = ffs_file["Data"] 166 | if "SigningKey" in ffs_file: 167 | signing_key = ffs_file["SigningKey"] 168 | if not os.path.isabs(signing_key): 169 | signing_key = os.path.join(json_dir, signing_key) 170 | vendor_guid = ffs_file["VendorGuid"] 171 | signer_type = ffs_file["SignerType"] 172 | self.ffs_files.append( 173 | SubRegionFfsFile(ffs_guid, data, 174 | signing_key, vendor_guid, signer_type) 175 | ) 176 | else: 177 | self.ffs_files.append(SubRegionFfsFile(ffs_guid, data)) 178 | 179 | for ffs_file in self.ffs_files: 180 | if not self.check_file_good(ffs_file): 181 | raise SubRegionDescSyntaxError("FfsFile") 182 | except (KeyError, IndexError) as e: 183 | raise SubRegionDescSyntaxError(str(e)) 184 | 185 | def check_file_good(self, ffs_file): 186 | valid_file = True 187 | 188 | for data_field in ffs_file.data: 189 | if type(data_field.name) not in [str]: 190 | valid_file = False 191 | if data_field.Type not in data_types: 192 | valid_file = False 193 | if data_field.ByteSize < 0: 194 | valid_file = False 195 | if type(data_field.Value) not in [str, int]: 196 | valid_file = False 197 | 198 | return valid_file 199 | 200 | def is_known_guid(self, guid): 201 | return guid in self.ValidGuidList 202 | -------------------------------------------------------------------------------- /siiptool/common/subregion_image.py: -------------------------------------------------------------------------------- 1 | # @file 2 | # Converts Sub Regions JSON into binary image 3 | # 4 | # Copyright (c) 2019, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | from io import open 8 | import json 9 | import os 10 | import struct 11 | import sys 12 | 13 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 14 | 15 | from common import subregion_descriptor as subrgn_descptr 16 | from common.utilities import get_key_and_value 17 | from common.tools_path import GENFV, GENFFS, GENSEC, LZCOMPRESS, IP_OPTIONS_CFG 18 | 19 | ############################################################################## 20 | # 21 | # Gets the options needed to create commands to replace the ip 22 | # 23 | # The Each List represents a command that needs to be created to replace the 24 | # given IP 25 | # The following list is for GenSec.exe 26 | # 'ui' creates EFI_SECTION_USER_INTERFACE 27 | # 'raw' creates EFI_SECTION_RAW 28 | # None creaetes EFI_SECTION_ALL that does not require a section header 29 | # 'guid' creates EFI_SECTION_GUID_DEFINED 30 | # 'pe32' creates EFI_SECTION_PE32 31 | # 'depex' creates EFI_SECTION_PEI_DEPEX 32 | # 'cmprs' creates EFI_SECTION_COMPRESSION 33 | # 34 | # 'lzma' calls the LzmaCompress 35 | # 36 | # The following list is for GenFfs.exe 37 | # 'free' creates EFI_FV_FILETYPE_FREEFORM 38 | # 'gop' creates EFI_FV_FILETYPE_DRIVER 39 | # 'peim' creates EFI_FV_FILETYPE_PEIM 40 | ############################################################################## 41 | # gets the section type needed for gensec.exe 42 | GENSEC_SECTION = { 43 | "ui": ["tmp.ui", "-s", "EFI_SECTION_USER_INTERFACE", "-n"], 44 | "raw": ["tmp.raw", "-s", "EFI_SECTION_RAW", "-c"], 45 | "guid": ["tmp.guid", "-s", "EFI_SECTION_GUID_DEFINED", "-g"], 46 | "pe32": ["tmp.pe32", "-s", "EFI_SECTION_PE32"], 47 | "depex": ["tmp.dpx", "-s", "EFI_SECTION_PEI_DEPEX"], 48 | "cmprs": ["tmp.cmps", "-s", "EFI_SECTION_COMPRESSION", "-c"] 49 | } 50 | 51 | # gets the firmware file system type needed for genFFs 52 | FFS_FILETYPE = { 53 | "free": "EFI_FV_FILETYPE_FREEFORM", 54 | "dxe": "EFI_FV_FILETYPE_DRIVER", 55 | "peim": "EFI_FV_FILETYPE_PEIM", 56 | } 57 | 58 | with open(IP_OPTIONS_CFG) as ip_options_config_file: 59 | ip_options = json.load(ip_options_config_file) 60 | 61 | # Translate IP_OPTIONS dict into a GUID-to-NAME lookup dict 62 | section_name_lookup_table = { 63 | option[-1][1]: option[0][1] for option in ip_options.values()} 64 | 65 | 66 | def ip_info_from_guid(lookup_val): 67 | """ returns the key and corresponding value """ 68 | return get_key_and_value(ip_options, lookup_val, [-1, 1]) 69 | 70 | 71 | def guid_section(sec_type, guid, guid_attrib, inputfile): 72 | """ generates the GUID defined section """ 73 | cmd = ["tmp.guid", "-s", "EFI_SECTION_GUID_DEFINED", "-g"] 74 | cmd += [guid, "-r", guid_attrib, inputfile] 75 | return cmd 76 | 77 | 78 | def generate_section(inputfiles, align_sizes): 79 | """ generates the all section """ 80 | 81 | cmd = ["tmp.all"] 82 | 83 | for index, file in enumerate(inputfiles): 84 | cmd += [file] 85 | if align_sizes != [None]: 86 | # the first input is None 87 | cmd += ["--sectionalign", align_sizes[index + 1]] 88 | return cmd 89 | 90 | 91 | def create_gensec_cmd(cmd_options, inputfile): 92 | """Create genSec commands for the merge and replace of firmware section.""" 93 | 94 | cmd = [GENSEC, "-o"] 95 | 96 | if cmd_options[0] == "guid": 97 | sec_type, guid, attrib = cmd_options 98 | cmd += guid_section(sec_type, guid, attrib, inputfile[0]) 99 | # EFI_SECTION_RAW, EFI_SECTION_PE32, EFI_SECTION_COMPRESSION or 100 | # EFI_SECTION_USER_INTERFACE 101 | elif cmd_options[0] is not None: 102 | sec_type, option = cmd_options 103 | cmd += GENSEC_SECTION.get(sec_type) 104 | if option is not None: 105 | cmd += [option] 106 | if sec_type != "ui": 107 | cmd += [inputfile[0]] 108 | else: 109 | cmd += generate_section(inputfile, cmd_options) 110 | return cmd 111 | 112 | 113 | def compress(compress_method, inputfile): 114 | """ compress the sections """ 115 | 116 | cmd = [LZCOMPRESS, compress_method, "-o", "tmp.cmps", inputfile] 117 | return cmd 118 | 119 | 120 | def create_ffs_cmd(filetype, guild, align, inputfile): 121 | """ generates the firmware volume according to file type""" 122 | 123 | fv_filetype = FFS_FILETYPE.get(filetype) 124 | cmd = [GENFFS, "-o", "tmp.ffs", "-t", fv_filetype, "-g", 125 | guild, "-i", inputfile] 126 | if align is not None: 127 | cmd += ["-a", align] 128 | return cmd 129 | 130 | 131 | def ip_inputfiles(filenames, ipname): 132 | """Create input files per IP""" 133 | 134 | inputfiles = [None, "tmp.raw", "tmp.ui", "tmp.all"] 135 | 136 | num_infiles = 1 137 | if ipname in ["pse", "fkm", "tccp"]: 138 | inputfiles.extend(["tmp.cmps", "tmp.guid"]) 139 | elif ipname in ["gop", "gfxpeim", "undi"]: 140 | inputfiles.remove("tmp.raw") 141 | inputfiles.insert(1, "tmp.pe32") 142 | if ipname == "gfxpeim": 143 | inputfiles.append("tmp.cmps") 144 | 145 | # add user given input files 146 | infiles = filenames[1:num_infiles + 1] 147 | inputfiles[1:1] = infiles 148 | 149 | return inputfiles, num_infiles 150 | 151 | 152 | def build_command_list(build_list, inputfiles, num_replace_files): 153 | """ Builds command list for firmware files system """ 154 | 155 | cmd_list = [] 156 | 157 | for instr in build_list: 158 | if GENSEC_SECTION.get(instr[0]) or instr[0] is None: 159 | files = [inputfiles.pop(0)] 160 | if instr[0] is None: 161 | for _ in range(num_replace_files): 162 | files += [inputfiles.pop(0)] 163 | cmd = create_gensec_cmd(instr, files) 164 | elif instr[0] == "lzma": 165 | cmd = compress(instr[1], inputfiles.pop(0)) 166 | elif FFS_FILETYPE.get(instr[0]): 167 | filetype, guild, align = instr 168 | cmd = create_ffs_cmd(filetype, guild, align, inputfiles.pop(0)) 169 | else: 170 | sys.exit("unexpected error from create_command function") 171 | 172 | cmd_list.append(cmd) 173 | 174 | return cmd_list 175 | 176 | 177 | def build_fv_from_ffs_files(sub_region_desc, out_file, ffs_file_list): 178 | """ Build FV file with multi firmware file syste """ 179 | 180 | fv_cmd_list = [] 181 | for file_index, file in enumerate(ffs_file_list): 182 | if file_index > 0: 183 | # Use other files just add with file input option in the same command; 184 | fv_cmd += ["-f", file] 185 | else: 186 | fv_cmd = create_gen_fv_command(sub_region_desc.s_fv_guid, out_file, file, 187 | block_size=sub_region_desc.s_fv_block_size, num_block=sub_region_desc.s_fv_num_block) 188 | 189 | fv_cmd_list.append(fv_cmd) 190 | 191 | return fv_cmd_list 192 | 193 | 194 | def create_gen_fv_command(fv_guid, output_fv_file, ffs_file, 195 | input_fv_file=None, block_size = None, num_block = None): 196 | gen_fv_cmd = [GENFV] 197 | if input_fv_file is not None: 198 | gen_fv_cmd += ["-i", input_fv_file] 199 | gen_fv_cmd += ["-o", output_fv_file] 200 | if block_size is None: 201 | gen_fv_cmd += ["-b", "0x1000"] 202 | else: 203 | gen_fv_cmd += ["-b", block_size] 204 | if num_block is not None: 205 | gen_fv_cmd += ["-n", num_block] 206 | gen_fv_cmd += ["-f", ffs_file] 207 | gen_fv_cmd += [ 208 | "-g", 209 | "8C8CE578-8A3D-4F1C-9935-896185C32DD3", 210 | ] # gEfiFirmwareFileSystem2Guid 211 | gen_fv_cmd += ["--FvNameGuid", fv_guid] 212 | return gen_fv_cmd 213 | 214 | 215 | def create_buffer_from_data_field(data_field): 216 | buffer = None 217 | if data_field.Type == subrgn_descptr.data_types.FILE: 218 | if data_field.ByteSize == 0: # Read the whole file 219 | with open(data_field.Value, "rb") as DataFile: 220 | buffer = DataFile.read() 221 | else: 222 | buffer = bytearray(data_field.ByteSize) # Allocate the buffer 223 | with open(data_field.Value, "rb") as DataFile: 224 | tmp = DataFile.read(data_field.ByteSize) 225 | buffer[:len(tmp)] = tmp # copy data to the beginning of the buffer 226 | 227 | if data_field.Type == subrgn_descptr.data_types.STRING: 228 | fmt = "{}s".format(data_field.ByteSize) 229 | if data_field.Value == "_STDIN_": 230 | buffer = struct.pack(fmt, bytes(sys.stdin.readline(), "utf-8")) 231 | else: 232 | buffer = struct.pack(fmt, bytes(data_field.sValue, "utf-8")) 233 | 234 | if data_field.Type in [subrgn_descptr.data_types.DECIMAL, 235 | subrgn_descptr.data_types.HEXADECIMAL]: 236 | buffer = data_field.dValue.to_bytes(data_field.ByteSize, "little") 237 | 238 | return buffer 239 | 240 | 241 | def generate_sub_region_image(ffs_file, output_file="./output.bin"): 242 | with open(output_file, "wb") as out_buffer: 243 | for data_field in ffs_file.data: 244 | line_buffer = create_buffer_from_data_field(data_field) 245 | out_buffer.write(line_buffer) 246 | 247 | 248 | if __name__ == "__main__": 249 | 250 | if len(sys.argv) != 3: 251 | print("Usage: script ") 252 | sys.exit(2) 253 | 254 | json_file = sys.argv[1] 255 | outfile = sys.argv[2] 256 | desc = subrgn_descptr.SubRegionDescriptor() 257 | desc.parse_json_data(json_file) 258 | 259 | # Currently only creates the first file 260 | generate_sub_region_image(desc.ffs_files[0], output_file=outfile) 261 | -------------------------------------------------------------------------------- /siiptool/common/tools_path.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2019, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | import os 9 | import sys 10 | 11 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 12 | THIRD_PARTY_DIR = os.path.join(BASE_DIR,"thirdparty") 13 | if sys.platform == 'win32': 14 | TOOLS_DIR = os.path.abspath(os.path.join(THIRD_PARTY_DIR, "Bin", "Win32")) 15 | FMMT = os.path.join(TOOLS_DIR, "FMMT.exe") 16 | GENSEC = os.path.join(TOOLS_DIR, "GenSec.exe") 17 | GENFFS = os.path.join(TOOLS_DIR, "GenFfs.exe") 18 | GENFV = os.path.join(TOOLS_DIR, "GenFv.exe") 19 | LZCOMPRESS = os.path.join(TOOLS_DIR, "LzmaCompress.exe") 20 | elif sys.platform == 'linux': 21 | TOOLS_DIR = os.path.abspath(os.path.join(THIRD_PARTY_DIR, "Bin", "Linux")) 22 | FMMT = os.path.join(TOOLS_DIR, "FMMT") 23 | GENSEC = os.path.join(TOOLS_DIR, "GenSec") 24 | GENFFS = os.path.join(TOOLS_DIR, "GenFfs") 25 | GENFV = os.path.join(TOOLS_DIR, "GenFv") 26 | LZCOMPRESS = os.path.join(TOOLS_DIR, "LzmaCompress") 27 | 28 | RSA_HELPER = os.path.join(TOOLS_DIR, "rsa_helper.py") 29 | FMMT_CFG = os.path.join(TOOLS_DIR, "FmmtConf.ini") 30 | IP_OPTIONS_CFG = os.path.join(BASE_DIR, "common", "ip_options.json") 31 | 32 | EDK2_CAPSULE_TOOL = os.path.abspath(os.path.join(THIRD_PARTY_DIR, 33 | "edk2_capsule_tool", 34 | "GenerateCapsule.py")) 35 | -------------------------------------------------------------------------------- /siiptool/common/utilities.py: -------------------------------------------------------------------------------- 1 | # @file 2 | # Functions use to suport sub regions tools 3 | # 4 | # Copyright (c) 2020, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | import os 9 | import subprocess 10 | import sys 11 | import click 12 | from collections.abc import Iterable 13 | from pathlib import Path 14 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 15 | import common.logger as logging 16 | 17 | 18 | 19 | 20 | def execute_cmds(log, cmds): 21 | """execute commands created from the build list""" 22 | 23 | for _, command in enumerate(cmds): 24 | try: 25 | log.info("\n{}".format(" ".join(command))) 26 | subprocess.check_call(command) 27 | except subprocess.CalledProcessError as status: 28 | log.warning("\nStatus Message: {}".format(status)) 29 | return 1 30 | return 0 31 | 32 | 33 | def get_key_and_value(dict, lookup_value, value_loc): 34 | """ Finds the key and associated value from the lookup value based on the location of the lookup value """ 35 | 36 | for key, value in dict.items(): 37 | if lookup_value == value[value_loc[0]][value_loc[1]]: 38 | return key, value 39 | return None, None 40 | 41 | def get_key(table,lookup_value): 42 | """Finds they key given a value for single values and list of values """ 43 | 44 | value_list = list(table.values()) 45 | 46 | # If each key only have one value, to see if lookup_value is in the dictionary 47 | if isinstance(value_list[0], Iterable) == False: 48 | if lookup_value in value_list: 49 | return list(table.keys())[value_list.index(lookup_value)] 50 | return None 51 | 52 | # Each key has a list of associate values, check to see if the lookup_value matches value for the key. 53 | # Note this assumes each list Value is unique to each key. 54 | for key in table: 55 | for value in table[key]: 56 | if (value == lookup_value): 57 | return key 58 | 59 | def cleanup(files): 60 | for file in files: 61 | try: 62 | os.remove(file) 63 | except FileNotFoundError: 64 | pass 65 | 66 | 67 | def file_not_exist(file, log): 68 | """Verify that file does not exist.""" 69 | 70 | if os.path.isfile(file): 71 | if not (click.confirm("\n{} file already exists! Do you want to overwrite it".format(file), abort=False)): 72 | log.critical("%s file already exists. Exiting tool!", file) 73 | sys.exit(2) 74 | return file 75 | 76 | 77 | def file_exist(files,log): 78 | """Verify that file exist.""" 79 | 80 | for file in files: 81 | if not os.path.isfile(file): 82 | log.critical("\n{} file not found".format(file)) 83 | return 2 84 | return 0 85 | 86 | 87 | def check_file_size(log, files): 88 | """ Check if file is empty or greater than IFWI/BIOS file""" 89 | 90 | bios_size = os.path.getsize(files[0]) 91 | 92 | for file in files: 93 | filesize = os.path.getsize(file) 94 | if filesize != 0: 95 | if not (filesize <= bios_size): 96 | log.critical("\n{} file is size {} file exceeds the size of the BIOS/IFWI file {}!".format(file, filesize, files[0])) 97 | return 2 98 | else: 99 | log.critical("\n{} file is empty!".format(file)) 100 | return 2 101 | 102 | return 0 103 | 104 | 105 | def check_key(file, key_type, log): 106 | """ Check if file exist, empty, or over max size and correct format""" 107 | # element[0][1] start of file; element[-1][0] is size of file 108 | KEY_TYPE = { 109 | "rsa": [ 110 | "RSA private key", 111 | "-----BEGIN RSA PRIVATE KEY-----", 112 | "-----END RSA PRIVATE KEY-----", 113 | 3500, 114 | ], 115 | "pubcert": [ 116 | "Public Certificate", 117 | "-----BEGIN CERTIFICATE-----", 118 | "-----END CERTIFICATE-----", 119 | 2500, 120 | ], 121 | "pkcs7": [ 122 | "PKCS7 Signer", 123 | "Bag Attributes", 124 | "-----END PRIVATE KEY-----", 125 | "localKeyID:", 126 | "subject=", 127 | "issuer=", 128 | "-----BEGIN CERTIFICATE-----", 129 | "-----END CERTIFICATE-----", 130 | "-----BEGIN PRIVATE KEY-----", 131 | 5500, 132 | ] 133 | } 134 | 135 | if os.path.isfile(file): 136 | 137 | key_info = KEY_TYPE.get(key_type) 138 | max_size = key_info[-1] 139 | size = os.path.getsize(file) 140 | key_name = key_info[0] 141 | 142 | FIRSTLINE = key_info[1] 143 | LASTLINE = key_info[2] 144 | 145 | if size > max_size or size == 0: 146 | log.critical("size of {} is {} the key file size must be greater than 0 and less than {}!".format(file, size, max_size)) 147 | return 2 148 | else: 149 | with open(file, "r") as key: 150 | key_lines = key.readlines() 151 | if not ((FIRSTLINE in key_lines[0]) and (LASTLINE in key_lines[-1])): 152 | if key_type == "rsa": 153 | # check if key is in format "-----Begin/End Private Key----" instead of -----Begin/End RSA Private Key---" 154 | if ( FIRSTLINE.replace(' RSA','') in key_lines[0]) and (LASTLINE.replace(' RSA',"")in key_lines[-1]): 155 | return 0 156 | log.critical("{} is not in the format of a {}".format(file, key_name)) 157 | return 2 158 | 159 | # veirfy signer format 160 | if key_type == "pkcs7": 161 | if verify_signer(key_info, key_lines): 162 | log.critical("{} is not in the format of a {}".format(file, key_name)) 163 | return 2 164 | else: 165 | log.critical("{} does not exist".format(file)) 166 | return 2 167 | 168 | return 0 169 | 170 | def verify_signer(key_info, file_data): 171 | """ Verify signature key file """ 172 | 173 | #format of signature file 174 | 175 | # Bag attributes 176 | #localKeyID: "keyid" 177 | #subject="some data" 178 | #issuer="some data" 179 | #-----BEGIN CERTIFICATE----- 180 | #"lines of certificate data" 181 | #-----END CERTIFICATE----- 182 | # Bag attributes 183 | # localKeyID: "keyid" 184 | #-----BEGIN PRIVATE KEY----- 185 | # "Lines of key data" 186 | #-----END PRIVATE KEY----- 187 | 188 | CORRECT_FORMAT = ["KEY", "SUB", "ISSU", "B_CERT","E_CERT", "KEY", "B_KEY"] 189 | KEYID =key_info[3] 190 | SUBJECT =key_info[4] 191 | ISSUER = key_info[5] 192 | BEGIN_CERT = key_info[6] 193 | END_CERT = key_info[7] 194 | BEGIN_KEY = key_info[8] 195 | key_indexes = [] 196 | format_pattern = [] 197 | 198 | 199 | # find keywords in file 200 | 201 | for i in range(len(file_data)): 202 | 203 | if file_data[i].find(KEYID) != -1: 204 | key_indexes.append(i) 205 | format_pattern.append('KEY') 206 | elif file_data[i].find(SUBJECT) != -1: 207 | format_pattern.append('SUB') 208 | elif file_data[i].find(ISSUER) != -1: 209 | format_pattern.append('ISSU') 210 | elif file_data[i].find(BEGIN_CERT) != -1: 211 | format_pattern.append('B_CERT') 212 | elif file_data[i].find(END_CERT) != -1: 213 | format_pattern.append('E_CERT') 214 | elif file_data[i].find(BEGIN_KEY) != -1: 215 | format_pattern.append('B_KEY') 216 | 217 | # verify there is two KeyIDs and they are the same, and format is correct for keywords in data file 218 | if (len(key_indexes) != 2 or (file_data[key_indexes[0]] != file_data[key_indexes[1]]) or 219 | format_pattern != CORRECT_FORMAT): 220 | return 1 221 | return 0 222 | 223 | 224 | def check_for_tool(tool, ver_cmd, tool_path=None): 225 | """Checks tool is installed and return path""" 226 | 227 | if tool_path is None: 228 | tool_path = "" 229 | else: 230 | tool_path = os.path.abspath(tool_path) 231 | 232 | path=os.path.join(tool_path, tool) 233 | 234 | cmd= f'{path} {ver_cmd}' 235 | 236 | try: 237 | p = subprocess.run(cmd, 238 | stdout=subprocess.PIPE, 239 | shell=True, 240 | universal_newlines=True) 241 | print("openssl version: {}".format(p.stdout)) 242 | return path 243 | except: 244 | print("OpenSSL is not installed or missing in PATH!\n") 245 | sys.exit(1) -------------------------------------------------------------------------------- /siiptool/release.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """Release script to package required files""" 4 | 5 | import os 6 | import sys 7 | import zipfile 8 | import subprocess 9 | from datetime import datetime 10 | import fileinput 11 | from shutil import move 12 | 13 | OUTDIR = "dist" 14 | 15 | BOM = [ 16 | "scripts", 17 | "common", 18 | "thirdparty", 19 | "bin" 20 | ] 21 | 22 | g_fmmt_config_file = "FmmtConf.ini" 23 | g_rsa_helper_exe = "" 24 | g_fmmt_path = "" 25 | g_fmmt_config_path = "" 26 | g_backup_extention = '.bak' 27 | 28 | def change_fmmt_conf(): 29 | global g_fmmt_path 30 | global g_rsa_helper_exe 31 | if sys.platform == 'win32': 32 | g_fmmt_path= os.path.join(os.path.dirname(__file__), 33 | "thirdparty", "Bin", "Win32") 34 | g_rsa_helper_exe = "rsa_helper.exe" 35 | elif sys.platform == 'linux': 36 | g_fmmt_path = os.path.join(os.path.dirname(__file__), 37 | "thirdparty", "Bin", "Linux") 38 | g_rsa_helper_exe = "rsa_helper" 39 | global g_fmmt_config_path 40 | g_fmmt_config_path = os.path.join(g_fmmt_path, g_fmmt_config_file) 41 | with fileinput.FileInput(g_fmmt_config_path, inplace=True, backup=g_backup_extention) as file: 42 | for line in file: 43 | print(line.replace("rsa_helper.py", g_rsa_helper_exe), end='') 44 | 45 | def cleanup(): 46 | move(g_fmmt_config_path + g_backup_extention, g_fmmt_config_path) 47 | os.remove(os.path.join(g_fmmt_path, g_rsa_helper_exe)) 48 | 49 | def generate_rsa_helper_exe(): 50 | if sys.platform == 'win32': 51 | subprocess.check_call(r"pyinstaller thirdparty/Bin/Win32/rsa_helper.py " 52 | r"--onefile --distpath ./thirdparty/Bin/Win32") 53 | elif sys.platform == 'linux': 54 | subprocess.check_call(r"pyinstaller thirdparty/Bin/Linux/rsa_helper.py " 55 | r"--onefile --distpath ./thirdparty/Bin/Linux", 56 | shell=True) 57 | 58 | def generate_exe(): 59 | generate_rsa_helper_exe() 60 | change_fmmt_conf() 61 | if sys.platform == 'win32': 62 | subprocess.check_call(r"pyinstaller scripts/siip_sign.py " 63 | r"--onefile --distpath ./bin") 64 | subprocess.check_call(r"pyinstaller scripts/siip_stitch.py " 65 | r"--add-binary " 66 | r"thirdparty/Bin/Win32/;thirdparty/Bin/Win32 " 67 | r"--add-data " 68 | r"common/ip_options.json;common " 69 | r"--onefile --distpath ./bin") 70 | subprocess.check_call(r"pyinstaller scripts/subregion_capsule.py " 71 | r"--add-binary " 72 | r"thirdparty/Bin/Win32/;thirdparty/Bin/Win32 " 73 | r"--add-data " 74 | r"common/ip_options.json;common " 75 | r"--onefile --distpath ./bin") 76 | subprocess.check_call(r"pyinstaller scripts/subregion_sign.py " 77 | r"--add-binary " 78 | r"thirdparty/Bin/Win32/;thirdparty/Bin/Win32 " 79 | r"--onefile --distpath ./bin") 80 | elif sys.platform == 'linux': 81 | subprocess.check_call(r"pyinstaller scripts/siip_sign.py " 82 | r"--onefile --distpath ./bin", 83 | shell=True) 84 | subprocess.check_call(r"pyinstaller scripts/siip_stitch.py " 85 | r"--add-binary " 86 | r"thirdparty/Bin/Linux/:thirdparty/Bin/Linux " 87 | r"--add-data " 88 | r"common/ip_options.json:common " 89 | r"--onefile --distpath ./bin", 90 | shell=True) 91 | subprocess.check_call(r"pyinstaller scripts/subregion_capsule.py " 92 | r"--add-binary " 93 | r"thirdparty/Bin/Linux/:thirdparty/Bin/Linux " 94 | r"--add-data " 95 | r"common/ip_options.json:common " 96 | r"--onefile --distpath ./bin", 97 | shell=True) 98 | subprocess.check_call(r"pyinstaller scripts/subregion_sign.py " 99 | r"--add-binary " 100 | r"thirdparty/Bin/Linux/:thirdparty/Bin/Linux " 101 | r"--onefile --distpath ./bin", 102 | shell=True) 103 | 104 | def create_archive(out_zip, file_list): 105 | 106 | dest_list = [] 107 | for name in file_list: 108 | if os.path.isdir(name): 109 | for root, dirs, files in os.walk(name): 110 | for f in files: 111 | if "__pycache__" in root: 112 | continue 113 | ff = os.path.join(root, f) 114 | dest_list.append(ff) 115 | else: 116 | dest_list.append(name) 117 | 118 | with zipfile.ZipFile(out_zip, "w") as zip_fd: 119 | for f in dest_list: 120 | zip_fd.write(f) 121 | zip_fd.printdir() 122 | print("*** Total files: {}".format(len(zip_fd.namelist()))) 123 | 124 | def main(): 125 | 126 | date_created = datetime.now().strftime('%Y%m%d') 127 | os_str = sys.platform.lower() 128 | if os_str.startswith('win'): 129 | os_str = 'win' 130 | zip_file = os.path.join(OUTDIR, "fbu_siiptool_{}_{}.zip" 131 | .format(os_str, date_created)) 132 | generate_exe() 133 | 134 | if not os.path.exists(OUTDIR): 135 | os.mkdir(OUTDIR) 136 | create_archive(zip_file, BOM) 137 | cleanup() 138 | 139 | 140 | if __name__ == "__main__": 141 | sys.exit(main()) 142 | -------------------------------------------------------------------------------- /siiptool/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/scripts/__init__.py -------------------------------------------------------------------------------- /siiptool/scripts/macgen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2021, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | """A helper script to simplify MAC address capsule 9 | """ 10 | 11 | 12 | import sys 13 | import os 14 | import argparse 15 | import glob 16 | import uuid 17 | 18 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 19 | import scripts.subregion_capsule as capsule_tool 20 | import common.subregion_descriptor as subrgn_descrptr 21 | import common.subregion_image as image 22 | import common.utilities as utils 23 | from common.siip_constants import VERSION as __version__ 24 | from common.banner import banner 25 | import common.logger as logging 26 | 27 | logger = logging.getLogger("macgen") 28 | 29 | if sys.version_info < (3, 6): 30 | raise Exception("Python 3.6 is the minimal version required") 31 | 32 | # 33 | # Globals for help information 34 | # 35 | __prog__ = "macgen" 36 | 37 | TOOLNAME = "MAC Sub-Region helper Tool" 38 | 39 | def create_arg_parser(): 40 | def convert_arg_line_to_args(arg_line): 41 | for arg in arg_line.split(): 42 | if not arg.strip(): 43 | continue 44 | yield arg 45 | 46 | my_parser = argparse.ArgumentParser( 47 | prog=__prog__, 48 | description=__doc__, 49 | conflict_handler="resolve", 50 | fromfile_prefix_chars="@", 51 | ) 52 | my_parser.convert_arg_line_to_args = convert_arg_line_to_args 53 | my_parser.add_argument( 54 | "DevMac", 55 | help="dev:mac", 56 | nargs="*", 57 | type=str, 58 | ) 59 | my_parser.add_argument( 60 | "-o", "--output", dest="Output_Capsule_File", 61 | help="Output Capsule filename.", 62 | default="tsnMacCapsule.bin", 63 | ) 64 | 65 | my_parser.add_argument( 66 | "-s", 67 | "--signer-private-cert", 68 | dest="OpenSslSignerPrivateCertFile", 69 | help="OpenSSL signer private certificate filename.", 70 | ) 71 | my_parser.add_argument( 72 | "-p", 73 | "--other-public-cert", 74 | dest="OpenSslOtherPublicCertFile", 75 | help="OpenSSL other public certificate filename.", 76 | ) 77 | my_parser.add_argument( 78 | "-t", 79 | "--trusted-public-cert", 80 | dest="OpenSslTrustedPublicCertFile", 81 | help="OpenSSL trusted public certificate filename.", 82 | ) 83 | my_parser.add_argument( 84 | "--signing-tool-path", 85 | dest="SigningToolPath", 86 | help="Path to signtool or OpenSSL tool. " 87 | " Optional if path to tools are already in PATH.", 88 | ) 89 | 90 | return my_parser 91 | 92 | 93 | def build_tsn_mac_address_descreiptor(descriptor, dev_mac_pairs): 94 | 95 | def hex_to_bin(hex, bits): 96 | binVal = bin(int(hex, 16))[2:].zfill(bits) 97 | if len(binVal) > bits: 98 | raise ValueError('Out of range') 99 | return binVal 100 | 101 | 102 | descriptor.fmp_guid = subrgn_descrptr.FMP_CAPSULE_TSN_MAC_ADDRESS_FILE_GUID 103 | descriptor.s_fmp_guid = (str) (subrgn_descrptr.FMP_CAPSULE_TSN_MAC_ADDRESS_FILE_GUID) 104 | descriptor.version = 1 105 | descriptor.s_fv_guid = "1A803C55-F034-4E60-AD9E-9D3F32CE273C" 106 | descriptor.fv_guid = uuid.UUID(descriptor.s_fv_guid) 107 | ffs_guid = "12E29FB4-AA56-4172-B34E-DD5F4B440AA9" 108 | descriptor.ffs_files = [] 109 | data = [] 110 | 111 | data.append(["Version", "DECIMAL", 4, 1]) 112 | data.append(["NumPorts", "DECIMAL", 4, len(dev_mac_pairs)]) 113 | 114 | for arg in dev_mac_pairs: 115 | 116 | try: 117 | dm = arg.split(':') 118 | if len(dm) != 2: # BDF and MAC address must be provided 119 | raise ValueError('Wrong argument format') 120 | 121 | bdf = dm[0].split('.') 122 | if len(bdf) != 3: # All 3 parts of BDF must be provided 123 | raise ValueError('Wrong BDF format') 124 | 125 | hexBus, hexDev, hexFun = bdf 126 | mac = dm[1] 127 | if len(mac) != 12: # MAC address must be 12 digits 128 | raise ValueError('Wrong MAC length') 129 | 130 | binMac = hex_to_bin(mac, 48) # MAC address must be valid Hexa digits 131 | if binMac.endswith('1'): # Validate MAC address is Unicast not multicast/broadcast 132 | raise ValueError('Invalid MAC Address, ends with odd number, unicast/multicast bit must be zero') 133 | 134 | # Validate MAC address is not from the invalid list 135 | invallid_list = [ 136 | '000000000000', 137 | 'FFFFFFFFFFFF' 138 | ] 139 | if mac in invallid_list: 140 | raise ValueError('Invalid MAC Address, from the invalid list {}'.format(invallid_list)) 141 | 142 | # Validate all values are numeric and within range 143 | binBus = hex_to_bin(hexBus, 8) # 8 bit binary 144 | binDev = hex_to_bin(hexDev, 5) # 5 bit binary 145 | binFun = hex_to_bin(hexFun, 3) # 3 bit binary 146 | except ValueError as error: 147 | print("{}: {}".format(error,arg)) 148 | exit(2) 149 | 150 | 151 | binBdf = "0000{bus}{dev}{fun}000000000000".format(bus = binBus, dev = binDev, fun = binFun) 152 | 153 | hexBdf = hex(int(binBdf, 2))[2:].zfill(8) 154 | print("BDF: {}".format(hexBdf)) 155 | 156 | macLow = mac[-8:].upper() 157 | print("MacLow: {}".format(macLow)) 158 | 159 | macHigh = mac[:-8].zfill(8).upper() 160 | print("MacHigh: {}".format(macHigh)) 161 | 162 | data.append( ["BDF", "HEXADECIMAL", 4, hexBdf ]) 163 | data.append( ["MacAddressLow", "HEXADECIMAL", 4, macLow ]) 164 | data.append( ["MacAddressHigh", "HEXADECIMAL", 4, macHigh ]) 165 | 166 | ffs_file = subrgn_descrptr.SubRegionFfsFile(ffs_guid, data) 167 | 168 | descriptor.ffs_files.append(ffs_file) 169 | 170 | 171 | if __name__ == "__main__": 172 | 173 | banner(TOOLNAME, __version__) 174 | 175 | parser = create_arg_parser() 176 | args = parser.parse_args() 177 | 178 | desc = subrgn_descrptr.SubRegionDescriptor() 179 | build_tsn_mac_address_descreiptor(desc, args.DevMac) 180 | capsule_tool.generate_sub_region_capsule(desc, args.Output_Capsule_File, args.SigningToolPath, 181 | args.OpenSslSignerPrivateCertFile, args.OpenSslOtherPublicCertFile, args.OpenSslTrustedPublicCertFile ) 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /siiptool/scripts/siip_stitch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2020, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | """A stitching utility to replace code/data sub-regions in System BIOS image 9 | """ 10 | 11 | 12 | import os 13 | import subprocess 14 | import sys 15 | import argparse 16 | import shutil 17 | import re 18 | import uuid 19 | import click 20 | import json 21 | from pathlib import Path 22 | 23 | 24 | from cryptography.hazmat.primitives import hashes as hashes 25 | from cryptography.hazmat.backends import default_backend 26 | 27 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 28 | import common.subregion_image as sbrgn_image 29 | import common.utilities as utils 30 | from common.subregion_descriptor import SubRegionDescriptor 31 | from common.subregion_image import generate_sub_region_image 32 | from common.ifwi import IFWI_IMAGE 33 | from common.firmware_volume import FirmwareDevice 34 | from common.tools_path import FMMT, GENFV, GENFFS, GENSEC, LZCOMPRESS, TOOLS_DIR, IP_OPTIONS_CFG 35 | from common.tools_path import RSA_HELPER, FMMT_CFG 36 | from common.siip_constants import VERSION as __version__ 37 | from common.banner import banner 38 | import common.logger as logging 39 | 40 | __prog__ = "siip_stitch" 41 | 42 | TOOLNAME = "SIIP Stitching Tool" 43 | 44 | banner(TOOLNAME, __version__) 45 | 46 | logger = logging.getLogger("siip_stitch") 47 | 48 | if sys.version_info < (3, 6): 49 | raise Exception("Python 3.6 is the minimal version required") 50 | 51 | GUID_FFS_OBBPEI_HASH = uuid.UUID("F57757FC-2603-404F-AAE2-34C6232388E8") 52 | GUID_FFS_OBBDXE_HASH = uuid.UUID("32198477-7337-40E4-897D-BC33F018B42F") 53 | 54 | # Region for OBBPEI digest 55 | GUID_FVOSBOOT = uuid.UUID("13BF8810-75FD-4B1A-91E6-E16C4201F80A") 56 | GUID_FVUEFIBOOT = uuid.UUID("0496D33D-EA79-495C-B65D-ABF607184E3B") 57 | GUID_FVADVANCED = uuid.UUID("B23E7388-9953-45C7-9201-0473DDE5487A") 58 | 59 | # Region for OBBDXE digest 60 | GUID_FVPOSTMEMORY = uuid.UUID("9DFE49DB-8EF0-4D9C-B273-0036144DE917") 61 | GUID_FVFSPS = uuid.UUID("8C8CE578-8A3D-4F1C-9935-896185C32DD3") # EFI_FIRMWARE_FILE_SYSTEM2_GUID 62 | 63 | with open(IP_OPTIONS_CFG) as ip_options_config_file: 64 | ip_options = json.load(ip_options_config_file) 65 | 66 | def search_for_fv(inputfile, ipname): 67 | """Search for the firmware volume.""" 68 | 69 | # use to find the name of the firmware to locate the firmware volume 70 | build_list = ip_options.get(ipname) 71 | 72 | ui_name = build_list[0][1] 73 | 74 | logger.info("\nFinding the Firmware Volume") 75 | fw_vol = None 76 | 77 | command = [FMMT, "-v", os.path.abspath(inputfile)] 78 | 79 | try: 80 | os.environ["PATH"] += os.pathsep + TOOLS_DIR 81 | logger.info("TOOLS_DIR : %s" % TOOLS_DIR) 82 | logger.info("PATH : %s" % os.environ["PATH"]) 83 | logger.info("\n{}".format(" ".join(command))) 84 | 85 | p = subprocess.run(command, 86 | shell=False, 87 | check=True, 88 | stdout=subprocess.PIPE, 89 | universal_newlines=True, 90 | timeout=60) 91 | 92 | except subprocess.CalledProcessError as status: 93 | logger.warning("\nError using FMMT: {}".format(status)) 94 | return 1, fw_vol 95 | except subprocess.TimeoutExpired: 96 | logger.warning( 97 | "\nFMMT timed out viewing {}! Check input file for correct format".format(inputfile) 98 | ) 99 | 100 | if sys.platform == 'win32': 101 | result = os.system("taskkill /f /im FMMT.exe") 102 | elif sys.platform == 'linux': 103 | result = os.system("killall FMMT") 104 | if result == 0: 105 | return 1, fw_vol 106 | sys.exit("\nError Must kill process") 107 | 108 | # search FFS by name in firmware volumes 109 | fwvol_found = False 110 | 111 | for line in p.stdout.splitlines(): 112 | print(">> %s" % line) 113 | match_fv = re.match(r"(^FV\d+) :", line) 114 | if match_fv: 115 | fwvol_found = True 116 | fw_vol = match_fv.groups()[0] 117 | continue 118 | if fwvol_found: 119 | match_name = re.match(r'File "(%s)"' % ui_name, line.lstrip()) 120 | if match_name: 121 | break 122 | else: 123 | fw_vol = None # firmware volume was not found. 124 | logger.warning("\nCould not find file {} in {}".format(ui_name, inputfile)) 125 | 126 | return 0, fw_vol 127 | 128 | 129 | def replace_ip(outfile, fw_vol, ui_name, inputfile): 130 | """ replaces the give firmware value with the input file """ 131 | 132 | cmd = [FMMT, "-r", inputfile, fw_vol, ui_name, "tmp.ffs", outfile] 133 | return cmd 134 | 135 | 136 | def create_commands(filenames, ipname, fwvol): 137 | """Create Commands for the merge and replace of firmware section.""" 138 | 139 | inputfiles, num_replace_files = sbrgn_image.ip_inputfiles(filenames, ipname) 140 | build_list = ip_options.get(ipname) 141 | 142 | # get the file name to be used to replace firmware volume 143 | ui_name = build_list[0][1] 144 | 145 | cmd_list = sbrgn_image.build_command_list(build_list, inputfiles, num_replace_files) 146 | 147 | cmd = replace_ip(filenames[len(filenames) - 1], fwvol, ui_name, 148 | filenames[0]) 149 | cmd_list.append(cmd) 150 | 151 | return cmd_list 152 | 153 | 154 | def merge_and_replace(filename, guid_values, fwvol): 155 | """Perform merge and replace of section using different executable.""" 156 | 157 | cmds = create_commands(filename, guid_values, fwvol) 158 | 159 | logger.info("\nStarting merge and replacement of section") 160 | 161 | # Merging and Replacing 162 | status = utils.execute_cmds(logger, cmds) 163 | 164 | return status 165 | 166 | 167 | def parse_cmdline(): 168 | """ Parsing and validating input arguments.""" 169 | 170 | visible_ip_list = list(ip_options.keys()) 171 | visible_ip_list.remove("obbpei_digest") 172 | visible_ip_list.remove("obbdxe_digest") 173 | 174 | epilog = "Supported Sub-Region Names: {}\n".format(visible_ip_list) 175 | parser = argparse.ArgumentParser(prog=__prog__, 176 | description=__doc__, 177 | epilog=epilog) 178 | 179 | parser.add_argument( 180 | "IFWI_IN", 181 | type=argparse.FileType("rb+"), 182 | help="Input BIOS Binary file(Ex: IFWI.bin) to be updated with the given input IP firmware", 183 | ) 184 | parser.add_argument( 185 | "IPNAME_IN", 186 | type=argparse.FileType("rb"), 187 | help="Input IP firmware Binary file(Ex: PseFw.Bin to be replaced in the IFWI.bin", 188 | ) 189 | parser.add_argument( 190 | "-ip", 191 | "--ipname", 192 | help="The name of the IP in the IFWI_IN file to be replaced. This is required.", 193 | metavar="ipname", 194 | required=True, 195 | choices=visible_ip_list, 196 | ) 197 | parser.add_argument( 198 | "-k", 199 | "--private-key", 200 | help="Private RSA key in PEM format. Note: Key is required for stitching GOP features", 201 | ) 202 | parser.add_argument( 203 | "-v", 204 | "--version", 205 | help="Shows the current version of the BIOS Stitching Tool", 206 | action="version", 207 | version="%(prog)s {version}".format(version=__version__), 208 | ) 209 | parser.add_argument( 210 | "-o", 211 | "--outputfile", 212 | dest="OUTPUT_FILE", 213 | help="IFWI binary file with the IP replaced with the IPNAME_IN", 214 | metavar="FileName", 215 | default="BIOS_OUT.bin", 216 | ) 217 | 218 | return parser 219 | 220 | 221 | def stitch_and_update(ifwi_file, ip_name, file_list, out_file): 222 | 223 | # search for firmware volume 224 | status, fw_volume = search_for_fv(ifwi_file, ip_name) 225 | 226 | # Check for error in using FMMT.exe or if firmware volume was not found. 227 | if status == 1 or fw_volume is None: 228 | 229 | to_remove = ["tmp.fmmt.txt", "tmp.payload.bin", "tmp.obb.hash.bin", 230 | os.path.join(TOOLS_DIR, "privkey.pem")] 231 | 232 | utils.cleanup(to_remove) 233 | 234 | if status == 0: 235 | logger.critical("\nError: No Firmware volume found") 236 | status = 1 237 | sys.exit(status) 238 | 239 | # firmware volume was found 240 | logger.info("\nThe Firmware volume is {}\n".format(fw_volume)) 241 | 242 | # adding the path name to the output file 243 | file_list.append(os.path.abspath(out_file)) 244 | 245 | # Add firmware volume header and merge it in out_file 246 | status = merge_and_replace(file_list, ip_name, fw_volume) 247 | if status != 0: 248 | sys.exit(status) 249 | 250 | 251 | def calculate_new_obb_digest(ifwi_file, fv_list, digest_file): 252 | """Calculate new OBB hash for one or more firmware volumes. 253 | The assumption is all FVs are continuous in one region.""" 254 | 255 | bios = bytearray() 256 | 257 | ifwi = IFWI_IMAGE(ifwi_file) 258 | if not ifwi.is_ifwi_image(): 259 | logger.warn("Invalid IFWI descriptor signature. Assuming BIOS image") 260 | with open(ifwi_file, "rb") as fd: 261 | bios = FirmwareDevice(0, bytearray(fd.read())) 262 | else: 263 | ifwi.parse() 264 | bios_start = ifwi.region_list[1][1] 265 | bios_limit = ifwi.region_list[1][2] 266 | bios = FirmwareDevice(0, ifwi.data[bios_start:bios_limit+1]) 267 | 268 | logger.info("Found BIOS ({}MB)...".format(len(bios.FdData) // (1024 * 1024))) 269 | bios.ParseFd() 270 | 271 | # Locate FVs (note: only the first FV index is used) 272 | fv_id_list = [] 273 | for fv in fv_list: 274 | obb_fv_idx = bios.get_fv_index_by_guid(fv.bytes_le) 275 | if not (0 < obb_fv_idx < len(bios.FvList)): 276 | raise ValueError("FV {} for OBB region is not found".format(fv)) 277 | logger.info("Found FV @ index {}".format(obb_fv_idx)) 278 | fv_id_list.append(obb_fv_idx) 279 | 280 | starting_fv_idx = fv_id_list[0] 281 | logger.info("*** OBB region starts from FV{} (len:{})".format(starting_fv_idx, len(fv_id_list))) 282 | obb_offset = bios.FvList[starting_fv_idx].Offset 283 | obb_length = 0 284 | if bios.is_fsp_wrapper(): 285 | logger.info("FSP Wrapper BIOS") 286 | obb_fv_end = starting_fv_idx + len(fv_list) 287 | else: 288 | logger.critical("EDK2 BIOS image format is not supported any more") 289 | exit(2) 290 | 291 | # Get total length of OBB 292 | logger.info("start FV: {} end FV: {}".format(starting_fv_idx, obb_fv_end)) 293 | for fv in bios.FvList[starting_fv_idx:obb_fv_end]: 294 | logger.info("Adding FV size 0x{:x} ...".format(len(fv.FvData))) 295 | obb_length += len(fv.FvData) 296 | 297 | logger.debug("OBB offset: {:x} len {:x}".format(obb_offset, obb_length)) 298 | 299 | # Hash it 300 | digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) 301 | digest.update(bios.FdData[obb_offset:obb_offset+obb_length]) 302 | result = digest.finalize() 303 | with open(digest_file, "wb") as hash_fd: 304 | hash_fd.write(result) 305 | 306 | return 307 | 308 | 309 | def main(): 310 | """Entry to script.""" 311 | 312 | # files created that needs to be remove 313 | to_remove = ["tmp.fmmt.txt", "tmp.raw", "tmp.ui", "tmp.all", "tmp.cmps", 314 | "tmp.guid", "tmp.pe32", "tmp.ffs"] 315 | try: 316 | parser = parse_cmdline() 317 | args = parser.parse_args() 318 | 319 | outfile = Path(args.OUTPUT_FILE).resolve() 320 | outfile = utils.file_not_exist(outfile, logger) 321 | 322 | for f in (FMMT, GENFV, GENFFS, GENSEC, LZCOMPRESS, RSA_HELPER, FMMT_CFG): 323 | if not os.path.exists(f): 324 | raise FileNotFoundError("Thirdparty tool not found ({})".format(f)) 325 | 326 | # Use absolute path because GenSec does not like relative ones 327 | IFWI_file = Path(args.IFWI_IN.name).resolve() 328 | 329 | # If input IP file is a JSON file, convert it to binary as the real input file 330 | if args.IPNAME_IN.name.lower().endswith('.json'): 331 | logger.info("Found JSON as input file. Converting it to binary ...\n") 332 | 333 | desc = SubRegionDescriptor() 334 | desc.parse_json_data(args.IPNAME_IN.name) 335 | 336 | # Currently only creates the first file 337 | generate_sub_region_image(desc.ffs_files[0], output_file="tmp.payload.bin") 338 | IPNAME_file = Path("tmp.payload.bin").resolve() 339 | 340 | # add to remove files 341 | to_remove.append("tmp.payload.bin") 342 | else: 343 | IPNAME_file = Path(args.IPNAME_IN.name).resolve() 344 | 345 | filenames = [str(IFWI_file), str(IPNAME_file)] 346 | if args.ipname in ["gop", "gfxpeim", "vbt", "undi"]: 347 | if not args.private_key or not os.path.exists(args.private_key): 348 | logger.critical("\nMissing RSA key to stitch GOP/PEIM GFX/VBT from command line\n") 349 | parser.print_help() 350 | sys.exit(2) 351 | else: 352 | key_file = Path(args.private_key).resolve() 353 | status = utils.check_key(key_file, "rsa", logger) 354 | if status != 0: 355 | sys.exit(status) 356 | filenames.append(key_file) 357 | 358 | # Verify file is not empty or the IP files are smaller than the input file 359 | status = utils.check_file_size(logger, filenames) 360 | if status != 0: 361 | sys.exit(status) 362 | 363 | # Copy key file to the required name needed for the rsa_helper.py 364 | if args.private_key: 365 | shutil.copyfile(key_file, os.path.join(TOOLS_DIR, "privkey.pem")) 366 | to_remove.append(os.path.join(TOOLS_DIR, 'privkey.pem')) 367 | filenames.remove(key_file) 368 | 369 | logger.info("*** Replacing {} ...".format(args.ipname)) 370 | stitch_and_update(args.IFWI_IN.name, args.ipname, filenames, outfile) 371 | 372 | # Update OBB digest after stitching any data inside OBB region 373 | if args.ipname in ["gop", "vbt", "gfxpeim", "undi"]: 374 | 375 | if args.ipname in ["gop", "undi"]: 376 | ipname = "obbdxe_digest" 377 | fv_list = [GUID_FVOSBOOT, GUID_FVUEFIBOOT, GUID_FVADVANCED] 378 | else: 379 | ipname = "obbpei_digest" 380 | fv_list = [GUID_FVPOSTMEMORY, GUID_FVFSPS] 381 | 382 | digest_file = "tmp.obb.hash.bin" 383 | 384 | to_remove.append(digest_file) 385 | 386 | calculate_new_obb_digest(outfile, fv_list, digest_file) 387 | 388 | filenames = [str(Path(f).resolve()) for f in [outfile, digest_file]] 389 | 390 | logger.info("*** Replacing {} ...".format(ipname)) 391 | stitch_and_update(outfile, ipname, filenames, outfile) 392 | finally: 393 | utils.cleanup(to_remove) 394 | 395 | 396 | if __name__ == "__main__": 397 | 398 | main() 399 | -------------------------------------------------------------------------------- /siiptool/scripts/subregion_capsule.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2020, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | """A capsule image utility to generate UEFI sub-region capsule images 9 | """ 10 | 11 | 12 | import sys 13 | import os 14 | import argparse 15 | import glob 16 | import subprocess 17 | 18 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 19 | import common.subregion_descriptor as subrgn_descrptr 20 | import common.subregion_image as sbrgn_image 21 | import common.utilities as utils 22 | import thirdparty.edk2_capsule_tool.GenerateCapsule as generate_capsule_tool 23 | from common.siip_constants import VERSION as __version__ 24 | from common.banner import banner 25 | import common.logger as logging 26 | from scripts.subregion_sign import sign_subregion 27 | 28 | logger = logging.getLogger("subregion_capsule") 29 | 30 | if sys.version_info < (3, 6): 31 | raise Exception("Python 3.6 is the minimal version required") 32 | 33 | # 34 | # Globals for help information 35 | # 36 | __prog__ = "subregion_capsule" 37 | 38 | TOOLNAME = "Sub-Region Capsule Tool" 39 | 40 | def generate_sub_region_fv( 41 | sub_region_descriptor, 42 | output_fv_file=os.path.join(os.path.curdir, "SubRegion.FV") 43 | ): 44 | 45 | sub_region_image = "SubRegionImage.bin" 46 | signed_sub_region_image = "SignedSubRegionImage.bin" 47 | fv_ffs_file_list = [] 48 | 49 | for file_index, ffs_file in enumerate(sub_region_descriptor.ffs_files): 50 | 51 | sbrgn_image.generate_sub_region_image(ffs_file, sub_region_image) 52 | ip, ip_ops = sbrgn_image.ip_info_from_guid(ffs_file.ffs_guid) 53 | 54 | if ffs_file.signing_key is not None: 55 | sign_subregion(sub_region_image, ffs_file.signing_key, signed_sub_region_image, 56 | ffs_file.signer_type, ip, ffs_file.vendor_guid) 57 | sub_region_image = signed_sub_region_image 58 | 59 | # if ffs GUID is not found exit. 60 | if ip is None: 61 | print("FFS GUIS {} not found".format(ffs_file.ffs_guid)) 62 | exit(-1) 63 | 64 | # Inputfiles should be minium of two files to work with function. 65 | inputfiles, num_files = sbrgn_image.ip_inputfiles( 66 | [None, sub_region_image], 67 | ip 68 | ) 69 | 70 | cmds = sbrgn_image.build_command_list(ip_ops, inputfiles, num_files) 71 | 72 | if utils.execute_cmds(logger, cmds) == 1: 73 | exit(-1) 74 | 75 | ffs_file_path = "tmp.{}.ffs".format(file_index) 76 | os.rename("tmp.ffs", ffs_file_path) 77 | fv_ffs_file_list.append(ffs_file_path) 78 | 79 | fv_cmd_list = sbrgn_image.build_fv_from_ffs_files( 80 | sub_region_descriptor, 81 | output_fv_file, 82 | fv_ffs_file_list) 83 | if utils.execute_cmds(logger, fv_cmd_list) == 1: 84 | print("Error generating FV File") 85 | exit(-1) 86 | 87 | 88 | def create_arg_parser(): 89 | def convert_arg_line_to_args(arg_line): 90 | for arg in arg_line.split(): 91 | if not arg.strip(): 92 | continue 93 | yield arg 94 | 95 | my_parser = argparse.ArgumentParser( 96 | prog=__prog__, 97 | description=__doc__, 98 | conflict_handler="resolve", 99 | fromfile_prefix_chars="@", 100 | ) 101 | my_parser.convert_arg_line_to_args = convert_arg_line_to_args 102 | my_parser.add_argument( 103 | "InputFile", help="Input JSON sub region descriptor filename." 104 | ) 105 | my_parser.add_argument( 106 | "-o", "--output", dest="OutputCapsuleFile", 107 | required=True, 108 | help="Output capsule filename." 109 | ) 110 | my_parser.add_argument( 111 | "-s", 112 | "--signer-private-cert", 113 | dest="OpenSslSignerPrivateCertFile", 114 | help="OpenSSL signer private certificate filename.", 115 | ) 116 | my_parser.add_argument( 117 | "-p", 118 | "--other-public-cert", 119 | dest="OpenSslOtherPublicCertFile", 120 | help="OpenSSL other public certificate filename.", 121 | ) 122 | my_parser.add_argument( 123 | "-t", 124 | "--trusted-public-cert", 125 | dest="OpenSslTrustedPublicCertFile", 126 | help="OpenSSL trusted public certificate filename.", 127 | ) 128 | my_parser.add_argument( 129 | "--signing-tool-path", 130 | dest="SigningToolPath", 131 | help="Path to signtool or OpenSSL tool. " 132 | " Optional if path to tools are already in PATH.", 133 | ) 134 | return my_parser 135 | 136 | 137 | def generate_sub_region_capsule( sub_region_desc, 138 | outputCapsuleFile=os.path.join(os.path.curdir, "capsule.bin"), 139 | signingToolPath = None, 140 | OpenSslSignerPrivateCertFile = None, 141 | OpenSslOtherPublicCertFile = None, 142 | OpenSslTrustedPublicCertFile = None 143 | ): 144 | 145 | sub_region_fv_file = os.path.join(os.path.curdir, "SubRegionFv.fv") 146 | 147 | if OpenSslSignerPrivateCertFile is None: 148 | OpenSslSignerPrivateCertFile = sub_region_desc.signer_prv_cert_file 149 | if OpenSslOtherPublicCertFile is None: 150 | OpenSslOtherPublicCertFile = sub_region_desc.other_pub_cert_file 151 | if OpenSslTrustedPublicCertFile is None: 152 | OpenSslTrustedPublicCertFile = sub_region_desc.trusted_pub_cert_file 153 | 154 | gen_cap_args = [] 155 | if all( 156 | [ 157 | OpenSslSignerPrivateCertFile, 158 | OpenSslOtherPublicCertFile, 159 | OpenSslTrustedPublicCertFile 160 | ] 161 | ): 162 | 163 | # Check if openssl is installed or at given path 164 | utils.check_for_tool('openssl', 'version', tool_path=signingToolPath) 165 | gen_cap_args += ["--signer-private-cert", OpenSslSignerPrivateCertFile] 166 | gen_cap_args += ["--other-public-cert", OpenSslOtherPublicCertFile] 167 | gen_cap_args += ["--trusted-public-cert", OpenSslTrustedPublicCertFile] 168 | elif any( 169 | [ 170 | OpenSslSignerPrivateCertFile, 171 | OpenSslOtherPublicCertFile, 172 | OpenSslTrustedPublicCertFile 173 | ] 174 | ): 175 | print('All-or-none of the certificate files must be provided.') 176 | return 2 177 | 178 | generate_sub_region_fv(sub_region_desc, sub_region_fv_file) 179 | 180 | gen_cap_args += ["--encode"] 181 | gen_cap_args += ["--guid", sub_region_desc.s_fmp_guid] 182 | gen_cap_args += ["--fw-version", str(sub_region_desc.version)] 183 | gen_cap_args += ["--lsv", "0"] 184 | gen_cap_args += ["--capflag", "PersistAcrossReset"] 185 | gen_cap_args += ["--capflag", "InitiateReset"] 186 | gen_cap_args += ["-o", outputCapsuleFile] 187 | gen_cap_args += ["-v"] 188 | 189 | if signingToolPath is not None: 190 | gen_cap_args += ["--signing-tool-path", os.path.abspath(signingToolPath)] 191 | gen_cap_args += [sub_region_fv_file] 192 | 193 | status = generate_capsule_tool.generate_capsule(gen_cap_args) 194 | 195 | # Creating list of files to remove 196 | to_remove = glob.glob("tmp.*") 197 | to_remove.extend(glob.glob("SubRegionFv.*")) 198 | to_remove.append("SubRegionImage.bin") 199 | to_remove.append("SignedSubRegionImage.bin") 200 | 201 | utils.cleanup(to_remove) 202 | 203 | return status 204 | 205 | 206 | if __name__ == "__main__": 207 | 208 | banner(TOOLNAME, __version__) 209 | 210 | parser = create_arg_parser() 211 | args = parser.parse_args() 212 | 213 | sub_region_desc = subrgn_descrptr.SubRegionDescriptor() 214 | sub_region_desc.parse_json_data(args.InputFile) 215 | status = generate_sub_region_capsule (sub_region_desc, args.OutputCapsuleFile, args.SigningToolPath, 216 | args.OpenSslSignerPrivateCertFile, args.OpenSslOtherPublicCertFile, args.OpenSslTrustedPublicCertFile ) 217 | sys.exit(status) 218 | -------------------------------------------------------------------------------- /siiptool/scripts/subregion_fv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2020, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | """A utility to generate UEFI sub-region FV images 9 | """ 10 | 11 | 12 | import sys 13 | import os 14 | import argparse 15 | import glob 16 | 17 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 18 | import scripts.subregion_capsule as capsule_tool 19 | import common.subregion_descriptor as subrgn_descrptr 20 | import common.utilities as utils 21 | from common.siip_constants import VERSION as __version__ 22 | from common.banner import banner 23 | import common.logger as logging 24 | 25 | logger = logging.getLogger("subregion_fv") 26 | 27 | if sys.version_info < (3, 6): 28 | raise Exception("Python 3.6 is the minimal version required") 29 | 30 | # 31 | # Globals for help information 32 | # 33 | __prog__ = "subregion_fv" 34 | 35 | TOOLNAME = "Sub-Region FV Tool" 36 | 37 | def create_arg_parser(): 38 | def convert_arg_line_to_args(arg_line): 39 | for arg in arg_line.split(): 40 | if not arg.strip(): 41 | continue 42 | yield arg 43 | 44 | my_parser = argparse.ArgumentParser( 45 | prog=__prog__, 46 | description=__doc__, 47 | conflict_handler="resolve", 48 | fromfile_prefix_chars="@", 49 | ) 50 | my_parser.convert_arg_line_to_args = convert_arg_line_to_args 51 | my_parser.add_argument( 52 | "InputFile", help="Input JSON sub region descriptor filename." 53 | ) 54 | my_parser.add_argument( 55 | "-o", "--output", dest="OutputFvFile", 56 | required=True, 57 | help="Output FV filename." 58 | ) 59 | 60 | return my_parser 61 | 62 | 63 | if __name__ == "__main__": 64 | 65 | banner(TOOLNAME, __version__) 66 | 67 | parser = create_arg_parser() 68 | args = parser.parse_args() 69 | 70 | sub_region_desc = subrgn_descrptr.SubRegionDescriptor() 71 | sub_region_desc.parse_json_data(args.InputFile) 72 | capsule_tool.logger = logger 73 | capsule_tool.generate_sub_region_fv(sub_region_desc, args.OutputFvFile) 74 | 75 | 76 | # Creating list of files to remove 77 | to_remove = glob.glob("tmp.*") 78 | to_remove.extend(glob.glob(args.OutputFvFile+".*")) 79 | to_remove.append("SubRegionImage.bin") 80 | 81 | utils.cleanup(to_remove) 82 | 83 | -------------------------------------------------------------------------------- /siiptool/scripts/subregion_sign.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2020, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | """A signing utility for creating and signing a BIOS sub-region for UEFI 9 | """ 10 | 11 | 12 | from __future__ import print_function 13 | 14 | import os 15 | import sys 16 | import subprocess 17 | import argparse 18 | import uuid 19 | import struct 20 | import re 21 | from pathlib import Path 22 | 23 | sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 24 | from common.siip_constants import VERSION as __version__ 25 | from common.banner import banner 26 | import common.utilities as utils 27 | import common.logger as logging 28 | 29 | LOGGER = logging.getLogger("subregion_sign") 30 | 31 | __prog__ = "subregion_sign" 32 | 33 | TOOLNAME = "Sub-Region Signing Tool" 34 | 35 | 36 | if sys.version_info < (3, 6): 37 | raise Exception("Python 3.6 is the minimal version required") 38 | 39 | 40 | class UefiSubregAuthenClass: 41 | """ Class define EFI subreation Authentication class """ 42 | 43 | # typedef struct { 44 | # char Name[16 bytes]; // Name of the sub-region 45 | # EFI_GUID VendorGuid; // Vendor GUID 46 | # SUB_REGION_VERIFICATION CertParam; // Sub-Region Certificate Parameters 47 | # } EFI_SUB_REGION_AUTHENTICATION; 48 | 49 | # typedef struct { 50 | # SUB_REGION_HEADER Hdr; // Certificate Header 51 | # UINT8 CertData[1]; // Calculated Signature 52 | # } SUB_REGION_VERIFICATION; 53 | 54 | # typedef struct { 55 | # UINT32 Revision; // Revision of Signature Structure 56 | # UINT32 Length; // Length of the Signature + Header 57 | # EFI_GUID CertType; // Signature type 58 | # } SUB_REGION_HEADER; 59 | 60 | # typedef struct { 61 | # UINT8 PublicKey[384]; // Public Key pair of the Signing Key 62 | # UINT8 Signature[384]; // SHA384-RSA3K Signature 63 | # } EFI_CERT_BLOCK_RSA3072_SHA384; 64 | 65 | _StructAuthInfoFormat = "<16s16sLL16s" 66 | _StructAuthInfoSize = struct.calcsize(_StructAuthInfoFormat) 67 | _StructSubRegionHdrFormat = " max_size: 326 | raise argparse.ArgumentTypeError(str(msg)) 327 | return string 328 | 329 | 330 | def chk_guid_format(guid): 331 | """ check for correct formate of GUID """ 332 | 333 | # format for guid xxxxxxxx-xxxx-xxxx-xxx-xxxxxxxxxxxx where x can be A-F or 0-9 334 | guidFormat = re.compile( 335 | r"([a-f\d]{8}[-][a-f\d]{4}[-][a-f\d]{4}[-][a-f\d]{4}[-]{1}[a-f\d]{12}$)", re.I 336 | ) 337 | 338 | if guidFormat.match(guid) is None: 339 | raise argparse.ArgumentTypeError( 340 | "File guild value is not in correct format \ 341 | (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx where x can be A-F or 0-9)\ 342 | {}".format(guid) 343 | ) 344 | return guid 345 | 346 | def sign_subregion(subregion_file, signer_file, signed_file, signer_type, subregion_name, vendor_guid, show = False, tool_path = None): 347 | 348 | # Use absolute path for openSSL 349 | sbrgn_file = Path(subregion_file).resolve() 350 | signer_file = Path(signer_file).resolve() 351 | outfile = Path(signed_file).resolve() 352 | 353 | filenames = [str(sbrgn_file), str(signer_file)] 354 | 355 | # Verify file input file exist 356 | status = utils.file_exist(filenames, LOGGER) 357 | if status != 0: 358 | sys.exit(status) 359 | 360 | if os.path.getsize(sbrgn_file) == 0: 361 | LOGGER.critical("size of {} subregion file must be greater than 0!".format(sbrgn_file)) 362 | sys.exit(status) 363 | 364 | status = utils.check_key(signer_file, signer_type, LOGGER) 365 | if status != 0: 366 | sys.exit(status) 367 | 368 | outfile = utils.file_not_exist(outfile, LOGGER) 369 | 370 | parser = argparse.ArgumentParser() 371 | parser.add_argument("name, vendor_guid, tool_path, signer_type") 372 | cl_inputs = parser.parse_args(['name={}'.format(subregion_name)]) 373 | cl_inputs.name = subregion_name 374 | cl_inputs.vendor_guid = vendor_guid 375 | cl_inputs.tool_path = tool_path 376 | cl_inputs.signer_type = signer_type 377 | 378 | cert_info = get_certifcation_info(cl_inputs, signer_file) 379 | 380 | uefi_subreg_authen = UefiSubregAuthenClass(cert_info) 381 | 382 | # read input file to store into structure 383 | payload = read_file(sbrgn_file) 384 | uefi_subreg_authen.payload = payload 385 | 386 | # add Vendor Guid to Payload 387 | payload = uefi_subreg_authen.vendor_guid.bytes_le + payload 388 | 389 | # calculate the signature store in structure 390 | cert_data = generate_signature(cert_info["openssl_cmd"], payload) 391 | 392 | if cert_info["openssl_cmd2"]: 393 | # Read in the private key 394 | payload = read_file(signer_file) 395 | 396 | # Extract the public key modulus from private key 397 | cert_pub = generate_signature(cert_info["openssl_cmd2"], payload) 398 | 399 | # convert public key from bytes to string 400 | cert_pub_string = cert_pub.decode("utf-8") 401 | 402 | # remove word Moudlus= from the file 403 | cert_pubkey = cert_pub_string.replace("Modulus=", "") 404 | 405 | # remove end of line from public key 406 | cert_pubkey = cert_pubkey.rstrip() 407 | 408 | # Conert to hex bytes and add to signature 409 | cert_pubkey = bytes.fromhex(cert_pubkey) 410 | 411 | # public key and signature are packed back to back 412 | cert_data = cert_pubkey + cert_data 413 | 414 | uefi_subreg_authen.cert_data = cert_data 415 | 416 | # pack structure with signature and get update size of header 417 | uefi_signed_data = uefi_subreg_authen.encode() 418 | 419 | if show: 420 | uefi_subreg_authen.dump_info() 421 | 422 | # Create output EFI subregion authentication header and signature and original file 423 | build_subreg_signed_file(uefi_signed_data, str(outfile)) 424 | 425 | print( 426 | "Signed {} sub-region({}) was successfully generated.".format( 427 | subregion_name, outfile 428 | ) 429 | ) 430 | 431 | def main(): 432 | """Entry to script.""" 433 | 434 | parser = create_arg_parser() 435 | args = parser.parse_args() 436 | sign_subregion(args.subregion_file, args.signerfile, args.signed_file, 437 | args.signer_type, args.name, args.vendor_guid, args.show, args.tool_path) 438 | 439 | 440 | if __name__ == "__main__": 441 | banner(TOOLNAME, __version__) 442 | main() 443 | -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Linux/FMMT: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Linux/FMMT -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Linux/FmmtConf.ini: -------------------------------------------------------------------------------- 1 | ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress 2 | A7717414-C616-4977-9420-844712A735BF RSA2048SHA256SIGN rsa_helper.py 3 | 4 | -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Linux/GenFfs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Linux/GenFfs -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Linux/GenFv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Linux/GenFv -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Linux/GenSec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Linux/GenSec -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Linux/LzmaCompress: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Linux/LzmaCompress -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Linux/rsa_helper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2019, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | import os 9 | import sys 10 | import argparse 11 | import uuid 12 | import pathlib 13 | 14 | from cryptography.hazmat.primitives import hashes as hashes 15 | from cryptography.hazmat.primitives import serialization as serialization 16 | from cryptography.hazmat.backends import default_backend 17 | from cryptography.hazmat.primitives.asymmetric import padding as crypto_padding 18 | 19 | # 20 | # GUID for SHA 256 Hash Algorithm from UEFI Specification 21 | # 22 | EFI_HASH_ALGORITHM_SHA256_GUID = \ 23 | uuid.UUID("{51aa59de-fdf2-4ea3-bc63-875fb7842ee9}") 24 | 25 | RSA_KEYMOD_SIZE = 256 26 | RSA_KEYEXP_SIZE = 4 27 | KB = 1024 28 | MB = 1024 * KB 29 | 30 | 31 | def pack_num(val, minlen=0): 32 | """Convert a large integer into bytearray, filling with 0 if needed""" 33 | 34 | buf = bytearray() 35 | while val > 0: 36 | if sys.version_info > (3, 0): 37 | buf += bytes([val & 0xFF]) 38 | else: 39 | buf += chr(val & 0xFF) 40 | val >>= 8 41 | buf += bytearray(max(0, minlen - len(buf))) 42 | return buf 43 | 44 | 45 | def get_pubkey_from_privkey(privkey_pem): 46 | """Extract public key from private key in PEM format""" 47 | 48 | with open(privkey_pem, "rb") as privkey_file: 49 | key = serialization.load_pem_private_key( 50 | privkey_file.read(), password=None, backend=default_backend() 51 | ) 52 | 53 | return key.public_key() 54 | 55 | 56 | def compute_signature(data, privkey_pem): 57 | """Compute signature from data""" 58 | 59 | with open(privkey_pem, "rb") as privkey_file: 60 | key = serialization.load_pem_private_key( 61 | privkey_file.read(), password=None, backend=default_backend() 62 | ) 63 | 64 | if key.key_size < 2048: 65 | raise Exception("Key size {} bits is too small.".format(key.key_size)) 66 | 67 | # Calculate signature using private key 68 | signature = key.sign(bytes(data), crypto_padding.PKCS1v15(), 69 | hashes.SHA256()) 70 | 71 | return (signature, key) 72 | 73 | 74 | def main(): 75 | """A helper script as a GUIDed tool called by FMMT""" 76 | 77 | parser = argparse.ArgumentParser( 78 | description="Strip or create signature for a GUIDed section" 79 | ) 80 | group = parser.add_mutually_exclusive_group(required=True) 81 | group.add_argument( 82 | "-d", 83 | action="store_true", 84 | dest="decode", 85 | help="decode file" 86 | ) 87 | group.add_argument( 88 | "-e", 89 | action="store_true", 90 | dest="encode", 91 | help="encode file" 92 | ) 93 | parser.add_argument( 94 | "-o", 95 | "--output", 96 | dest="output_file", 97 | type=str, 98 | metavar="filename", 99 | help="specify the output filename", 100 | required=True, 101 | ) 102 | parser.add_argument( 103 | "--private-key", 104 | dest="privkey_file", 105 | default=os.path.join(os.path.dirname(os.path.abspath(__file__)), "privkey.pem"), 106 | help="specify the private key filename. If not specified," 107 | "a test signing key is used." 108 | ) 109 | parser.add_argument( 110 | metavar="input_file", 111 | dest="input_file", 112 | help="specify the input filename" 113 | ) 114 | 115 | args = parser.parse_args() 116 | 117 | with open(args.input_file, "rb") as in_fd: 118 | in_data = in_fd.read() 119 | 120 | # Strip GUID (16B), public key modulus (256B) and signature (256B) 121 | if args.decode: 122 | with open(args.output_file, "wb") as out_fd: 123 | out_fd.write(in_data[0x210:]) 124 | 125 | # Prepend GUID (16B), public key modulus (256B) and signature (256B) 126 | if args.encode and args.privkey_file: 127 | if getattr(sys, 'frozen', False): 128 | privkey_file_name = os.path.basename(args.privkey_file) 129 | base_dir = pathlib.Path(sys.executable).parent.absolute() 130 | args.privkey_file = os.path.join(base_dir, privkey_file_name) 131 | 132 | pubkey = get_pubkey_from_privkey(args.privkey_file) 133 | (signature, key) = compute_signature(in_data, args.privkey_file) 134 | 135 | puk = get_pubkey_from_privkey(args.privkey_file) 136 | puk_num = puk.public_numbers() 137 | mod_buf = pack_num(puk_num.n, RSA_KEYMOD_SIZE) 138 | 139 | with open(args.output_file, "wb") as out_fd: 140 | out_fd.write(EFI_HASH_ALGORITHM_SHA256_GUID.bytes_le) 141 | out_fd.write(mod_buf[::-1]) # Reverse byte-order before saving 142 | out_fd.write(signature) 143 | out_fd.write(in_data) 144 | 145 | 146 | if __name__ == "__main__": 147 | main() 148 | -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Win32/FMMT.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Win32/FMMT.exe -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Win32/FmmtConf.ini: -------------------------------------------------------------------------------- 1 | ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress 2 | A7717414-C616-4977-9420-844712A735BF RSA2048SHA256SIGN rsa_helper.py 3 | 4 | -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Win32/GenFfs.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Win32/GenFfs.exe -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Win32/GenFv.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Win32/GenFv.exe -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Win32/GenSec.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Win32/GenSec.exe -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Win32/LzmaCompress.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/Bin/Win32/LzmaCompress.exe -------------------------------------------------------------------------------- /siiptool/thirdparty/Bin/Win32/rsa_helper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright (c) 2019, Intel Corporation. All rights reserved. 5 | # SPDX-License-Identifier: BSD-2-Clause 6 | # 7 | 8 | import os 9 | import sys 10 | import argparse 11 | import uuid 12 | import pathlib 13 | 14 | from cryptography.hazmat.primitives import hashes as hashes 15 | from cryptography.hazmat.primitives import serialization as serialization 16 | from cryptography.hazmat.backends import default_backend 17 | from cryptography.hazmat.primitives.asymmetric import padding as crypto_padding 18 | 19 | # 20 | # GUID for SHA 256 Hash Algorithm from UEFI Specification 21 | # 22 | EFI_HASH_ALGORITHM_SHA256_GUID = \ 23 | uuid.UUID("{51aa59de-fdf2-4ea3-bc63-875fb7842ee9}") 24 | 25 | RSA_KEYMOD_SIZE = 256 26 | RSA_KEYEXP_SIZE = 4 27 | KB = 1024 28 | MB = 1024 * KB 29 | 30 | 31 | def pack_num(val, minlen=0): 32 | """Convert a large integer into bytearray, filling with 0 if needed""" 33 | 34 | buf = bytearray() 35 | while val > 0: 36 | if sys.version_info > (3, 0): 37 | buf += bytes([val & 0xFF]) 38 | else: 39 | buf += chr(val & 0xFF) 40 | val >>= 8 41 | buf += bytearray(max(0, minlen - len(buf))) 42 | return buf 43 | 44 | 45 | def get_pubkey_from_privkey(privkey_pem): 46 | """Extract public key from private key in PEM format""" 47 | 48 | with open(privkey_pem, "rb") as privkey_file: 49 | key = serialization.load_pem_private_key( 50 | privkey_file.read(), password=None, backend=default_backend() 51 | ) 52 | 53 | return key.public_key() 54 | 55 | 56 | def compute_signature(data, privkey_pem): 57 | """Compute signature from data""" 58 | 59 | with open(privkey_pem, "rb") as privkey_file: 60 | key = serialization.load_pem_private_key( 61 | privkey_file.read(), password=None, backend=default_backend() 62 | ) 63 | 64 | if key.key_size < 2048: 65 | raise Exception("Key size {} bits is too small.".format(key.key_size)) 66 | 67 | # Calculate signature using private key 68 | signature = key.sign(bytes(data), crypto_padding.PKCS1v15(), 69 | hashes.SHA256()) 70 | 71 | return (signature, key) 72 | 73 | 74 | def main(): 75 | """A helper script as a GUIDed tool called by FMMT""" 76 | 77 | parser = argparse.ArgumentParser( 78 | description="Strip or create signature for a GUIDed section" 79 | ) 80 | group = parser.add_mutually_exclusive_group(required=True) 81 | group.add_argument( 82 | "-d", 83 | action="store_true", 84 | dest="decode", 85 | help="decode file" 86 | ) 87 | group.add_argument( 88 | "-e", 89 | action="store_true", 90 | dest="encode", 91 | help="encode file" 92 | ) 93 | parser.add_argument( 94 | "-o", 95 | "--output", 96 | dest="output_file", 97 | type=str, 98 | metavar="filename", 99 | help="specify the output filename", 100 | required=True, 101 | ) 102 | parser.add_argument( 103 | "--private-key", 104 | dest="privkey_file", 105 | default=os.path.join(os.path.dirname(os.path.abspath(__file__)), "privkey.pem"), 106 | help="specify the private key filename. If not specified," 107 | "a test signing key is used." 108 | ) 109 | parser.add_argument( 110 | metavar="input_file", 111 | dest="input_file", 112 | help="specify the input filename" 113 | ) 114 | 115 | args = parser.parse_args() 116 | 117 | with open(args.input_file, "rb") as in_fd: 118 | in_data = in_fd.read() 119 | 120 | # Strip GUID (16B), public key modulus (256B) and signature (256B) 121 | if args.decode: 122 | with open(args.output_file, "wb") as out_fd: 123 | out_fd.write(in_data[0x210:]) 124 | 125 | # Prepend GUID (16B), public key modulus (256B) and signature (256B) 126 | if args.encode and args.privkey_file: 127 | if getattr(sys, 'frozen', False): 128 | privkey_file_name = os.path.basename(args.privkey_file) 129 | base_dir = pathlib.Path(sys.executable).parent.absolute() 130 | args.privkey_file = os.path.join(base_dir, privkey_file_name) 131 | 132 | pubkey = get_pubkey_from_privkey(args.privkey_file) 133 | (signature, key) = compute_signature(in_data, args.privkey_file) 134 | 135 | puk = get_pubkey_from_privkey(args.privkey_file) 136 | puk_num = puk.public_numbers() 137 | mod_buf = pack_num(puk_num.n, RSA_KEYMOD_SIZE) 138 | 139 | with open(args.output_file, "wb") as out_fd: 140 | out_fd.write(EFI_HASH_ALGORITHM_SHA256_GUID.bytes_le) 141 | out_fd.write(mod_buf[::-1]) # Reverse byte-order before saving 142 | out_fd.write(signature) 143 | out_fd.write(in_data) 144 | 145 | 146 | if __name__ == "__main__": 147 | main() 148 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/Common/Edk2/Capsule/FmpPayloadHeader.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Module that encodes and decodes a FMP_PAYLOAD_HEADER with a payload. 3 | # The FMP_PAYLOAD_HEADER is processed by the FmpPayloadHeaderLib in the 4 | # FmpDevicePkg. 5 | # 6 | # Copyright (c) 2018, Intel Corporation. All rights reserved.
7 | # This program and the accompanying materials 8 | # are licensed and made available under the terms and conditions of the BSD License 9 | # which accompanies this distribution. The full text of the license may be found at 10 | # http://opensource.org/licenses/bsd-license.php 11 | # 12 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 | # 15 | 16 | ''' 17 | FmpPayloadHeader 18 | ''' 19 | 20 | import struct 21 | 22 | def _SIGNATURE_32 (A, B, C, D): 23 | return struct.unpack ('=I',bytearray (A + B + C + D, 'ascii'))[0] 24 | 25 | def _SIGNATURE_32_TO_STRING (Signature): 26 | return struct.pack (" 8 | # This program and the accompanying materials 9 | # are licensed and made available under the terms and conditions of the BSD License 10 | # which accompanies this distribution. The full text of the license may be found at 11 | # http://opensource.org/licenses/bsd-license.php 12 | # 13 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 | # 16 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/Common/Edk2/__init__.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Python 'Common.Edk2' package initialization file. 3 | # 4 | # This file is required to make Python interpreter treat the directory 5 | # as containing package. 6 | # 7 | # Copyright (c) 2018, Intel Corporation. All rights reserved.
8 | # This program and the accompanying materials 9 | # are licensed and made available under the terms and conditions of the BSD License 10 | # which accompanies this distribution. The full text of the license may be found at 11 | # http://opensource.org/licenses/bsd-license.php 12 | # 13 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 | # 16 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/Common/Uefi/Capsule/FmpAuthHeader.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Module that encodes and decodes a EFI_FIRMWARE_IMAGE_AUTHENTICATION with 3 | # certificate data and payload data. 4 | # 5 | # Copyright (c) 2018, Intel Corporation. All rights reserved.
6 | # This program and the accompanying materials 7 | # are licensed and made available under the terms and conditions of the BSD License 8 | # which accompanies this distribution. The full text of the license may be found at 9 | # http://opensource.org/licenses/bsd-license.php 10 | # 11 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 | # 14 | 15 | ''' 16 | FmpAuthHeader 17 | ''' 18 | 19 | import struct 20 | import uuid 21 | 22 | class FmpAuthHeaderClass (object): 23 | # /// 24 | # /// Image Attribute -Authentication Required 25 | # /// 26 | # typedef struct { 27 | # /// 28 | # /// It is included in the signature of AuthInfo. It is used to ensure freshness/no replay. 29 | # /// It is incremented during each firmware image operation. 30 | # /// 31 | # UINT64 MonotonicCount; 32 | # /// 33 | # /// Provides the authorization for the firmware image operations. It is a signature across 34 | # /// the image data and the Monotonic Count value. Caller uses the private key that is 35 | # /// associated with a public key that has been provisioned via the key exchange. 36 | # /// Because this is defined as a signature, WIN_CERTIFICATE_UEFI_GUID.CertType must 37 | # /// be EFI_CERT_TYPE_PKCS7_GUID. 38 | # /// 39 | # WIN_CERTIFICATE_UEFI_GUID AuthInfo; 40 | # } EFI_FIRMWARE_IMAGE_AUTHENTICATION; 41 | # 42 | # /// 43 | # /// Certificate which encapsulates a GUID-specific digital signature 44 | # /// 45 | # typedef struct { 46 | # /// 47 | # /// This is the standard WIN_CERTIFICATE header, where 48 | # /// wCertificateType is set to WIN_CERT_TYPE_EFI_GUID. 49 | # /// 50 | # WIN_CERTIFICATE Hdr; 51 | # /// 52 | # /// This is the unique id which determines the 53 | # /// format of the CertData. . 54 | # /// 55 | # EFI_GUID CertType; 56 | # /// 57 | # /// The following is the certificate data. The format of 58 | # /// the data is determined by the CertType. 59 | # /// If CertType is EFI_CERT_TYPE_RSA2048_SHA256_GUID, 60 | # /// the CertData will be EFI_CERT_BLOCK_RSA_2048_SHA256 structure. 61 | # /// 62 | # UINT8 CertData[1]; 63 | # } WIN_CERTIFICATE_UEFI_GUID; 64 | # 65 | # /// 66 | # /// The WIN_CERTIFICATE structure is part of the PE/COFF specification. 67 | # /// 68 | # typedef struct { 69 | # /// 70 | # /// The length of the entire certificate, 71 | # /// including the length of the header, in bytes. 72 | # /// 73 | # UINT32 dwLength; 74 | # /// 75 | # /// The revision level of the WIN_CERTIFICATE 76 | # /// structure. The current revision level is 0x0200. 77 | # /// 78 | # UINT16 wRevision; 79 | # /// 80 | # /// The certificate type. See WIN_CERT_TYPE_xxx for the UEFI 81 | # /// certificate types. The UEFI specification reserves the range of 82 | # /// certificate type values from 0x0EF0 to 0x0EFF. 83 | # /// 84 | # UINT16 wCertificateType; 85 | # /// 86 | # /// The following is the actual certificate. The format of 87 | # /// the certificate depends on wCertificateType. 88 | # /// 89 | # /// UINT8 bCertificate[ANYSIZE_ARRAY]; 90 | # /// 91 | # } WIN_CERTIFICATE; 92 | # 93 | # #define WIN_CERT_TYPE_EFI_GUID 0x0EF1 94 | # 95 | # /// 96 | # /// This identifies a signature containing a DER-encoded PKCS #7 version 1.5 [RFC2315] 97 | # /// SignedData value. 98 | # /// 99 | # #define EFI_CERT_TYPE_PKCS7_GUID \ 100 | # { \ 101 | # 0x4aafd29d, 0x68df, 0x49ee, {0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7} \ 102 | # } 103 | 104 | _StructFormat = ' 6 | # This program and the accompanying materials 7 | # are licensed and made available under the terms and conditions of the BSD License 8 | # which accompanies this distribution. The full text of the license may be found at 9 | # http://opensource.org/licenses/bsd-license.php 10 | # 11 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 | # 14 | 15 | ''' 16 | FmpCapsuleHeader 17 | ''' 18 | 19 | import struct 20 | import uuid 21 | 22 | class FmpCapsuleImageHeaderClass (object): 23 | # typedef struct { 24 | # UINT32 Version; 25 | # 26 | # /// 27 | # /// Used to identify device firmware targeted by this update. This guid is matched by 28 | # /// system firmware against ImageTypeId field within a EFI_FIRMWARE_IMAGE_DESCRIPTOR 29 | # /// 30 | # EFI_GUID UpdateImageTypeId; 31 | # 32 | # /// 33 | # /// Passed as ImageIndex in call to EFI_FIRMWARE_MANAGEMENT_PROTOCOL.SetImage () 34 | # /// 35 | # UINT8 UpdateImageIndex; 36 | # UINT8 reserved_bytes[3]; 37 | # 38 | # /// 39 | # /// Size of the binary update image which immediately follows this structure 40 | # /// 41 | # UINT32 UpdateImageSize; 42 | # 43 | # /// 44 | # /// Size of the VendorCode bytes which optionally immediately follow binary update image in the capsule 45 | # /// 46 | # UINT32 UpdateVendorCodeSize; 47 | # 48 | # /// 49 | # /// The HardwareInstance to target with this update. If value is zero it means match all 50 | # /// HardwareInstances. This field allows update software to target only a single device in 51 | # /// cases where there are more than one device with the same ImageTypeId GUID. 52 | # /// This header is outside the signed data of the Authentication Info structure and 53 | # /// therefore can be modified without changing the Auth data. 54 | # /// 55 | # UINT64 UpdateHardwareInstance; 56 | # } EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER; 57 | # 58 | # #define EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION 0x00000002 59 | 60 | _StructFormat = ' len (self._EmbeddedDriverList): 178 | raise ValueError 179 | return self._EmbeddedDriverList[Index] 180 | 181 | def AddPayload (self, UpdateImageTypeId, Payload = b'', VendorCodeBytes = b'', HardwareInstance = 0): 182 | self._PayloadList.append ((UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance)) 183 | 184 | def GetFmpCapsuleImageHeader (self, Index): 185 | if Index >= len (self._FmpCapsuleImageHeaderList): 186 | raise ValueError 187 | return self._FmpCapsuleImageHeaderList[Index] 188 | 189 | def Encode (self): 190 | self.EmbeddedDriverCount = len (self._EmbeddedDriverList) 191 | self.PayloadItemCount = len (self._PayloadList) 192 | 193 | FmpCapsuleHeader = struct.pack ( 194 | self._StructFormat, 195 | self.Version, 196 | self.EmbeddedDriverCount, 197 | self.PayloadItemCount 198 | ) 199 | 200 | FmpCapsuleData = b'' 201 | Offset = self._StructSize + (self.EmbeddedDriverCount + self.PayloadItemCount) * self._ItemOffsetSize 202 | for EmbeddedDriver in self._EmbeddedDriverList: 203 | FmpCapsuleData = FmpCapsuleData + EmbeddedDriver 204 | self._ItemOffsetList.append (Offset) 205 | Offset = Offset + len (EmbeddedDriver) 206 | Index = 1 207 | for (UpdateImageTypeId, Payload, VendorCodeBytes, HardwareInstance) in self._PayloadList: 208 | FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () 209 | FmpCapsuleImageHeader.UpdateImageTypeId = UpdateImageTypeId 210 | FmpCapsuleImageHeader.UpdateImageIndex = Index 211 | FmpCapsuleImageHeader.Payload = Payload 212 | FmpCapsuleImageHeader.VendorCodeBytes = VendorCodeBytes 213 | FmpCapsuleImageHeader.UpdateHardwareInstance = HardwareInstance 214 | FmpCapsuleImage = FmpCapsuleImageHeader.Encode () 215 | FmpCapsuleData = FmpCapsuleData + FmpCapsuleImage 216 | 217 | self._ItemOffsetList.append (Offset) 218 | self._FmpCapsuleImageHeaderList.append (FmpCapsuleImageHeader) 219 | 220 | Offset = Offset + len (FmpCapsuleImage) 221 | Index = Index + 1 222 | 223 | for Offset in self._ItemOffsetList: 224 | FmpCapsuleHeader = FmpCapsuleHeader + struct.pack (self._ItemOffsetFormat, Offset) 225 | 226 | self._Valid = True 227 | return FmpCapsuleHeader + FmpCapsuleData 228 | 229 | def Decode (self, Buffer): 230 | if len (Buffer) < self._StructSize: 231 | raise ValueError 232 | (Version, EmbeddedDriverCount, PayloadItemCount) = \ 233 | struct.unpack ( 234 | self._StructFormat, 235 | Buffer[0:self._StructSize] 236 | ) 237 | if Version < self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION: 238 | raise ValueError 239 | 240 | self.Version = Version 241 | self.EmbeddedDriverCount = EmbeddedDriverCount 242 | self.PayloadItemCount = PayloadItemCount 243 | self._ItemOffsetList = [] 244 | self._EmbeddedDriverList = [] 245 | self._PayloadList = [] 246 | self._FmpCapsuleImageHeaderList = [] 247 | 248 | # 249 | # Parse the ItemOffsetList values 250 | # 251 | Offset = self._StructSize 252 | for Index in range (0, EmbeddedDriverCount + PayloadItemCount): 253 | ItemOffset = struct.unpack (self._ItemOffsetFormat, Buffer[Offset:Offset + self._ItemOffsetSize])[0] 254 | if ItemOffset >= len (Buffer): 255 | raise ValueError 256 | self._ItemOffsetList.append (ItemOffset) 257 | Offset = Offset + self._ItemOffsetSize 258 | Result = Buffer[Offset:] 259 | 260 | # 261 | # Parse the EmbeddedDrivers 262 | # 263 | for Index in range (0, EmbeddedDriverCount): 264 | Offset = self._ItemOffsetList[Index] 265 | if Index < (len (self._ItemOffsetList) - 1): 266 | Length = self._ItemOffsetList[Index + 1] - Offset 267 | else: 268 | Length = len (Buffer) - Offset 269 | self.AddEmbeddedDriver (Buffer[Offset:Offset + Length]) 270 | 271 | # 272 | # Parse the Payloads that are FMP Capsule Images 273 | # 274 | for Index in range (EmbeddedDriverCount, EmbeddedDriverCount + PayloadItemCount): 275 | Offset = self._ItemOffsetList[Index] 276 | if Index < (len (self._ItemOffsetList) - 1): 277 | Length = self._ItemOffsetList[Index + 1] - Offset 278 | else: 279 | Length = len (Buffer) - Offset 280 | FmpCapsuleImageHeader = FmpCapsuleImageHeaderClass () 281 | FmpCapsuleImageHeader.Decode (Buffer[Offset:Offset + Length]) 282 | self.AddPayload ( 283 | FmpCapsuleImageHeader.UpdateImageTypeId, 284 | FmpCapsuleImageHeader.Payload, 285 | FmpCapsuleImageHeader.VendorCodeBytes 286 | ) 287 | self._FmpCapsuleImageHeaderList.append (FmpCapsuleImageHeader) 288 | 289 | self._Valid = True 290 | return Result 291 | 292 | def DumpInfo (self): 293 | if not self._Valid: 294 | raise ValueError 295 | print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.Version = {Version:08X}'.format (Version = self.Version)) 296 | print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.EmbeddedDriverCount = {EmbeddedDriverCount:08X}'.format (EmbeddedDriverCount = self.EmbeddedDriverCount)) 297 | print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.PayloadItemCount = {PayloadItemCount:08X}'.format (PayloadItemCount = self.PayloadItemCount)) 298 | print ('EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER.ItemOffsetList = ') 299 | for Offset in self._ItemOffsetList: 300 | print (' {Offset:016X}'.format (Offset = Offset)) 301 | for FmpCapsuleImageHeader in self._FmpCapsuleImageHeaderList: 302 | FmpCapsuleImageHeader.DumpInfo () 303 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/Common/Uefi/Capsule/UefiCapsuleHeader.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Module that encodes and decodes a EFI_CAPSULE_HEADER with a payload 3 | # 4 | # Copyright (c) 2018, Intel Corporation. All rights reserved.
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 9 | # 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. 12 | # 13 | 14 | ''' 15 | UefiCapsuleHeader 16 | ''' 17 | 18 | import struct 19 | import uuid 20 | 21 | class UefiCapsuleHeaderClass (object): 22 | # typedef struct { 23 | # /// 24 | # /// A GUID that defines the contents of a capsule. 25 | # /// 26 | # EFI_GUID CapsuleGuid; 27 | # /// 28 | # /// The size of the capsule header. This may be larger than the size of 29 | # /// the EFI_CAPSULE_HEADER since CapsuleGuid may imply 30 | # /// extended header entries 31 | # /// 32 | # UINT32 HeaderSize; 33 | # /// 34 | # /// Bit-mapped list describing the capsule attributes. The Flag values 35 | # /// of 0x0000 - 0xFFFF are defined by CapsuleGuid. Flag values 36 | # /// of 0x10000 - 0xFFFFFFFF are defined by this specification 37 | # /// 38 | # UINT32 Flags; 39 | # /// 40 | # /// Size in bytes of the capsule. 41 | # /// 42 | # UINT32 CapsuleImageSize; 43 | # } EFI_CAPSULE_HEADER; 44 | # 45 | # #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 46 | # #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 47 | # #define CAPSULE_FLAGS_INITIATE_RESET 0x00040000 48 | # 49 | _StructFormat = '<16sIIII' 50 | _StructSize = struct.calcsize (_StructFormat) 51 | 52 | EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID = uuid.UUID ('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A') 53 | 54 | _CAPSULE_FLAGS_PERSIST_ACROSS_RESET = 0x00010000 55 | _CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE = 0x00020000 56 | _CAPSULE_FLAGS_INITIATE_RESET = 0x00040000 57 | 58 | def __init__ (self): 59 | self._Valid = False 60 | self.CapsuleGuid = self.EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID 61 | self.HeaderSize = self._StructSize 62 | self.OemFlags = 0x0000 63 | self.PersistAcrossReset = False 64 | self.PopulateSystemTable = False 65 | self.InitiateReset = False 66 | self.CapsuleImageSize = self.HeaderSize 67 | self.Payload = b'' 68 | 69 | def Encode (self): 70 | Flags = self.OemFlags 71 | if self.PersistAcrossReset: 72 | Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET 73 | if self.PopulateSystemTable: 74 | Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 75 | if self.InitiateReset: 76 | Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET 77 | 78 | self.CapsuleImageSize = self.HeaderSize + len (self.Payload) 79 | 80 | UefiCapsuleHeader = struct.pack ( 81 | self._StructFormat, 82 | self.CapsuleGuid.bytes_le, 83 | self.HeaderSize, 84 | Flags, 85 | self.CapsuleImageSize, 86 | 0 87 | ) 88 | self._Valid = True 89 | return UefiCapsuleHeader + self.Payload 90 | 91 | def Decode (self, Buffer): 92 | if len (Buffer) < self._StructSize: 93 | raise ValueError 94 | (CapsuleGuid, HeaderSize, Flags, CapsuleImageSize, Reserved) = \ 95 | struct.unpack ( 96 | self._StructFormat, 97 | Buffer[0:self._StructSize] 98 | ) 99 | if HeaderSize < self._StructSize: 100 | raise ValueError 101 | if CapsuleImageSize != len (Buffer): 102 | raise ValueError 103 | self.CapsuleGuid = uuid.UUID (bytes_le = CapsuleGuid) 104 | self.HeaderSize = HeaderSize 105 | self.OemFlags = Flags & 0xffff 106 | self.PersistAcrossReset = (Flags & self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0 107 | self.PopulateSystemTable = (Flags & self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 108 | self.InitiateReset = (Flags & self._CAPSULE_FLAGS_INITIATE_RESET) != 0 109 | self.CapsuleImageSize = CapsuleImageSize 110 | self.Payload = Buffer[self.HeaderSize:] 111 | 112 | self._Valid = True 113 | return self.Payload 114 | 115 | def DumpInfo (self): 116 | if not self._Valid: 117 | raise ValueError 118 | Flags = self.OemFlags 119 | if self.PersistAcrossReset: 120 | Flags = Flags | self._CAPSULE_FLAGS_PERSIST_ACROSS_RESET 121 | if self.PopulateSystemTable: 122 | Flags = Flags | self._CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 123 | if self.InitiateReset: 124 | Flags = Flags | self._CAPSULE_FLAGS_INITIATE_RESET 125 | print ('EFI_CAPSULE_HEADER.CapsuleGuid = {Guid}'.format (Guid = str(self.CapsuleGuid).upper())) 126 | print ('EFI_CAPSULE_HEADER.HeaderSize = {Size:08X}'.format (Size = self.HeaderSize)) 127 | print ('EFI_CAPSULE_HEADER.Flags = {Flags:08X}'.format (Flags = Flags)) 128 | print (' OEM Flags = {Flags:04X}'.format (Flags = self.OemFlags)) 129 | if self.PersistAcrossReset: 130 | print (' CAPSULE_FLAGS_PERSIST_ACROSS_RESET') 131 | if self.PopulateSystemTable: 132 | print (' CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE') 133 | if self.InitiateReset: 134 | print (' CAPSULE_FLAGS_INITIATE_RESET') 135 | print ('EFI_CAPSULE_HEADER.CapsuleImageSize = {Size:08X}'.format (Size = self.CapsuleImageSize)) 136 | print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload))) 137 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/Common/Uefi/Capsule/__init__.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Python 'Common.Uefi.Capsule' package initialization file. 3 | # 4 | # This file is required to make Python interpreter treat the directory 5 | # as containing package. 6 | # 7 | # Copyright (c) 2018, Intel Corporation. All rights reserved.
8 | # This program and the accompanying materials 9 | # are licensed and made available under the terms and conditions of the BSD License 10 | # which accompanies this distribution. The full text of the license may be found at 11 | # http://opensource.org/licenses/bsd-license.php 12 | # 13 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 | # 16 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/Common/Uefi/__init__.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Python 'Common.Uefi' package initialization file. 3 | # 4 | # This file is required to make Python interpreter treat the directory 5 | # as containing package. 6 | # 7 | # Copyright (c) 2018, Intel Corporation. All rights reserved.
8 | # This program and the accompanying materials 9 | # are licensed and made available under the terms and conditions of the BSD License 10 | # which accompanies this distribution. The full text of the license may be found at 11 | # http://opensource.org/licenses/bsd-license.php 12 | # 13 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 | # 16 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/Common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/edk2_capsule_tool/Common/__init__.py -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/CommonDataClass/DataClass.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # This file is used to define class for data structure used in ECC 3 | # 4 | # Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.
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 9 | # 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. 12 | 13 | ## 14 | # Import Modules 15 | # 16 | import Common.EdkLogger as EdkLogger 17 | 18 | ## 19 | # Static values for data models 20 | # 21 | MODEL_UNKNOWN = 0 22 | 23 | MODEL_FILE_C = 1001 24 | MODEL_FILE_H = 1002 25 | MODEL_FILE_ASM = 1003 26 | MODEL_FILE_INF = 1011 27 | MODEL_FILE_DEC = 1012 28 | MODEL_FILE_DSC = 1013 29 | MODEL_FILE_FDF = 1014 30 | MODEL_FILE_INC = 1015 31 | MODEL_FILE_CIF = 1016 32 | MODEL_FILE_UNI = 1017 33 | MODEL_FILE_OTHERS = 1099 34 | 35 | MODEL_IDENTIFIER_FILE_HEADER = 2001 36 | MODEL_IDENTIFIER_FUNCTION_HEADER = 2002 37 | MODEL_IDENTIFIER_COMMENT = 2003 38 | MODEL_IDENTIFIER_PARAMETER = 2004 39 | MODEL_IDENTIFIER_STRUCTURE = 2005 40 | MODEL_IDENTIFIER_VARIABLE = 2006 41 | MODEL_IDENTIFIER_INCLUDE = 2007 42 | MODEL_IDENTIFIER_PREDICATE_EXPRESSION = 2008 43 | MODEL_IDENTIFIER_ENUMERATE = 2009 44 | MODEL_IDENTIFIER_PCD = 2010 45 | MODEL_IDENTIFIER_UNION = 2011 46 | MODEL_IDENTIFIER_MACRO_IFDEF = 2012 47 | MODEL_IDENTIFIER_MACRO_IFNDEF = 2013 48 | MODEL_IDENTIFIER_MACRO_DEFINE = 2014 49 | MODEL_IDENTIFIER_MACRO_ENDIF = 2015 50 | MODEL_IDENTIFIER_MACRO_PROGMA = 2016 51 | MODEL_IDENTIFIER_FUNCTION_CALLING = 2018 52 | MODEL_IDENTIFIER_TYPEDEF = 2017 53 | MODEL_IDENTIFIER_FUNCTION_DECLARATION = 2019 54 | MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION = 2020 55 | 56 | MODEL_EFI_PROTOCOL = 3001 57 | MODEL_EFI_PPI = 3002 58 | MODEL_EFI_GUID = 3003 59 | MODEL_EFI_LIBRARY_CLASS = 3004 60 | MODEL_EFI_LIBRARY_INSTANCE = 3005 61 | MODEL_EFI_PCD = 3006 62 | MODEL_EFI_SOURCE_FILE = 3007 63 | MODEL_EFI_BINARY_FILE = 3008 64 | MODEL_EFI_SKU_ID = 3009 65 | MODEL_EFI_INCLUDE = 3010 66 | MODEL_EFI_DEPEX = 3011 67 | MODEL_EFI_DEFAULT_STORES = 3012 68 | 69 | MODEL_PCD = 4000 70 | MODEL_PCD_FIXED_AT_BUILD = 4001 71 | MODEL_PCD_PATCHABLE_IN_MODULE = 4002 72 | MODEL_PCD_FEATURE_FLAG = 4003 73 | MODEL_PCD_DYNAMIC_EX = 4004 74 | MODEL_PCD_DYNAMIC_EX_DEFAULT = 4005 75 | MODEL_PCD_DYNAMIC_EX_VPD = 4006 76 | MODEL_PCD_DYNAMIC_EX_HII = 4007 77 | MODEL_PCD_DYNAMIC = 4008 78 | MODEL_PCD_DYNAMIC_DEFAULT = 4009 79 | MODEL_PCD_DYNAMIC_VPD = 4010 80 | MODEL_PCD_DYNAMIC_HII = 4011 81 | MODEL_PCD_TYPE_LIST = [MODEL_PCD_FIXED_AT_BUILD, 82 | MODEL_PCD_PATCHABLE_IN_MODULE, 83 | MODEL_PCD_FEATURE_FLAG, 84 | MODEL_PCD_DYNAMIC_DEFAULT, 85 | MODEL_PCD_DYNAMIC_HII, 86 | MODEL_PCD_DYNAMIC_VPD, 87 | MODEL_PCD_DYNAMIC_EX_DEFAULT, 88 | MODEL_PCD_DYNAMIC_EX_HII, 89 | MODEL_PCD_DYNAMIC_EX_VPD 90 | ] 91 | 92 | MODEL_META_DATA_HEADER_COMMENT = 5000 93 | MODEL_META_DATA_HEADER = 5001 94 | MODEL_META_DATA_INCLUDE = 5002 95 | MODEL_META_DATA_DEFINE = 5003 96 | MODEL_META_DATA_CONDITIONAL_STATEMENT_IF = 5004 97 | MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE = 5005 98 | MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF = 5006 99 | MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF = 5007 100 | MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR = 5400 101 | MODEL_META_DATA_BUILD_OPTION = 5008 102 | MODEL_META_DATA_COMPONENT = 5009 103 | MODEL_META_DATA_USER_EXTENSION = 5010 104 | MODEL_META_DATA_PACKAGE = 5011 105 | MODEL_META_DATA_NMAKE = 5012 106 | MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSEIF = 5013 107 | MODEL_META_DATA_CONDITIONAL_STATEMENT_ENDIF = 5014 108 | MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH = 5015 109 | MODEL_META_DATA_COMMENT = 5016 110 | MODEL_META_DATA_GLOBAL_DEFINE = 5017 111 | MODEL_META_DATA_SECTION_HEADER = 5100 112 | MODEL_META_DATA_SUBSECTION_HEADER = 5200 113 | MODEL_META_DATA_TAIL_COMMENT = 5300 114 | 115 | MODEL_EXTERNAL_DEPENDENCY = 10000 116 | 117 | MODEL_LIST = [('MODEL_UNKNOWN', MODEL_UNKNOWN), 118 | ('MODEL_FILE_C', MODEL_FILE_C), 119 | ('MODEL_FILE_H', MODEL_FILE_H), 120 | ('MODEL_FILE_ASM', MODEL_FILE_ASM), 121 | ('MODEL_FILE_INF', MODEL_FILE_INF), 122 | ('MODEL_FILE_DEC', MODEL_FILE_DEC), 123 | ('MODEL_FILE_DSC', MODEL_FILE_DSC), 124 | ('MODEL_FILE_FDF', MODEL_FILE_FDF), 125 | ('MODEL_FILE_INC', MODEL_FILE_INC), 126 | ('MODEL_FILE_CIF', MODEL_FILE_CIF), 127 | ('MODEL_FILE_OTHERS', MODEL_FILE_OTHERS), 128 | ('MODEL_IDENTIFIER_FILE_HEADER', MODEL_IDENTIFIER_FILE_HEADER), 129 | ('MODEL_IDENTIFIER_FUNCTION_HEADER', MODEL_IDENTIFIER_FUNCTION_HEADER), 130 | ('MODEL_IDENTIFIER_COMMENT', MODEL_IDENTIFIER_COMMENT), 131 | ('MODEL_IDENTIFIER_PARAMETER', MODEL_IDENTIFIER_PARAMETER), 132 | ('MODEL_IDENTIFIER_STRUCTURE', MODEL_IDENTIFIER_STRUCTURE), 133 | ('MODEL_IDENTIFIER_VARIABLE', MODEL_IDENTIFIER_VARIABLE), 134 | ('MODEL_IDENTIFIER_INCLUDE', MODEL_IDENTIFIER_INCLUDE), 135 | ('MODEL_IDENTIFIER_PREDICATE_EXPRESSION', MODEL_IDENTIFIER_PREDICATE_EXPRESSION), 136 | ('MODEL_IDENTIFIER_ENUMERATE', MODEL_IDENTIFIER_ENUMERATE), 137 | ('MODEL_IDENTIFIER_PCD', MODEL_IDENTIFIER_PCD), 138 | ('MODEL_IDENTIFIER_UNION', MODEL_IDENTIFIER_UNION), 139 | ('MODEL_IDENTIFIER_MACRO_IFDEF', MODEL_IDENTIFIER_MACRO_IFDEF), 140 | ('MODEL_IDENTIFIER_MACRO_IFNDEF', MODEL_IDENTIFIER_MACRO_IFNDEF), 141 | ('MODEL_IDENTIFIER_MACRO_DEFINE', MODEL_IDENTIFIER_MACRO_DEFINE), 142 | ('MODEL_IDENTIFIER_MACRO_ENDIF', MODEL_IDENTIFIER_MACRO_ENDIF), 143 | ('MODEL_IDENTIFIER_MACRO_PROGMA', MODEL_IDENTIFIER_MACRO_PROGMA), 144 | ('MODEL_IDENTIFIER_FUNCTION_CALLING', MODEL_IDENTIFIER_FUNCTION_CALLING), 145 | ('MODEL_IDENTIFIER_TYPEDEF', MODEL_IDENTIFIER_TYPEDEF), 146 | ('MODEL_IDENTIFIER_FUNCTION_DECLARATION', MODEL_IDENTIFIER_FUNCTION_DECLARATION), 147 | ('MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION', MODEL_IDENTIFIER_ASSIGNMENT_EXPRESSION), 148 | ('MODEL_EFI_PROTOCOL', MODEL_EFI_PROTOCOL), 149 | ('MODEL_EFI_PPI', MODEL_EFI_PPI), 150 | ('MODEL_EFI_GUID', MODEL_EFI_GUID), 151 | ('MODEL_EFI_LIBRARY_CLASS', MODEL_EFI_LIBRARY_CLASS), 152 | ('MODEL_EFI_LIBRARY_INSTANCE', MODEL_EFI_LIBRARY_INSTANCE), 153 | ('MODEL_EFI_PCD', MODEL_EFI_PCD), 154 | ('MODEL_EFI_SKU_ID', MODEL_EFI_SKU_ID), 155 | ('MODEL_EFI_INCLUDE', MODEL_EFI_INCLUDE), 156 | ('MODEL_EFI_DEPEX', MODEL_EFI_DEPEX), 157 | ('MODEL_IDENTIFIER_UNION', MODEL_IDENTIFIER_UNION), 158 | ('MODEL_EFI_SOURCE_FILE', MODEL_EFI_SOURCE_FILE), 159 | ('MODEL_EFI_BINARY_FILE', MODEL_EFI_BINARY_FILE), 160 | ('MODEL_PCD', MODEL_PCD), 161 | ('MODEL_PCD_FIXED_AT_BUILD', MODEL_PCD_FIXED_AT_BUILD), 162 | ('MODEL_PCD_PATCHABLE_IN_MODULE', MODEL_PCD_PATCHABLE_IN_MODULE), 163 | ('MODEL_PCD_FEATURE_FLAG', MODEL_PCD_FEATURE_FLAG), 164 | ('MODEL_PCD_DYNAMIC_EX', MODEL_PCD_DYNAMIC_EX), 165 | ('MODEL_PCD_DYNAMIC_EX_DEFAULT', MODEL_PCD_DYNAMIC_EX_DEFAULT), 166 | ('MODEL_PCD_DYNAMIC_EX_VPD', MODEL_PCD_DYNAMIC_EX_VPD), 167 | ('MODEL_PCD_DYNAMIC_EX_HII', MODEL_PCD_DYNAMIC_EX_HII), 168 | ('MODEL_PCD_DYNAMIC', MODEL_PCD_DYNAMIC), 169 | ('MODEL_PCD_DYNAMIC_DEFAULT', MODEL_PCD_DYNAMIC_DEFAULT), 170 | ('MODEL_PCD_DYNAMIC_VPD', MODEL_PCD_DYNAMIC_VPD), 171 | ('MODEL_PCD_DYNAMIC_HII', MODEL_PCD_DYNAMIC_HII), 172 | ("MODEL_META_DATA_HEADER", MODEL_META_DATA_HEADER), 173 | ("MODEL_META_DATA_INCLUDE", MODEL_META_DATA_INCLUDE), 174 | ("MODEL_META_DATA_DEFINE", MODEL_META_DATA_DEFINE), 175 | ("MODEL_META_DATA_CONDITIONAL_STATEMENT_IF", MODEL_META_DATA_CONDITIONAL_STATEMENT_IF), 176 | ("MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE", MODEL_META_DATA_CONDITIONAL_STATEMENT_ELSE), 177 | ("MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF", MODEL_META_DATA_CONDITIONAL_STATEMENT_IFDEF), 178 | ("MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF", MODEL_META_DATA_CONDITIONAL_STATEMENT_IFNDEF), 179 | ("MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR", MODEL_META_DATA_CONDITIONAL_STATEMENT_ERROR), 180 | ("MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH", MODEL_META_DATA_COMPONENT_SOURCE_OVERRIDE_PATH), 181 | ("MODEL_META_DATA_BUILD_OPTION", MODEL_META_DATA_BUILD_OPTION), 182 | ("MODEL_META_DATA_COMPONENT", MODEL_META_DATA_COMPONENT), 183 | ('MODEL_META_DATA_USER_EXTENSION', MODEL_META_DATA_USER_EXTENSION), 184 | ('MODEL_META_DATA_PACKAGE', MODEL_META_DATA_PACKAGE), 185 | ('MODEL_META_DATA_NMAKE', MODEL_META_DATA_NMAKE), 186 | ('MODEL_META_DATA_COMMENT', MODEL_META_DATA_COMMENT) 187 | ] 188 | 189 | ## FunctionClass 190 | # 191 | # This class defines a structure of a function 192 | # 193 | # @param ID: ID of a Function 194 | # @param Header: Header of a Function 195 | # @param Modifier: Modifier of a Function 196 | # @param Name: Name of a Function 197 | # @param ReturnStatement: ReturnStatement of a Funciont 198 | # @param StartLine: StartLine of a Function 199 | # @param StartColumn: StartColumn of a Function 200 | # @param EndLine: EndLine of a Function 201 | # @param EndColumn: EndColumn of a Function 202 | # @param BodyStartLine: BodyStartLine of a Function Body 203 | # @param BodyStartColumn: BodyStartColumn of a Function Body 204 | # @param BelongsToFile: The Function belongs to which file 205 | # @param IdentifierList: IdentifierList of a File 206 | # @param PcdList: PcdList of a File 207 | # 208 | # @var ID: ID of a Function 209 | # @var Header: Header of a Function 210 | # @var Modifier: Modifier of a Function 211 | # @var Name: Name of a Function 212 | # @var ReturnStatement: ReturnStatement of a Funciont 213 | # @var StartLine: StartLine of a Function 214 | # @var StartColumn: StartColumn of a Function 215 | # @var EndLine: EndLine of a Function 216 | # @var EndColumn: EndColumn of a Function 217 | # @var BodyStartLine: StartLine of a Function Body 218 | # @var BodyStartColumn: StartColumn of a Function Body 219 | # @var BelongsToFile: The Function belongs to which file 220 | # @var IdentifierList: IdentifierList of a File 221 | # @var PcdList: PcdList of a File 222 | # 223 | class FunctionClass(object): 224 | def __init__(self, ID = -1, Header = '', Modifier = '', Name = '', ReturnStatement = '', \ 225 | StartLine = -1, StartColumn = -1, EndLine = -1, EndColumn = -1, \ 226 | BodyStartLine = -1, BodyStartColumn = -1, BelongsToFile = -1, \ 227 | IdentifierList = [], PcdList = [], \ 228 | FunNameStartLine = -1, FunNameStartColumn = -1): 229 | self.ID = ID 230 | self.Header = Header 231 | self.Modifier = Modifier 232 | self.Name = Name 233 | self.ReturnStatement = ReturnStatement 234 | self.StartLine = StartLine 235 | self.StartColumn = StartColumn 236 | self.EndLine = EndLine 237 | self.EndColumn = EndColumn 238 | self.BodyStartLine = BodyStartLine 239 | self.BodyStartColumn = BodyStartColumn 240 | self.BelongsToFile = BelongsToFile 241 | self.FunNameStartLine = FunNameStartLine 242 | self.FunNameStartColumn = FunNameStartColumn 243 | 244 | self.IdentifierList = IdentifierList 245 | self.PcdList = PcdList 246 | 247 | ## IdentifierClass 248 | # 249 | # This class defines a structure of a variable 250 | # 251 | # @param ID: ID of a Identifier 252 | # @param Modifier: Modifier of a Identifier 253 | # @param Type: Type of a Identifier 254 | # @param Name: Name of a Identifier 255 | # @param Value: Value of a Identifier 256 | # @param Model: Model of a Identifier 257 | # @param BelongsToFile: The Identifier belongs to which file 258 | # @param BelongsToFunction: The Identifier belongs to which function 259 | # @param StartLine: StartLine of a Identifier 260 | # @param StartColumn: StartColumn of a Identifier 261 | # @param EndLine: EndLine of a Identifier 262 | # @param EndColumn: EndColumn of a Identifier 263 | # 264 | # @var ID: ID of a Identifier 265 | # @var Modifier: Modifier of a Identifier 266 | # @var Type: Type of a Identifier 267 | # @var Name: Name of a Identifier 268 | # @var Value: Value of a Identifier 269 | # @var Model: Model of a Identifier 270 | # @var BelongsToFile: The Identifier belongs to which file 271 | # @var BelongsToFunction: The Identifier belongs to which function 272 | # @var StartLine: StartLine of a Identifier 273 | # @var StartColumn: StartColumn of a Identifier 274 | # @var EndLine: EndLine of a Identifier 275 | # @var EndColumn: EndColumn of a Identifier 276 | # 277 | class IdentifierClass(object): 278 | def __init__(self, ID = -1, Modifier = '', Type = '', Name = '', Value = '', Model = MODEL_UNKNOWN, \ 279 | BelongsToFile = -1, BelongsToFunction = -1, StartLine = -1, StartColumn = -1, EndLine = -1, EndColumn = -1): 280 | self.ID = ID 281 | self.Modifier = Modifier 282 | self.Type = Type 283 | self.Name = Name 284 | self.Value = Value 285 | self.Model = Model 286 | self.BelongsToFile = BelongsToFile 287 | self.BelongsToFunction = BelongsToFunction 288 | self.StartLine = StartLine 289 | self.StartColumn = StartColumn 290 | self.EndLine = EndLine 291 | self.EndColumn = EndColumn 292 | 293 | ## PcdClass 294 | # 295 | # This class defines a structure of a Pcd 296 | # 297 | # @param ID: ID of a Pcd 298 | # @param CName: CName of a Pcd 299 | # @param TokenSpaceGuidCName: TokenSpaceGuidCName of a Pcd 300 | # @param Token: Token of a Pcd 301 | # @param DatumType: DatumType of a Pcd 302 | # @param Model: Model of a Pcd 303 | # @param BelongsToFile: The Pcd belongs to which file 304 | # @param BelongsToFunction: The Pcd belongs to which function 305 | # @param StartLine: StartLine of a Pcd 306 | # @param StartColumn: StartColumn of a Pcd 307 | # @param EndLine: EndLine of a Pcd 308 | # @param EndColumn: EndColumn of a Pcd 309 | # 310 | # @var ID: ID of a Pcd 311 | # @var CName: CName of a Pcd 312 | # @var TokenSpaceGuidCName: TokenSpaceGuidCName of a Pcd 313 | # @var Token: Token of a Pcd 314 | # @var DatumType: DatumType of a Pcd 315 | # @var Model: Model of a Pcd 316 | # @var BelongsToFile: The Pcd belongs to which file 317 | # @var BelongsToFunction: The Pcd belongs to which function 318 | # @var StartLine: StartLine of a Pcd 319 | # @var StartColumn: StartColumn of a Pcd 320 | # @var EndLine: EndLine of a Pcd 321 | # @var EndColumn: EndColumn of a Pcd 322 | # 323 | class PcdDataClass(object): 324 | def __init__(self, ID = -1, CName = '', TokenSpaceGuidCName = '', Token = '', DatumType = '', Model = MODEL_UNKNOWN, \ 325 | BelongsToFile = -1, BelongsToFunction = -1, StartLine = -1, StartColumn = -1, EndLine = -1, EndColumn = -1): 326 | self.ID = ID 327 | self.CName = CName 328 | self.TokenSpaceGuidCName = TokenSpaceGuidCName 329 | self.Token = Token 330 | self.DatumType = DatumType 331 | self.BelongsToFile = BelongsToFile 332 | self.BelongsToFunction = BelongsToFunction 333 | self.StartLine = StartLine 334 | self.StartColumn = StartColumn 335 | self.EndLine = EndLine 336 | self.EndColumn = EndColumn 337 | 338 | ## FileClass 339 | # 340 | # This class defines a structure of a file 341 | # 342 | # @param ID: ID of a File 343 | # @param Name: Name of a File 344 | # @param ExtName: ExtName of a File 345 | # @param Path: Path of a File 346 | # @param FullPath: FullPath of a File 347 | # @param Model: Model of a File 348 | # @param TimeStamp: TimeStamp of a File 349 | # @param FunctionList: FunctionList of a File 350 | # @param IdentifierList: IdentifierList of a File 351 | # @param PcdList: PcdList of a File 352 | # 353 | # @var ID: ID of a File 354 | # @var Name: Name of a File 355 | # @var ExtName: ExtName of a File 356 | # @var Path: Path of a File 357 | # @var FullPath: FullPath of a File 358 | # @var Model: Model of a File 359 | # @var TimeStamp: TimeStamp of a File 360 | # @var FunctionList: FunctionList of a File 361 | # @var IdentifierList: IdentifierList of a File 362 | # @var PcdList: PcdList of a File 363 | # 364 | class FileClass(object): 365 | def __init__(self, ID = -1, Name = '', ExtName = '', Path = '', FullPath = '', Model = MODEL_UNKNOWN, TimeStamp = '', \ 366 | FunctionList = [], IdentifierList = [], PcdList = []): 367 | self.ID = ID 368 | self.Name = Name 369 | self.ExtName = ExtName 370 | self.Path = Path 371 | self.FullPath = FullPath 372 | self.Model = Model 373 | self.TimeStamp = TimeStamp 374 | 375 | self.FunctionList = FunctionList 376 | self.IdentifierList = IdentifierList 377 | self.PcdList = PcdList 378 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/CommonDataClass/Exceptions.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # This file is used to define common Exceptions class used in python tools 3 | # 4 | # Copyright (c) 2011, Intel Corporation. All rights reserved.
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 9 | # 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. 12 | 13 | ## Exceptions used in Expression 14 | class EvaluationException(Exception): 15 | pass 16 | 17 | class BadExpression(EvaluationException): 18 | pass 19 | 20 | class WrnExpression(Exception): 21 | pass 22 | 23 | ## Exceptions used in macro replacements 24 | class MacroException(Exception): 25 | pass 26 | 27 | class SymbolNotFound(MacroException): 28 | pass 29 | 30 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/CommonDataClass/FdfClass.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # classes represent data in FDF 3 | # 4 | # Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.
5 | # 6 | # This program and the accompanying materials 7 | # are licensed and made available under the terms and conditions of the BSD License 8 | # which accompanies this distribution. The full text of the license may be found at 9 | # http://opensource.org/licenses/bsd-license.php 10 | # 11 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 | # 14 | 15 | ## FD data in FDF 16 | # 17 | # 18 | class FDClassObject: 19 | ## The constructor 20 | # 21 | # @param self The object pointer 22 | # 23 | def __init__(self): 24 | self.FdUiName = '' 25 | self.CreateFileName = None 26 | self.BaseAddress = None 27 | self.BaseAddressPcd = None 28 | self.Size = None 29 | self.SizePcd = None 30 | self.ErasePolarity = None 31 | # 3-tuple list (blockSize, numBlocks, pcd) 32 | self.BlockSizeList = [] 33 | # DefineVarDict[var] = value 34 | self.DefineVarDict = {} 35 | # SetVarDict[var] = value 36 | self.SetVarDict = {} 37 | self.RegionList = [] 38 | self.vtfRawDict = {} 39 | 40 | ## FV data in FDF 41 | # 42 | # 43 | class FvClassObject: 44 | ## The constructor 45 | # 46 | # @param self The object pointer 47 | # 48 | def __init__(self): 49 | self.UiFvName = None 50 | self.CreateFileName = None 51 | # 3-tuple list (blockSize, numBlocks, pcd) 52 | self.BlockSizeList = [] 53 | # DefineVarDict[var] = value 54 | self.DefineVarDict = {} 55 | # SetVarDict[var] = value 56 | self.SetVarDict = {} 57 | self.FvAlignment = None 58 | # FvAttributeDict[attribute] = TRUE/FALSE (1/0) 59 | self.FvAttributeDict = {} 60 | self.FvNameGuid = None 61 | self.FvNameString = None 62 | self.AprioriSectionList = [] 63 | self.FfsList = [] 64 | self.BsBaseAddress = None 65 | self.RtBaseAddress = None 66 | 67 | ## Region data in FDF 68 | # 69 | # 70 | class RegionClassObject: 71 | ## The constructor 72 | # 73 | # @param self The object pointer 74 | # 75 | def __init__(self): 76 | self.Offset = None # The begin position of the Region 77 | self.Size = None # The Size of the Region 78 | self.PcdOffset = None 79 | self.PcdSize = None 80 | self.SetVarDict = {} 81 | self.RegionType = None 82 | self.RegionDataList = [] 83 | 84 | ## FFS data in FDF 85 | # 86 | # 87 | class FfsClassObject: 88 | ## The constructor 89 | # 90 | # @param self The object pointer 91 | # 92 | def __init__(self): 93 | self.NameGuid = None 94 | self.Fixed = False 95 | self.CheckSum = False 96 | self.Alignment = None 97 | self.SectionList = [] 98 | 99 | ## FILE statement data in FDF 100 | # 101 | # 102 | class FileStatementClassObject (FfsClassObject) : 103 | ## The constructor 104 | # 105 | # @param self The object pointer 106 | # 107 | def __init__(self): 108 | FfsClassObject.__init__(self) 109 | self.FvFileType = None 110 | self.FileName = None 111 | self.KeyStringList = [] 112 | self.FvName = None 113 | self.FdName = None 114 | self.DefineVarDict = {} 115 | self.AprioriSection = None 116 | self.KeepReloc = None 117 | 118 | ## INF statement data in FDF 119 | # 120 | # 121 | class FfsInfStatementClassObject(FfsClassObject): 122 | ## The constructor 123 | # 124 | # @param self The object pointer 125 | # 126 | def __init__(self): 127 | FfsClassObject.__init__(self) 128 | self.Rule = None 129 | self.Version = None 130 | self.Ui = None 131 | self.InfFileName = None 132 | self.BuildNum = '' 133 | self.KeyStringList = [] 134 | self.KeepReloc = None 135 | self.UseArch = None 136 | 137 | ## APRIORI section data in FDF 138 | # 139 | # 140 | class AprioriSectionClassObject: 141 | ## The constructor 142 | # 143 | # @param self The object pointer 144 | # 145 | def __init__(self): 146 | # DefineVarDict[var] = value 147 | self.DefineVarDict = {} 148 | self.FfsList = [] 149 | 150 | ## section data in FDF 151 | # 152 | # 153 | class SectionClassObject: 154 | ## The constructor 155 | # 156 | # @param self The object pointer 157 | # 158 | def __init__(self): 159 | self.Alignment = None 160 | 161 | ## Depex expression section in FDF 162 | # 163 | # 164 | class DepexSectionClassObject (SectionClassObject): 165 | ## The constructor 166 | # 167 | # @param self The object pointer 168 | # 169 | def __init__(self): 170 | self.DepexType = None 171 | self.Expression = None 172 | self.ExpressionProcessed = False 173 | 174 | ## Compress section data in FDF 175 | # 176 | # 177 | class CompressSectionClassObject (SectionClassObject) : 178 | ## The constructor 179 | # 180 | # @param self The object pointer 181 | # 182 | def __init__(self): 183 | SectionClassObject.__init__(self) 184 | self.CompType = None 185 | self.SectionList = [] 186 | 187 | ## Data section data in FDF 188 | # 189 | # 190 | class DataSectionClassObject (SectionClassObject): 191 | ## The constructor 192 | # 193 | # @param self The object pointer 194 | # 195 | def __init__(self): 196 | SectionClassObject.__init__(self) 197 | self.SecType = None 198 | self.SectFileName = None 199 | self.SectionList = [] 200 | self.KeepReloc = True 201 | 202 | ## Rule section data in FDF 203 | # 204 | # 205 | class EfiSectionClassObject (SectionClassObject): 206 | ## The constructor 207 | # 208 | # @param self The object pointer 209 | # 210 | def __init__(self): 211 | SectionClassObject.__init__(self) 212 | self.SectionType = None 213 | self.Optional = False 214 | self.FileType = None 215 | self.StringData = None 216 | self.FileName = None 217 | self.FileExtension = None 218 | self.BuildNum = None 219 | self.KeepReloc = None 220 | 221 | ## FV image section data in FDF 222 | # 223 | # 224 | class FvImageSectionClassObject (SectionClassObject): 225 | ## The constructor 226 | # 227 | # @param self The object pointer 228 | # 229 | def __init__(self): 230 | SectionClassObject.__init__(self) 231 | self.Fv = None 232 | self.FvName = None 233 | self.FvFileType = None 234 | self.FvFileName = None 235 | self.FvFileExtension = None 236 | self.FvAddr = None 237 | 238 | ## GUIDed section data in FDF 239 | # 240 | # 241 | class GuidSectionClassObject (SectionClassObject) : 242 | ## The constructor 243 | # 244 | # @param self The object pointer 245 | # 246 | def __init__(self): 247 | SectionClassObject.__init__(self) 248 | self.NameGuid = None 249 | self.SectionList = [] 250 | self.SectionType = None 251 | self.ProcessRequired = False 252 | self.AuthStatusValid = False 253 | self.ExtraHeaderSize = -1 254 | self.FvAddr = [] 255 | self.FvParentAddr = None 256 | self.IncludeFvSection = False 257 | 258 | ## UI section data in FDF 259 | # 260 | # 261 | class UiSectionClassObject (SectionClassObject): 262 | ## The constructor 263 | # 264 | # @param self The object pointer 265 | # 266 | def __init__(self): 267 | SectionClassObject.__init__(self) 268 | self.StringData = None 269 | self.FileName = None 270 | 271 | ## Version section data in FDF 272 | # 273 | # 274 | class VerSectionClassObject (SectionClassObject): 275 | ## The constructor 276 | # 277 | # @param self The object pointer 278 | # 279 | def __init__(self): 280 | SectionClassObject.__init__(self) 281 | self.BuildNum = None 282 | self.StringData = None 283 | self.FileName = None 284 | 285 | ## Rule data in FDF 286 | # 287 | # 288 | class RuleClassObject : 289 | ## The constructor 290 | # 291 | # @param self The object pointer 292 | # 293 | def __init__(self): 294 | self.Arch = None 295 | self.ModuleType = None # For Module Type 296 | self.TemplateName = None 297 | self.NameGuid = None 298 | self.Fixed = False 299 | self.Alignment = None 300 | self.SectAlignment = None 301 | self.CheckSum = False 302 | self.FvFileType = None # for Ffs File Type 303 | self.KeyStringList = [] 304 | self.KeepReloc = None 305 | 306 | ## Complex rule data in FDF 307 | # 308 | # 309 | class RuleComplexFileClassObject(RuleClassObject) : 310 | ## The constructor 311 | # 312 | # @param self The object pointer 313 | # 314 | def __init__(self): 315 | RuleClassObject.__init__(self) 316 | self.SectionList = [] 317 | 318 | ## Simple rule data in FDF 319 | # 320 | # 321 | class RuleSimpleFileClassObject(RuleClassObject) : 322 | ## The constructor 323 | # 324 | # @param self The object pointer 325 | # 326 | def __init__(self): 327 | RuleClassObject.__init__(self) 328 | self.FileName = None 329 | self.SectionType = '' 330 | self.FileExtension = None 331 | 332 | ## File extension rule data in FDF 333 | # 334 | # 335 | class RuleFileExtensionClassObject(RuleClassObject): 336 | ## The constructor 337 | # 338 | # @param self The object pointer 339 | # 340 | def __init__(self): 341 | RuleClassObject.__init__(self) 342 | self.FileExtension = None 343 | 344 | ## Capsule data in FDF 345 | # 346 | # 347 | class CapsuleClassObject : 348 | ## The constructor 349 | # 350 | # @param self The object pointer 351 | # 352 | def __init__(self): 353 | self.SpecName = None 354 | self.UiCapsuleName = None 355 | self.CreateFile = None 356 | self.GroupIdNumber = None 357 | # DefineVarDict[var] = value 358 | self.DefineVarDict = {} 359 | # SetVarDict[var] = value 360 | self.SetVarDict = {} 361 | # TokensDict[var] = value 362 | self.TokensDict = {} 363 | self.CapsuleDataList = [] 364 | self.FmpPayloadList = [] 365 | 366 | ## VTF data in FDF 367 | # 368 | # 369 | class VtfClassObject : 370 | ## The constructor 371 | # 372 | # @param self The object pointer 373 | # 374 | def __init__(self): 375 | self.KeyArch = None 376 | self.ArchList = None 377 | self.UiName = None 378 | self.ResetBin = None 379 | self.ComponentStatementList = [] 380 | 381 | ## VTF component data in FDF 382 | # 383 | # 384 | class ComponentStatementClassObject : 385 | ## The constructor 386 | # 387 | # @param self The object pointer 388 | # 389 | def __init__(self): 390 | self.CompName = None 391 | self.CompLoc = None 392 | self.CompType = None 393 | self.CompVer = None 394 | self.CompCs = None 395 | self.CompBin = None 396 | self.CompSym = None 397 | self.CompSize = None 398 | self.FilePos = None 399 | 400 | ## OptionROM data in FDF 401 | # 402 | # 403 | class OptionRomClassObject: 404 | ## The constructor 405 | # 406 | # @param self The object pointer 407 | # 408 | def __init__(self): 409 | self.DriverName = None 410 | self.FfsList = [] 411 | 412 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/CommonDataClass/PackageClass.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # This file is used to define a class object to describe a package 3 | # 4 | # Copyright (c) 2007, Intel Corporation. All rights reserved.
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 9 | # 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. 12 | 13 | ## 14 | # Import Modules 15 | # 16 | from CommonClass import * 17 | from Common.Misc import sdict 18 | 19 | ## PackageHeaderClass 20 | # 21 | # This class defined header items used in Package file 22 | # 23 | # @param IdentificationClass: Inherited from IdentificationClass class 24 | # @param CommonHeaderClass: Inherited from CommonHeaderClass class 25 | # 26 | # @var DecSpecification: To store value for DecSpecification 27 | # @var ReadOnly: To store value for ReadOnly 28 | # @var RePackage: To store value for RePackage 29 | # @var ClonedFrom: To store value for ClonedFrom, it is a set structure as 30 | # [ ClonedRecordClass, ...] 31 | # 32 | class PackageHeaderClass(IdentificationClass, CommonHeaderClass): 33 | def __init__(self): 34 | IdentificationClass.__init__(self) 35 | CommonHeaderClass.__init__(self) 36 | self.DecSpecification = '' 37 | self.ReadOnly = False 38 | self.RePackage = False 39 | self.PackagePath = '' 40 | self.ClonedFrom = [] 41 | 42 | ## PackageIndustryStdHeaderClass 43 | # 44 | # This class defined industry std header items used in Package file 45 | # 46 | # @param CommonHeaderClass: Inherited from CommonHeaderClass class 47 | # 48 | # @var Name: To store value for Name 49 | # @var IncludeHeader: To store value for IncludeHeader 50 | # 51 | class PackageIndustryStdHeaderClass(CommonClass): 52 | def __init__(self): 53 | self.Name = '' 54 | self.IncludeHeader = '' 55 | CommonClass.__init__(self) 56 | 57 | ## PackageIncludePkgHeaderClass 58 | # 59 | # This class defined include Pkg header items used in Package file 60 | # 61 | # @param object: Inherited from object class 62 | # 63 | # @var IncludeHeader: To store value for IncludeHeader 64 | # @var ModuleType: To store value for ModuleType, it is a set structure as 65 | # BASE | SEC | PEI_CORE | PEIM | DXE_CORE | DXE_DRIVER | DXE_RUNTIME_DRIVER | DXE_SAL_DRIVER | DXE_SMM_DRIVER | TOOL | UEFI_DRIVER | UEFI_APPLICATION | USER_DEFINED | SMM_CORE | MM_STANDALONE | MM_CORE_STANDALONE 66 | # 67 | class PackageIncludePkgHeaderClass(object): 68 | def __init__(self): 69 | self.IncludeHeader = '' 70 | self.ModuleType = [] 71 | 72 | ## PackageClass 73 | # 74 | # This class defined a complete package item 75 | # 76 | # @param object: Inherited from object class 77 | # 78 | # @var Header: To store value for Header, it is a structure as 79 | # {Arch : PackageHeaderClass} 80 | # @var Includes: To store value for Includes, it is a list structure as 81 | # [ IncludeClass, ...] 82 | # @var LibraryClassDeclarations: To store value for LibraryClassDeclarations, it is a list structure as 83 | # [ LibraryClassClass, ...] 84 | # @var IndustryStdHeaders: To store value for IndustryStdHeaders, it is a list structure as 85 | # [ PackageIndustryStdHeader, ...] 86 | # @var ModuleFiles: To store value for ModuleFiles, it is a list structure as 87 | # [ '', '', ...] 88 | # @var PackageIncludePkgHeaders: To store value for PackageIncludePkgHeaders, it is a list structure as 89 | # [ PackageIncludePkgHeader, ...] 90 | # @var GuidDeclarations: To store value for GuidDeclarations, it is a list structure as 91 | # [ GuidClass, ...] 92 | # @var ProtocolDeclarations: To store value for ProtocolDeclarations, it is a list structure as 93 | # [ ProtocolClass, ...] 94 | # @var PpiDeclarations: To store value for PpiDeclarations, it is a list structure as 95 | # [ PpiClass, ...] 96 | # @var PcdDeclarations: To store value for PcdDeclarations, it is a list structure as 97 | # [ PcdClass, ...] 98 | # @var UserExtensions: To store value for UserExtensions, it is a list structure as 99 | # [ UserExtensionsClass, ...] 100 | # 101 | class PackageClass(object): 102 | def __init__(self): 103 | self.PackageHeader = PackageHeaderClass() 104 | self.Header = {} 105 | self.Includes = [] 106 | self.LibraryClassDeclarations = [] 107 | self.IndustryStdHeaders = [] 108 | self.ModuleFiles = [] 109 | # {[Guid, Value, Path(relative to WORKSPACE)]: ModuleClassObj} 110 | self.Modules = sdict() 111 | self.PackageIncludePkgHeaders = [] 112 | self.GuidDeclarations = [] 113 | self.ProtocolDeclarations = [] 114 | self.PpiDeclarations = [] 115 | self.PcdDeclarations = [] 116 | self.PcdChecks = [] 117 | self.UserExtensions = UserExtensionsClass() 118 | self.MiscFiles = MiscFileClass() 119 | self.FileList = [] 120 | 121 | ## 122 | # 123 | # This acts like the main() function for the script, unless it is 'import'ed into another 124 | # script. 125 | # 126 | if __name__ == '__main__': 127 | P = PackageClass() 128 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/CommonDataClass/__init__.py: -------------------------------------------------------------------------------- 1 | ## @file 2 | # Python 'CommonDataClass' package initialization file. 3 | # 4 | # This file is required to make Python interpreter treat the directory 5 | # as containing package. 6 | # 7 | # Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
8 | # This program and the accompanying materials 9 | # are licensed and made available under the terms and conditions of the BSD License 10 | # which accompanies this distribution. The full text of the license may be found at 11 | # http://opensource.org/licenses/bsd-license.php 12 | # 13 | # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 | # 16 | -------------------------------------------------------------------------------- /siiptool/thirdparty/edk2_capsule_tool/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/iotg-fbu/f6a0c807a62ae536e7bc3953ec9e83d109e20b92/siiptool/thirdparty/edk2_capsule_tool/__init__.py --------------------------------------------------------------------------------