summaryrefslogtreecommitdiff
path: root/util/unpack_ftb.py
blob: 49f4d0ab5b708451ecf97faa3f8f81ac671430c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#!/usr/bin/env python
# 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
]

OUTPUT_FILE_SIZE = 128 * 1024  # 128KB


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')

    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(addr, os.SEEK_SET)
      f.write(data[offset : offset + size])
      offset += size

    f.flush()


if __name__ == '__main__':
  main()