summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic (Chun-Ju) Yang <victoryang@chromium.org>2013-11-20 20:07:21 +0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-11-26 18:19:14 +0000
commit0892ff6418e615b6f52a4010cf94a6f28b675511 (patch)
treea71de7856a871615f53fa891682b3370a6764388
parent3f82ac35797b730b98d2bebeed4240b3439800ee (diff)
downloadchrome-ec-0892ff6418e615b6f52a4010cf94a6f28b675511.tar.gz
mec1322: Add script for packing EC binary into SPI flash
This script is needed for packing EC binary into SPI flash for MEC1322. This includes adding tag and header at appropriate location and signing the image. Signing key, for obvious reason, is not included here until we are sure what key we want to check in. BUG=chrome-os-partner:24107 TEST=Build and boot on eval board BRANCH=None Change-Id: I92db7d2ba2c76c14a9c6611a04dbd6a2c3eb8d83 Signed-off-by: Vic (Chun-Ju) Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/177324 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rwxr-xr-xchip/mec1322/util/pack_ec.py159
1 files changed, 159 insertions, 0 deletions
diff --git a/chip/mec1322/util/pack_ec.py b/chip/mec1322/util/pack_ec.py
new file mode 100755
index 0000000000..6039b3c10b
--- /dev/null
+++ b/chip/mec1322/util/pack_ec.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# A script to pack EC binary into SPI flash image for MEC1322
+
+# TODO(crosbug.com/p/24107): Add reference to document on image format.
+
+import hashlib
+import os
+import struct
+import subprocess
+import tempfile
+
+# TODO(crosbug.com/p/24188): Make these options available as command line
+# arguments.
+SPI_SIZE = 4 * 1024 * 1024
+HEADER_PEM_FILE = 'rsakey_sign_header.pem'
+PAYLOAD_PEM_FILE = 'rsakey_sign_payload.pem'
+PAYLOAD_FILE = 'ec.bin' # Set to 'ec.RO.flat' for RO-only image
+HEADER_LOCATION = 0x170000
+HEADER_FLAG1 = 0x00
+HEADER_FLAG2 = 0x01
+SPI_READ_CMD = 0x01
+LOAD_ADDR = 0x100000
+SPI_CHIP_SELECT = 0
+HEADER_SIZE = 0x140
+PAYLOAD_OFFSET = 0x240
+OUTPUT_FILE = 'ec.4mb.bin'
+
+CRC_TABLE = [0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
+ 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d]
+
+def Crc8(crc, data):
+ """Update CRC8 value."""
+ data_bytes = map(lambda b: ord(b) if isinstance(b, str) else b, data)
+ for v in data_bytes:
+ crc = ((crc << 4) & 0xff) ^ (CRC_TABLE[(crc >> 4) ^ (v >> 4)]);
+ crc = ((crc << 4) & 0xff) ^ (CRC_TABLE[(crc >> 4) ^ (v & 0xf)]);
+ return crc ^ 0x55
+
+def GetEntryPoint(payload_file):
+ """Read entry point from payload EC image."""
+ with open(payload_file, 'rb') as f:
+ f.seek(4)
+ s = f.read(4)
+ return struct.unpack('<I', s)[0]
+
+def GetPayload(payload_file):
+ """Read payload and pad it to 64-byte aligned."""
+ with open(payload_file, 'rb') as f:
+ payload = bytearray(f.read())
+ rem_len = len(payload) % 64
+ if rem_len:
+ payload += '\0' * (64 - rem_len)
+ return payload
+
+def GetPublicKey(pem_file):
+ """Extract public exponent and modulus from PEM file."""
+ s = subprocess.check_output(['openssl', 'rsa', '-in', pem_file,
+ '-text', '-noout'])
+ modulus_raw = []
+ in_modulus = False
+ for line in s.split('\n'):
+ if line.startswith('modulus'):
+ in_modulus = True
+ elif not line.startswith(' '):
+ in_modulus = False
+ elif in_modulus:
+ modulus_raw.extend(line.strip().strip(':').split(':'))
+ if line.startswith('publicExponent'):
+ exp = int(line.split(' ')[1], 10)
+ modulus_raw.reverse()
+ modulus = bytearray(''.join(map(lambda x: chr(int(x, 16)),
+ modulus_raw[0:256])))
+ return struct.pack('<Q', exp), modulus
+
+def PadZeroTo(data, size):
+ data.extend('\0' * (size - len(data)))
+
+def BuildHeader(payload_len):
+ header = bytearray(['C', 'S', 'M', 'S', '\0'])
+ header.extend([HEADER_FLAG1, HEADER_FLAG2, SPI_READ_CMD])
+ header.extend(struct.pack('<I', LOAD_ADDR))
+ header.extend(struct.pack('<I', GetEntryPoint(PAYLOAD_FILE)))
+ header.append((payload_len >> 6) & 0xff)
+ header.append((payload_len >> 14) & 0xff)
+ PadZeroTo(header, 0x14)
+ header.extend(struct.pack('<I', PAYLOAD_OFFSET))
+
+ exp, modulus = GetPublicKey(PAYLOAD_PEM_FILE)
+ PadZeroTo(header, 0x20)
+ header.extend(exp)
+ PadZeroTo(header, 0x30)
+ header.extend(modulus)
+ PadZeroTo(header, HEADER_SIZE)
+
+ return header
+
+def SignByteArray(data, pem_file):
+ hash_file = tempfile.mkstemp()[1]
+ sign_file = tempfile.mkstemp()[1]
+ with open(hash_file, 'wb') as f:
+ hasher = hashlib.sha256()
+ hasher.update(data)
+ f.write(hasher.digest())
+ subprocess.check_call(['openssl', 'rsautl', '-sign', '-inkey', pem_file,
+ '-keyform', 'PEM', '-in', hash_file,
+ '-out', sign_file])
+ with open(sign_file, 'rb') as f:
+ signed = list(f.read())
+ signed.reverse()
+ return bytearray(''.join(signed))
+
+def BuildTag(header_loc):
+ tag = bytearray([(header_loc >> 8) & 0xff,
+ (header_loc >> 16) & 0xff,
+ (header_loc >> 24) & 0xff])
+ if SPI_CHIP_SELECT != 0:
+ tag[2] |= 0x80
+ tag.append(Crc8(0, tag))
+ return tag
+
+
+def main():
+ spi_list = []
+
+ payload = GetPayload(PAYLOAD_FILE)
+ payload_len = len(payload)
+ payload_signature = SignByteArray(payload, PAYLOAD_PEM_FILE)
+ header = BuildHeader(payload_len)
+ header_signature = SignByteArray(header, HEADER_PEM_FILE)
+ tag = BuildTag(HEADER_LOCATION)
+
+ spi_list.append((HEADER_LOCATION, header))
+ spi_list.append((HEADER_LOCATION + HEADER_SIZE, header_signature))
+ spi_list.append((HEADER_LOCATION + PAYLOAD_OFFSET, payload))
+ spi_list.append((HEADER_LOCATION + PAYLOAD_OFFSET + payload_len,
+ payload_signature))
+ spi_list.append((SPI_SIZE - 256, tag))
+
+ spi_list = sorted(spi_list)
+
+ with open(OUTPUT_FILE, 'wb') as f:
+ addr = 0
+ for s in spi_list:
+ assert addr <= s[0]
+ if addr < s[0]:
+ f.write('\xff' * (s[0] - addr))
+ addr = s[0]
+ f.write(s[1])
+ addr += len(s[1])
+ if addr < SPI_SIZE:
+ f.write('\xff' * (SPI_SIZE - addr))
+
+if __name__ == '__main__':
+ main()