fiptool.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. #!/usr/bin/env python3
  2. # SPDX-License-Identifier: BSD-3-Clause
  3. # PYTHON_ARGCOMPLETE_OK
  4. import sys
  5. import logging
  6. import os
  7. import os.path
  8. import argparse
  9. from collections import OrderedDict
  10. import binascii
  11. from struct import pack, unpack
  12. import lzma
  13. import pprint
  14. PYTHON_MIN_VERSION = (3, 5, 2) # Ubuntu 16.04 LTS contains Python v3.5.2 by default
  15. if sys.version_info < PYTHON_MIN_VERSION:
  16. print("Python >= %r is required" % (PYTHON_MIN_VERSION,))
  17. sys.exit(-1)
  18. try:
  19. import coloredlogs
  20. except ImportError:
  21. coloredlogs = None
  22. try:
  23. import argcomplete
  24. except ImportError:
  25. argcomplete = None
  26. LOADER_2ND_MAGIC_ORIG = b"BL33"
  27. LOADER_2ND_MAGIC_LZMA = b"B3MA"
  28. LOADER_2ND_MAGIC_LZ4 = b"B3Z4"
  29. LOADER_2ND_MAGIC_LIST = [
  30. LOADER_2ND_MAGIC_ORIG,
  31. LOADER_2ND_MAGIC_LZMA,
  32. LOADER_2ND_MAGIC_LZ4,
  33. ]
  34. IMAGE_ALIGN = 512
  35. PARAM1_SIZE = 0x1000
  36. PARAM1_SIZE_WO_SIG = 0x800
  37. PARAM2_SIZE = 0x1000
  38. def round_up(divident, divisor):
  39. return ((divident + divisor - 1) // divisor) * divisor
  40. def lzma_compress(body):
  41. z = lzma.LZMACompressor(lzma.FORMAT_ALONE, preset=lzma.PRESET_EXTREME)
  42. compressed = z.compress(body)
  43. compressed += z.flush()
  44. return compressed
  45. def lz4_compress(body):
  46. try:
  47. import lz4.frame
  48. except ImportError:
  49. logging.error("lz4 is not installed. Run 'pip install lz4'.")
  50. raise
  51. compressed = lz4.frame.compress(body)
  52. return compressed
  53. class Entry:
  54. __slots__ = "name", "type", "addr", "_content", "entry_size"
  55. def __init__(self):
  56. self.addr = None
  57. self._content = None
  58. @property
  59. def end(self):
  60. return self.addr + self.entry_size
  61. @property
  62. def content(self):
  63. return self._content
  64. @content.setter
  65. def content(self, value):
  66. if type(value) == int:
  67. value = value.to_bytes(self.entry_size, "little")
  68. if self.entry_size is not None:
  69. if len(value) > self.entry_size:
  70. raise ValueError("%s (%d bytes) must <= %#r" % (self.name, len(value), self.entry_size))
  71. value = value + b"\0" * (self.entry_size - len(value))
  72. self._content = value
  73. @classmethod
  74. def make(cls, name, entry_size, _type, init=None):
  75. entry = Entry()
  76. entry.name = name
  77. entry.type = _type
  78. entry.entry_size = entry_size
  79. if type(init) in (bytes, bytearray):
  80. entry.content = bytes(init)
  81. elif entry_size is not None:
  82. entry.content = b"\0" * entry.entry_size
  83. else:
  84. entry.content = b""
  85. return (name, entry)
  86. def toint(self):
  87. if self.type != int:
  88. raise TypeError("%s is not int type" % self.name)
  89. return int.from_bytes(self.content, "little")
  90. def tostr(self):
  91. v = self.content
  92. if self.type == int:
  93. v = "%#08x" % self.toint()
  94. elif type(self.content) in [bytes, bytearray]:
  95. v = v.hex()
  96. if len(v) > 32:
  97. v = v[:32] + "..."
  98. return v
  99. def __str__(self):
  100. v = self.tostr()
  101. return "<%s=%s (%dbytes)>" % (self.name, v, self.entry_size)
  102. def __repr__(self):
  103. v = self.tostr()
  104. return "<%s: a=%#x s=%#x c=%s %r>" % (self.name, self.addr, self.entry_size, v, self.type)
  105. class FIP:
  106. param1 = OrderedDict(
  107. [
  108. Entry.make("MAGIC1", 8, int, b"CVBL01\n\0"),
  109. Entry.make("MAGIC2", 4, int),
  110. Entry.make("PARAM_CKSUM", 4, int),
  111. Entry.make("NAND_INFO", 128, int),
  112. Entry.make("NOR_INFO", 36, int),
  113. Entry.make("FIP_FLAGS", 8, int),
  114. Entry.make("CHIP_CONF_SIZE", 4, int),
  115. Entry.make("BLCP_IMG_CKSUM", 4, int),
  116. Entry.make("BLCP_IMG_SIZE", 4, int),
  117. Entry.make("BLCP_IMG_RUNADDR", 4, int),
  118. Entry.make("BLCP_PARAM_LOADADDR", 4, int),
  119. Entry.make("BLCP_PARAM_SIZE", 4, int),
  120. Entry.make("BL2_IMG_CKSUM", 4, int),
  121. Entry.make("BL2_IMG_SIZE", 4, int),
  122. Entry.make("BLD_IMG_SIZE", 4, int),
  123. Entry.make("PARAM2_LOADADDR", 4, int),
  124. Entry.make("RESERVED1", 4, int),
  125. Entry.make("CHIP_CONF", 760, bytes),
  126. Entry.make("BL_EK", 32, bytes),
  127. Entry.make("ROOT_PK", 512, bytes),
  128. Entry.make("BL_PK", 512, bytes),
  129. Entry.make("BL_PK_SIG", 512, bytes),
  130. Entry.make("CHIP_CONF_SIG", 512, bytes),
  131. Entry.make("BL2_IMG_SIG", 512, bytes),
  132. Entry.make("BLCP_IMG_SIG", 512, bytes),
  133. ]
  134. )
  135. body1 = OrderedDict(
  136. [
  137. Entry.make("BLCP", None, bytes),
  138. Entry.make("BL2", None, bytes),
  139. ]
  140. )
  141. param2 = OrderedDict(
  142. [
  143. Entry.make("MAGIC1", 8, int, b"CVLD02\n\0"),
  144. Entry.make("PARAM2_CKSUM", 4, int),
  145. Entry.make("RESERVED1", 4, bytes),
  146. # DDR param
  147. Entry.make("DDR_PARAM_CKSUM", 4, int),
  148. Entry.make("DDR_PARAM_LOADADDR", 4, int),
  149. Entry.make("DDR_PARAM_SIZE", 4, int),
  150. Entry.make("DDR_PARAM_RESERVED", 4, int),
  151. # BLCP_2ND
  152. Entry.make("BLCP_2ND_CKSUM", 4, int),
  153. Entry.make("BLCP_2ND_LOADADDR", 4, int),
  154. Entry.make("BLCP_2ND_SIZE", 4, int),
  155. Entry.make("BLCP_2ND_RUNADDR", 4, int),
  156. # ATF-BL31 or OpenSBI
  157. Entry.make("MONITOR_CKSUM", 4, int),
  158. Entry.make("MONITOR_LOADADDR", 4, int),
  159. Entry.make("MONITOR_SIZE", 4, int),
  160. Entry.make("MONITOR_RUNADDR", 4, int),
  161. # u-boot
  162. Entry.make("LOADER_2ND_RESERVED0", 4, int),
  163. Entry.make("LOADER_2ND_LOADADDR", 4, int),
  164. Entry.make("LOADER_2ND_RESERVED1", 4, int),
  165. Entry.make("LOADER_2ND_RESERVED2", 4, int),
  166. # Reserved
  167. Entry.make("RESERVED_LAST", 4096 - 16 * 5, bytes),
  168. ]
  169. )
  170. body2 = OrderedDict(
  171. [
  172. Entry.make("DDR_PARAM", None, bytes),
  173. Entry.make("BLCP_2ND", None, bytes),
  174. Entry.make("MONITOR", None, bytes),
  175. Entry.make("LOADER_2ND", None, bytes),
  176. ]
  177. )
  178. ldr_2nd_hdr = OrderedDict(
  179. [
  180. Entry.make("JUMP0", 4, int),
  181. Entry.make("MAGIC", 4, int),
  182. Entry.make("CKSUM", 4, int),
  183. Entry.make("SIZE", 4, int),
  184. Entry.make("RUNADDR", 8, int),
  185. Entry.make("RESERVED1", 4, int),
  186. Entry.make("RESERVED2", 4, int),
  187. ]
  188. )
  189. FIP_FLAGS_SCS_MASK = 0x000c
  190. FIP_FLAGS_ENCRYPTED_MASK = 0x0030
  191. def _param_size(self, param):
  192. return max((e.end for e in param.values()))
  193. def _gen_param(self):
  194. addr = 0
  195. for entry in self.param1.values():
  196. entry.addr = addr
  197. addr += entry.entry_size
  198. assert PARAM1_SIZE_WO_SIG == self.param1["BL_PK_SIG"].addr
  199. addr = 0
  200. for entry in self.param2.values():
  201. entry.addr = addr
  202. addr += entry.entry_size
  203. assert PARAM2_SIZE == self.param2["RESERVED_LAST"].addr + self.param2["RESERVED_LAST"].entry_size
  204. addr = 0
  205. for entry in self.ldr_2nd_hdr.values():
  206. entry.addr = addr
  207. addr += entry.entry_size
  208. def __init__(self):
  209. self.compress_algo = None
  210. self._gen_param()
  211. def image_crc(self, image):
  212. crc = binascii.crc_hqx(image, 0)
  213. crc = pack("<H", crc) + b"\xFE\xCA"
  214. return crc
  215. def pad(self, data, block_size):
  216. if type(data) not in [bytearray, bytes]:
  217. raise TypeError("Need bytearray or bytes")
  218. r = len(data) % block_size
  219. if r:
  220. data += b"\0" * (block_size - r)
  221. return data
  222. def _pprint_attr(self, name):
  223. v = getattr(self, name)
  224. if type(v) == OrderedDict:
  225. v = list(v.values())
  226. logging.info("print(%s):\n" % name + pprint.pformat(v, 4, 140))
  227. def print_fip_params(self):
  228. self._pprint_attr("param1")
  229. self._pprint_attr("param2")
  230. self._pprint_attr("ldr_2nd_hdr")
  231. def read_fip(self, path):
  232. logging.debug("read_fip:")
  233. with open(path, "rb") as fp:
  234. fip_bin = fp.read()
  235. fip_bin = bytearray(fip_bin)
  236. e = self.param1["MAGIC1"]
  237. if fip_bin[e.addr : e.end] != e.content:
  238. raise ValueError("Unknown magic %r" % fip_bin[e.addr : e.end])
  239. # Read param1 from fip.bin
  240. for e in self.param1.values():
  241. e.content = fip_bin[e.addr : e.end]
  242. self.read_end = PARAM1_SIZE
  243. # Read BLCP
  244. e = self.param1["BLCP_IMG_SIZE"]
  245. blcp_img_size = unpack("<I", fip_bin[e.addr : e.end])[0]
  246. if blcp_img_size:
  247. start = self.read_end
  248. self.read_end = start + blcp_img_size
  249. self.body1["BLCP"].content = fip_bin[start : self.read_end]
  250. # Read FSBL as BL2
  251. e = self.param1["BL2_IMG_SIZE"]
  252. bl2_img_size = unpack("<I", fip_bin[e.addr : e.end])[0]
  253. if bl2_img_size:
  254. start = self.read_end
  255. self.read_end = start + bl2_img_size
  256. self.body1["BL2"].content = fip_bin[start : self.read_end]
  257. logging.info("read_fip end=%#x", self.read_end)
  258. self.rest_fip = fip_bin[self.read_end :]
  259. self.read_fip2(fip_bin)
  260. def read_fip2(self, fip_bin):
  261. param2_loadaddr = self.param1["PARAM2_LOADADDR"].toint()
  262. param2_bin = fip_bin[param2_loadaddr : param2_loadaddr + PARAM2_SIZE]
  263. for e in self.param2.values():
  264. e.content = param2_bin[e.addr : e.end]
  265. self.read_end = param2_loadaddr + PARAM2_SIZE
  266. # Read DDR_PARAM, BLCP_2ND, and MONITOR
  267. for name in ["DDR_PARAM", "BLCP_2ND", "MONITOR"]:
  268. size = self.param2[name + "_SIZE"].toint()
  269. loadaddr = self.param2[name + "_LOADADDR"].toint()
  270. self.body2[name].content = fip_bin[loadaddr : loadaddr + size]
  271. self.read_end = loadaddr + size
  272. # Read LOADER_2ND
  273. loader_2nd_loadaddr = self.param2["LOADER_2ND_LOADADDR"].toint()
  274. if loader_2nd_loadaddr:
  275. self.read_loader_2nd(fip_bin)
  276. logging.info("read_fip2 end=%#x", self.read_end)
  277. self.rest_fip = fip_bin[self.read_end :]
  278. def read_loader_2nd(self, fip_bin):
  279. loader_2nd_loadaddr = self.param2["LOADER_2ND_LOADADDR"].toint()
  280. self._parse_ldr_2nd_hdr(fip_bin[loader_2nd_loadaddr:])
  281. if self.ldr_2nd_hdr["MAGIC"].content not in LOADER_2ND_MAGIC_LIST:
  282. raise ValueError("%r" % self.ldr_2nd_hdr["MAGIC"].content)
  283. ldr_2nd_size = self.ldr_2nd_hdr["SIZE"].toint()
  284. self.body2["LOADER_2ND"].content = fip_bin[loader_2nd_loadaddr : loader_2nd_loadaddr + ldr_2nd_size]
  285. self.read_end = loader_2nd_loadaddr + ldr_2nd_size
  286. self.rest_fip = fip_bin[self.read_end :]
  287. def add_chip_conf(self, args):
  288. logging.debug("add_chip_conf:")
  289. with open(args.CHIP_CONF, "rb") as fp:
  290. image = fp.read()
  291. if image.startswith(b"APLB"):
  292. image = image[8:] # strip old BLP header
  293. self.param1["CHIP_CONF"].content = image
  294. def add_blcp(self, args):
  295. logging.debug("add_blcp:")
  296. with open(args.BLCP, "rb") as fp:
  297. image = fp.read()
  298. image = self.pad(image, IMAGE_ALIGN)
  299. self.param1["BLCP_IMG_RUNADDR"].content = args.BLCP_IMG_RUNADDR
  300. self.body1["BLCP"].content = image
  301. def add_bl2(self, args):
  302. logging.debug("add_bl2:")
  303. with open(args.BL2, "rb") as fp:
  304. image = fp.read()
  305. bl2_fill = 0
  306. if args.BL2_FILL:
  307. bl2_fill = args.BL2_FILL
  308. image += b"\xA9" * (bl2_fill - len(image))
  309. image = self.pad(image, IMAGE_ALIGN)
  310. self.body1["BL2"].content = image
  311. def add_nor_info(self, args):
  312. logging.debug("add_nor_info:")
  313. self.param1["NOR_INFO"].content = args.NOR_INFO
  314. def add_nand_info(self, args):
  315. logging.debug("add_nand_info:")
  316. self.param1["NAND_INFO"].content = args.NAND_INFO
  317. def update_param1_cksum(self, image):
  318. image = bytearray(image)
  319. crc = self.image_crc(image[self.param1["NAND_INFO"].addr : PARAM1_SIZE_WO_SIG])
  320. param_cksum = self.param1["PARAM_CKSUM"]
  321. param_cksum.content = crc
  322. image[param_cksum.addr : param_cksum.end] = crc
  323. return image
  324. def make_fip1(self):
  325. logging.debug("make_fip1:")
  326. chip_conf = self.param1["CHIP_CONF"].content
  327. self.param1["CHIP_CONF_SIZE"].content = len(chip_conf)
  328. blcp = self.body1["BLCP"].content
  329. self.param1["BLCP_IMG_CKSUM"].content = self.image_crc(blcp)
  330. self.param1["BLCP_IMG_SIZE"].content = len(blcp)
  331. bl2 = self.body1["BL2"].content
  332. self.param1["BL2_IMG_CKSUM"].content = self.image_crc(bl2)
  333. self.param1["BL2_IMG_SIZE"].content = len(bl2)
  334. # Pack body1
  335. body1_bin = b""
  336. for entry in self.body1.values():
  337. if len(entry.content) % IMAGE_ALIGN:
  338. raise ValueError("%s (%d) is not align to %d" % (entry.name, len(entry.content), IMAGE_ALIGN))
  339. logging.info("add %s (%#x)", entry.name, len(entry.content))
  340. body1_bin += entry.content
  341. logging.debug("len(body1_bin) is %d", len(body1_bin))
  342. # Param1 cksum
  343. param1_bin = b"".join((entry.content for entry in self.param1.values()))
  344. param1_bin = self.update_param1_cksum(param1_bin)
  345. if len(param1_bin) != PARAM1_SIZE:
  346. raise ValueError("param1_bin is %d bytes" % len(param1_bin))
  347. fip1_bin = param1_bin + body1_bin
  348. logging.debug("len(fip1_bin) is %d", len(fip1_bin))
  349. return fip1_bin
  350. def add_ddr_param(self, args):
  351. with open(args.DDR_PARAM, "rb") as fp:
  352. ddr_param = fp.read()
  353. logging.debug("ddr_param=%#x bytes", len(ddr_param))
  354. self.body2["DDR_PARAM"].content = ddr_param
  355. def add_blcp_2nd(self, args):
  356. with open(args.BLCP_2ND, "rb") as fp:
  357. blcp_2nd = fp.read()
  358. logging.debug("blcp_2nd=%#x bytes", len(blcp_2nd))
  359. self.body2["BLCP_2ND"].content = blcp_2nd
  360. def add_monitor(self, args):
  361. with open(args.MONITOR, "rb") as fp:
  362. monitor = fp.read()
  363. logging.debug("monitor=%#x bytes", len(monitor))
  364. self.body2["MONITOR"].content = monitor
  365. def add_loader_2nd(self, args):
  366. with open(args.LOADER_2ND, "rb") as fp:
  367. loader_2nd = fp.read()
  368. logging.debug("loader_2nd=%#x bytes", len(loader_2nd))
  369. e = self.ldr_2nd_hdr["MAGIC"]
  370. magic = loader_2nd[e.addr : e.end]
  371. if magic != LOADER_2ND_MAGIC_ORIG:
  372. raise ValueError("loader_2nd's magic should be %r, but %r" % (LOADER_2ND_MAGIC_ORIG, magic))
  373. self.compress_algo = args.compress
  374. self.body2["LOADER_2ND"].content = loader_2nd
  375. def pack_ddr_param(self, fip_bin):
  376. if not len(self.body2["DDR_PARAM"].content):
  377. return
  378. fip_bin = self.pad(fip_bin, IMAGE_ALIGN)
  379. # Pack DDR_PARAM to body2
  380. ddr_param = self.pad(self.body2["DDR_PARAM"].content, IMAGE_ALIGN)
  381. self.param2["DDR_PARAM_CKSUM"].content = self.image_crc(ddr_param)
  382. self.param2["DDR_PARAM_SIZE"].content = len(ddr_param)
  383. self.param2["DDR_PARAM_LOADADDR"].content = len(fip_bin)
  384. return fip_bin + ddr_param
  385. def pack_blcp_2nd(self, fip_bin, blcp_2nd_runaddr):
  386. logging.debug("pack_blcp_2nd:")
  387. if not len(self.body2["BLCP_2ND"].content):
  388. return
  389. runaddr = int(blcp_2nd_runaddr)
  390. fip_bin = self.pad(fip_bin, IMAGE_ALIGN)
  391. # Pack MONITOR to body2
  392. body = self.pad(self.body2["BLCP_2ND"].content, IMAGE_ALIGN)
  393. self.param2["BLCP_2ND_CKSUM"].content = self.image_crc(body)
  394. self.param2["BLCP_2ND_SIZE"].content = len(body)
  395. self.param2["BLCP_2ND_LOADADDR"].content = len(fip_bin)
  396. self.param2["BLCP_2ND_RUNADDR"].content = runaddr
  397. return fip_bin + body
  398. def pack_monitor(self, fip_bin, monitor_runaddr):
  399. logging.debug("pack_monitor:")
  400. if not len(self.body2["MONITOR"].content):
  401. return
  402. monitor_runaddr = int(monitor_runaddr)
  403. fip_bin = self.pad(fip_bin, IMAGE_ALIGN)
  404. # Pack MONITOR to body2
  405. monitor = self.pad(self.body2["MONITOR"].content, IMAGE_ALIGN)
  406. self.param2["MONITOR_CKSUM"].content = self.image_crc(monitor)
  407. self.param2["MONITOR_SIZE"].content = len(monitor)
  408. self.param2["MONITOR_LOADADDR"].content = len(fip_bin)
  409. self.param2["MONITOR_RUNADDR"].content = monitor_runaddr
  410. return fip_bin + monitor
  411. def _parse_ldr_2nd_hdr(self, image):
  412. for e in self.ldr_2nd_hdr.values():
  413. e.content = image[e.addr : e.end]
  414. def _update_ldr_2nd_hdr(self):
  415. image = self.body2["LOADER_2ND"].content
  416. hdr_size = self._param_size(self.ldr_2nd_hdr)
  417. hdr, body = image[:hdr_size], image[hdr_size:]
  418. # Update SIZE
  419. self.ldr_2nd_hdr["SIZE"].content = len(image)
  420. # Update CKSUM
  421. hdr = bytearray(b"".join((e.content for e in self.ldr_2nd_hdr.values())))
  422. # CKSUM is calculated after "CKSUM" field
  423. hdr_cksum = self.ldr_2nd_hdr["CKSUM"]
  424. crc = self.image_crc((hdr + body)[hdr_cksum.end :])
  425. hdr_cksum.content = crc
  426. hdr = bytearray(b"".join((e.content for e in self.ldr_2nd_hdr.values())))
  427. self.body2["LOADER_2ND"].content = hdr + body
  428. def _compress_ldr_2nd(self):
  429. image = self.body2["LOADER_2ND"].content
  430. hdr_size = self._param_size(self.ldr_2nd_hdr)
  431. hdr, body = image[:hdr_size], image[hdr_size:]
  432. magic = self.ldr_2nd_hdr["MAGIC"].content
  433. if magic == LOADER_2ND_MAGIC_ORIG:
  434. # if image is uncompressed, compress it.
  435. if self.compress_algo is None:
  436. pass
  437. elif self.compress_algo == "lzma":
  438. self.ldr_2nd_hdr["MAGIC"].content = LOADER_2ND_MAGIC_LZMA
  439. body = lzma_compress(body)
  440. logging.info("lzma loader_2nd=%#x bytes wo header", len(body))
  441. elif self.compress_algo == "lz4":
  442. self.ldr_2nd_hdr["MAGIC"].content = LOADER_2ND_MAGIC_LZ4
  443. body = lz4_compress(body)
  444. logging.info("lz4 loader_2nd=%#x bytes wo header", len(body))
  445. else:
  446. raise NotImplementedError("'%r' is not supported." % self.compress_algo)
  447. elif magic in LOADER_2ND_MAGIC_LIST:
  448. logging.info("loader_2nd is already compressed")
  449. else:
  450. raise ValueError("unknown loader_2nd magic (%r)", magic)
  451. self.body2["LOADER_2ND"].content = self.pad(hdr + body, IMAGE_ALIGN)
  452. def pack_loader_2nd(self, fip_bin):
  453. logging.debug("pack_loader_2nd:")
  454. if not len(self.body2["LOADER_2ND"].content):
  455. return
  456. fip_bin = self.pad(fip_bin, IMAGE_ALIGN)
  457. self.param2["LOADER_2ND_LOADADDR"].content = len(fip_bin)
  458. self._parse_ldr_2nd_hdr(self.body2["LOADER_2ND"].content)
  459. self._compress_ldr_2nd()
  460. self._update_ldr_2nd_hdr()
  461. # Append LOADER_2ND to body2
  462. return fip_bin + self.body2["LOADER_2ND"].content
  463. def insert_param1(self, fip_bin, name, value):
  464. fip_bin = bytearray(fip_bin)
  465. e = self.param1[name]
  466. e.content = value
  467. fip_bin[e.addr : e.end] = value
  468. return self.update_param1_cksum(fip_bin)
  469. def append_fip2(self, fip1_bin, args):
  470. logging.debug("make_fip2:")
  471. fip_bin = bytearray(fip1_bin)
  472. # Update PARAM2_LOADADDR
  473. param2_loadaddr = len(fip1_bin)
  474. fip_bin = self.insert_param1(fip_bin, "PARAM2_LOADADDR", pack("<I", param2_loadaddr))
  475. # Add an empty PARAM2
  476. fip_bin += b"\0" * PARAM2_SIZE
  477. # Pack body
  478. fip_bin = self.pack_ddr_param(fip_bin)
  479. if len(self.body2["BLCP_2ND"].content):
  480. runaddr = self.param2["BLCP_2ND_RUNADDR"].toint()
  481. if not runaddr:
  482. runaddr = int(args.BLCP_2ND_RUNADDR)
  483. fip_bin = self.pack_blcp_2nd(fip_bin, runaddr)
  484. if len(self.body2["MONITOR"].content):
  485. runaddr = self.param2["MONITOR_RUNADDR"].toint()
  486. if not runaddr:
  487. runaddr = int(args.MONITOR_RUNADDR)
  488. fip_bin = self.pack_monitor(fip_bin, runaddr)
  489. if len(self.body2["LOADER_2ND"].content):
  490. fip_bin = self.pack_loader_2nd(fip_bin)
  491. # Pack param2_bin
  492. param2_bin = b"".join((entry.content for entry in self.param2.values()))
  493. self.param2["PARAM2_CKSUM"].content = self.image_crc(param2_bin[self.param2["PARAM2_CKSUM"].end :])
  494. param2_bin = b"".join((entry.content for entry in self.param2.values())) # update cksum
  495. logging.debug("len(param2_bin) is %d", len(param2_bin))
  496. assert len(param2_bin) == PARAM2_SIZE
  497. fip_bin[param2_loadaddr : param2_loadaddr + PARAM2_SIZE] = param2_bin
  498. return fip_bin
  499. def make(self, args=None):
  500. fip_bin = self.make_fip1()
  501. if len(self.body2["DDR_PARAM"].content):
  502. fip_bin = self.append_fip2(fip_bin, args)
  503. logging.info("generated fip_bin is %d bytes", len(fip_bin))
  504. if getattr(self, "rest_fip", None):
  505. logging.error("the rest of fip is not used: %#x bytes ", len(self.rest_fip))
  506. return fip_bin
  507. METHODS = {
  508. "NOR_INFO": FIP.add_nor_info,
  509. "NAND_INFO": FIP.add_nand_info,
  510. "CHIP_CONF": FIP.add_chip_conf,
  511. "BLCP": FIP.add_blcp,
  512. "BL2": FIP.add_bl2,
  513. "DDR_PARAM": FIP.add_ddr_param,
  514. "BLCP_2ND": FIP.add_blcp_2nd,
  515. "MONITOR": FIP.add_monitor,
  516. "LOADER_2ND": FIP.add_loader_2nd,
  517. }
  518. def generate_fip(args):
  519. logging.debug("generate_fip:")
  520. fip = FIP()
  521. if args.OLD_FIP:
  522. fip.read_fip(args.OLD_FIP)
  523. for m, f in METHODS.items():
  524. if getattr(args, m):
  525. f(fip, args)
  526. fip_bin = fip.make(args)
  527. fip.print_fip_params()
  528. if args.output:
  529. with open(args.output, "wb") as fp:
  530. fp.write(fip_bin)
  531. def parse_args():
  532. parser = argparse.ArgumentParser(description="FIP tools")
  533. parser.add_argument(
  534. "-v",
  535. "--verbose",
  536. help="Increase output verbosity",
  537. action="store_const",
  538. const=logging.DEBUG,
  539. default=logging.INFO,
  540. )
  541. subparsers = parser.add_subparsers(dest="subcmd", help="Sub-command help")
  542. pr_gen = subparsers.add_parser("genfip", help="Generate keys")
  543. for name in list(METHODS):
  544. if name in ["NOR_INFO", "NAND_INFO"]:
  545. pr_gen.add_argument("--" + name, type=bytes.fromhex)
  546. else:
  547. pr_gen.add_argument("--" + name, dest=name, type=str, help="Add %s into FIP" % name)
  548. def auto_int(x):
  549. return int(x, 0)
  550. pr_gen.add_argument("--BLCP_IMG_RUNADDR", type=auto_int)
  551. pr_gen.add_argument("--BLCP_PARAM_LOADADDR", type=auto_int)
  552. pr_gen.add_argument("--BLCP_2ND_RUNADDR", type=auto_int)
  553. pr_gen.add_argument("--MONITOR_RUNADDR", type=auto_int)
  554. pr_gen.add_argument("--compress", choices=["lzma", "lz4", ""])
  555. pr_gen.add_argument("--OLD_FIP", type=str)
  556. pr_gen.add_argument("--BLOCK_SIZE", type=auto_int)
  557. pr_gen.add_argument("--BL2_FILL", type=auto_int)
  558. pr_gen.add_argument("output", type=str, help="Output filename")
  559. pr_gen.set_defaults(func=generate_fip)
  560. if argcomplete:
  561. argcomplete.autocomplete(parser)
  562. args = parser.parse_args()
  563. init_logging(stdout_level=args.verbose)
  564. logging.info("PROG: %s", parser.prog)
  565. if not args.subcmd:
  566. parser.print_help()
  567. raise SystemExit(1)
  568. for a, v in sorted(vars(args).items()):
  569. logging.debug(" %s=%r", a, v)
  570. return args
  571. def main():
  572. args = parse_args()
  573. args.func(args)
  574. def init_logging(log_file=None, file_level="DEBUG", stdout_level="WARNING"):
  575. root_logger = logging.getLogger()
  576. root_logger.setLevel(logging.NOTSET)
  577. fmt = "%(asctime)s %(levelname)8s:%(name)s:%(message)s"
  578. if log_file is not None:
  579. file_handler = logging.FileHandler(log_file, encoding="utf-8")
  580. file_handler.setFormatter(logging.Formatter(fmt))
  581. file_handler.setLevel(file_level)
  582. root_logger.addHandler(file_handler)
  583. if coloredlogs:
  584. os.environ["COLOREDLOGS_DATE_FORMAT"] = "%H:%M:%S"
  585. field_styles = {
  586. "asctime": {"color": "green"},
  587. "hostname": {"color": "magenta"},
  588. "levelname": {"color": "black", "bold": True},
  589. "name": {"color": "blue"},
  590. "programname": {"color": "cyan"},
  591. }
  592. level_styles = coloredlogs.DEFAULT_LEVEL_STYLES
  593. level_styles["debug"]["color"] = "cyan"
  594. coloredlogs.install(
  595. level=stdout_level,
  596. fmt=fmt,
  597. field_styles=field_styles,
  598. level_styles=level_styles,
  599. milliseconds=True,
  600. )
  601. if __name__ == "__main__":
  602. main()