117 lines
2.8 KiB
Python
117 lines
2.8 KiB
Python
|
#!/usr/bin/env python2
|
||
|
# Copyright 2018 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.
|
||
|
|
||
|
from __future__ import print_function
|
||
|
import argparse
|
||
|
import ctypes
|
||
|
import os
|
||
|
|
||
|
|
||
|
class Header(ctypes.Structure):
|
||
|
_pack_ = 1
|
||
|
_fields_ = [
|
||
|
('signature', ctypes.c_uint32),
|
||
|
('ftb_ver', ctypes.c_uint32),
|
||
|
('chip_id', ctypes.c_uint32),
|
||
|
('svn_ver', ctypes.c_uint32),
|
||
|
('fw_ver', ctypes.c_uint32),
|
||
|
('config_id', ctypes.c_uint32),
|
||
|
('config_ver', ctypes.c_uint32),
|
||
|
('reserved', ctypes.c_uint8 * 8),
|
||
|
('release_info', ctypes.c_ulonglong),
|
||
|
('sec_size', ctypes.c_uint32 * 4),
|
||
|
('crc', ctypes.c_uint32),
|
||
|
]
|
||
|
|
||
|
FW_HEADER_SIZE = 64
|
||
|
FW_HEADER_SIGNATURE = 0xAA55AA55
|
||
|
FW_FTB_VER = 0x00000001
|
||
|
FW_CHIP_ID = 0x3936
|
||
|
FW_BYTES_ALIGN = 4
|
||
|
FW_BIN_VER_OFFSET = 16
|
||
|
FW_BIN_CONFIG_ID_OFFSET = 20
|
||
|
|
||
|
# Starting address in flash for each section
|
||
|
FLASH_SEC_ADDR = [
|
||
|
0x0000 * 4, # CODE
|
||
|
0x7C00 * 4, # CONFIG
|
||
|
0x7000 * 4, # CX
|
||
|
None # This section shouldn't exist
|
||
|
]
|
||
|
|
||
|
UPDATE_PDU_SIZE = 4096
|
||
|
|
||
|
# Bin file format:
|
||
|
# FTB header (padded to `UPDATE_PDU_SIZE`)
|
||
|
# Flash sections
|
||
|
# CODE
|
||
|
# CX
|
||
|
# CONFIG
|
||
|
OUTPUT_FILE_SIZE = UPDATE_PDU_SIZE + 128 * 1024
|
||
|
|
||
|
|
||
|
def main():
|
||
|
parser = argparse.ArgumentParser()
|
||
|
parser.add_argument('--input', '-i', required=True)
|
||
|
parser.add_argument('--output', '-o', required=True)
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
with open(args.input) as f:
|
||
|
bs = f.read()
|
||
|
|
||
|
size = len(bs)
|
||
|
if size < FW_HEADER_SIZE + FW_BYTES_ALIGN:
|
||
|
raise Exception('FW size too small')
|
||
|
|
||
|
print('FTB file size:', size)
|
||
|
|
||
|
header = Header()
|
||
|
assert ctypes.sizeof(header) == FW_HEADER_SIZE
|
||
|
|
||
|
ctypes.memmove(ctypes.addressof(header), bs, ctypes.sizeof(header))
|
||
|
if (header.signature != FW_HEADER_SIGNATURE or
|
||
|
header.ftb_ver != FW_FTB_VER or
|
||
|
header.chip_id != FW_CHIP_ID):
|
||
|
raise Exception('Invalid header')
|
||
|
|
||
|
for key, _ in header._fields_:
|
||
|
v = getattr(header, key)
|
||
|
if isinstance(v, ctypes.Array):
|
||
|
print(key, map(hex, v))
|
||
|
else:
|
||
|
print(key, hex(v))
|
||
|
|
||
|
dimension = sum(header.sec_size)
|
||
|
|
||
|
assert dimension + FW_HEADER_SIZE + FW_BYTES_ALIGN == size
|
||
|
data = bs[FW_HEADER_SIZE:FW_HEADER_SIZE + dimension]
|
||
|
|
||
|
with open(args.output, 'wb') as f:
|
||
|
# ensure the file size
|
||
|
f.seek(OUTPUT_FILE_SIZE - 1, os.SEEK_SET)
|
||
|
f.write('\x00')
|
||
|
|
||
|
f.seek(0, os.SEEK_SET)
|
||
|
f.write(bs[0 : ctypes.sizeof(header)])
|
||
|
|
||
|
offset = 0
|
||
|
# write each sections
|
||
|
for i, addr in enumerate(FLASH_SEC_ADDR):
|
||
|
size = header.sec_size[i]
|
||
|
assert addr is not None or size == 0
|
||
|
|
||
|
if size == 0:
|
||
|
continue
|
||
|
|
||
|
f.seek(UPDATE_PDU_SIZE + addr, os.SEEK_SET)
|
||
|
f.write(data[offset : offset + size])
|
||
|
offset += size
|
||
|
|
||
|
f.flush()
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|