From e38f85915f7681f9e52970682f7c476791eb2301 Mon Sep 17 00:00:00 2001 From: Nicola Corna Date: Wed, 22 Feb 2017 10:16:32 +0100 Subject: util/me_cleaner: Pull the latest changes from upstream Relevant changes (commit 250b2ec): * Fix a bug for ME6 Ignition images. * Fix signature checking for ME11 and later. * Add command line arguments. * Add an option to relocate the FTPR partition to the top of the ME region, recovering most of the ME region space. * Print the image minimum size. * Add write boundary checks, to prevent writes on other regions in case of bugs. The new changes have been tested on multiple platforms by the me_cleaner users. They have been tested also on the author's X220T with coreboot, where the ME region has been shrinked up to 84 kB without any issue. Change-Id: I3bd6b4cba9f5eebc3cd4892dd9f188744a06c42b Signed-off-by: Nicola Corna Reviewed-on: https://review.coreboot.org/18473 Tested-by: build bot (Jenkins) Reviewed-by: Philipp Deppenwiese --- util/me_cleaner/README.md | 3 +- util/me_cleaner/me_cleaner.py | 438 ++++++++++++++++++++++++++++++------------ 2 files changed, 317 insertions(+), 124 deletions(-) (limited to 'util') diff --git a/util/me_cleaner/README.md b/util/me_cleaner/README.md index 9a09b550eb..0ca3d32bf9 100644 --- a/util/me_cleaner/README.md +++ b/util/me_cleaner/README.md @@ -12,7 +12,8 @@ Currently this tool: * Removes any partition except for the fundamental one (FTPR) * Removes the EFFS presence flag * Corrects the FPT checksum - * Removes any non-essential LZMA or Huffman compressed module (pre-Skylake only) + * Removes any non-essential LZMA or Huffman compressed module from the FTPR partition (pre-Skylake only) + * Relocates the remaining parts of the FTPR partition to the top of the ME region (pre-Skylake only) * Checks the validity of the RSA signature of the FTPR partition Don't forget to power cycle your PC after flashing the modified ME/TXE image diff --git a/util/me_cleaner/me_cleaner.py b/util/me_cleaner/me_cleaner.py index 2ad5898213..8ca5498134 100755 --- a/util/me_cleaner/me_cleaner.py +++ b/util/me_cleaner/me_cleaner.py @@ -18,12 +18,70 @@ import sys import itertools import binascii import hashlib +import argparse +import shutil from struct import pack, unpack +min_ftpr_offset = 0x400 +spared_blocks = 4 unremovable_modules = ("BUP", "ROMP") +class OutOfRegionException(Exception): + pass + + +class regionFile: + def __init__(self, f, region_start, region_end): + self.f = f + self.region_start = region_start + self.region_end = region_end + + def read(self, n): + return self.f.read(n) + + def readinto(self, b): + return self.f.readinto(b) + + def seek(self, offset): + return self.f.seek(offset) + + def write_to(self, offset, data): + if offset >= self.region_start and \ + offset + len(data) <= self.region_end: + self.f.seek(offset) + return self.f.write(data) + else: + raise OutOfRegionException() + + def fill_range(self, start, end, fill): + if start >= self.region_start and end <= self.region_end: + if start < end: + block = fill * 4096 + self.f.seek(start) + self.f.writelines(itertools.repeat(block, + (end - start) // 4096)) + self.f.write(block[:(end - start) % 4096]) + else: + raise OutOfRegionException() + + def move_range(self, offset_from, size, offset_to, fill): + if offset_from >= self.region_start and \ + offset_from + size <= self.region_end and \ + offset_to >= self.region_start and \ + offset_to + size <= self.region_end: + for i in range(0, size, 4096): + self.f.seek(offset_from + i, 0) + block = self.f.read(4096 if size - i >= 4096 else size - i) + self.f.seek(offset_from + i, 0) + self.f.write(fill * len(block)) + self.f.seek(offset_to + i, 0) + self.f.write(block) + else: + raise OutOfRegionException() + + def get_chunks_offsets(llut, me_start): chunk_count = unpack(" removable_chunk[0]: - fill_range(f, removable_chunk[0], removable_chunk[1], b"\xff") + end = min(removable_chunk[1], me_end) + f.fill_range(removable_chunk[0], end, b"\xff") + + end_addr = max(end_addr, + max(unremovable_huff_chunks, key=lambda x: x[1])[1]) + + return end_addr def check_partition_signature(f, offset): f.seek(offset) header = f.read(0x80) modulus = int(binascii.hexlify(f.read(0x100)[::-1]), 16) - public_exponent = int(binascii.hexlify(f.read(0x4)[::-1]), 16) + public_exponent = unpack("> 24 & 0x7 - frba = flmap0 >> 12 & 0xff0 - if nr >= 2: - f.seek(frba + 0x8) - flreg2 = unpack("> 4 & 0x1fff000 | 0xfff - - if me_start >= me_end: - sys.exit("The ME/TXE region in this image has been " - "disabled") - - f.seek(me_start + 0x10) - if f.read(4) != b"$FPT": - sys.exit("The ME/TXE region is corrupted or missing") - - print("The ME/TXE region goes from {:#x} to {:#x}" - .format(me_start, me_end)) - else: - sys.exit("This image does not contains a ME/TXE firmware " - "(NR = {})".format(nr)) +def relocate_partition(f, me_start, me_end, partition_header_offset, + new_offset, mod_headers): + + f.seek(partition_header_offset) + name = f.read(4).rstrip(b"\x00").decode("ascii") + f.seek(partition_header_offset + 0x8) + old_offset, partition_size = unpack("> 4) & 7 == 0x01: + llut_start = unpack("> 24 & 0x7 + frba = flmap0 >> 12 & 0xff0 + fmba = (flmap1 & 0xff) << 4 + if nr >= 2: + f.seek(frba) + flreg0, flreg1, flreg2 = unpack("> 4 & 0x1fff000 | 0xfff + 1 + me_start = (flreg2 & 0x1fff) << 12 + me_end = flreg2 >> 4 & 0x1fff000 | 0xfff + 1 + + if me_start >= me_end: + sys.exit("The ME/TXE region in this image has been disabled") + + f.seek(me_start + 0x10) + if f.read(4) != b"$FPT": + sys.exit("The ME/TXE region is corrupted or missing") + + print("The ME/TXE region goes from {:#x} to {:#x}" + .format(me_start, me_end)) else: - sys.exit("Unknown image") + sys.exit("This image does not contains a ME/TXE firmware NR = {})" + .format(nr)) + else: + sys.exit("Unknown image") - print("Found FPT header at {:#x}".format(me_start + 0x10)) + print("Found FPT header at {:#x}".format(me_start + 0x10)) - f.seek(me_start + 0x14) - entries = unpack("= 11 (except for + # 0x1b, the checksum itself). In other words, the sum of those bytes + # must be always 0x00. + mef.write_to(me_start + 0x1b, pack("B", checksum)) if not me11: print("Reading FTPR modules list...") - f.seek(ftpr_offset + 0x1c) - tag = f.read(4) + mef.seek(ftpr_offset + 0x1c) + tag = mef.read(4) if tag == b"$MN2": - f.seek(ftpr_offset + 0x20) - num_modules = unpack(" 0: + print("The ME region can be reduced up to:\n" + " {:08x}:{:08x} me" + .format(me_start, end_addr - 1)) else: print("Found less modules than expected in the FTPR " "partition; skipping modules removal") @@ -302,12 +491,15 @@ else: else: print("Modules removal in ME v11 or greater is not yet supported") - sys.stdout.write("Checking FTPR RSA signature... ") - if check_partition_signature(f, ftpr_offset): - print("VALID") - else: - print("INVALID!!") - sys.exit("The FTPR partition signature is not valid. Is the input " - "ME/TXE image valid?") + sys.stdout.write("Checking FTPR RSA signature... ") + if check_partition_signature(f, ftpr_offset + ftpr_mn2_offset): + print("VALID") + else: + print("INVALID!!") + sys.exit("The FTPR partition signature is not valid. Is the input " + "ME/TXE image valid?") + + f.close() + if not args.check: print("Done! Good luck!") -- cgit v1.2.3