build_boot_image.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. #!/usr/bin/env python3
  2. #
  3. # Build Actions NVRAM config binary file
  4. #
  5. # Copyright (c) 2017 Actions Semiconductor Co., Ltd
  6. #
  7. # SPDX-License-Identifier: Apache-2.0
  8. #
  9. import os
  10. import sys
  11. import struct
  12. import array
  13. import argparse
  14. import zlib
  15. import configparser
  16. from ctypes import *;
  17. BINARY_BLOCK_SIZE_ALIGN = 512
  18. class BOOT_PARAMETERS(Structure): # import from ctypes
  19. _pack_ = 1
  20. _fields_ = [
  21. ("magic", c_uint32),
  22. ("uart_baudrate", c_uint32),
  23. ("uart_id", c_uint8),
  24. ("uart_mfp", c_uint8),
  25. ("jtag_groud", c_uint8),
  26. ("psram_mfp", c_uint8),
  27. ("adfu_txrx", c_uint8),
  28. ("adfu_gpio", c_uint8),
  29. ("reserved", c_uint8 * 10),
  30. ("psram_code", c_uint32),
  31. ("checksum", c_uint32),
  32. ] # 32 bytes
  33. SIZEOF_BOOT_PARAMETERS_VERSION = 0x20
  34. BOOT_PARAMETERS_MAGIC = 0x52415042 #'BPAR'
  35. BOOT_PARAMETERS_OFFSET = 0x30
  36. def c_struct_crc(c_struct, length):
  37. crc_buf = (c_byte * length)()
  38. memmove(addressof(crc_buf), addressof(c_struct), length)
  39. return zlib.crc32(crc_buf, 0) & 0xffffffff
  40. def generate_boot_parameters(boot_name, boot_ini_name, out_ini_bin):
  41. if os.path.exists(boot_ini_name):
  42. boot_param = BOOT_PARAMETERS()
  43. memset(addressof(boot_param), 0, SIZEOF_BOOT_PARAMETERS_VERSION)
  44. boot_param.magic = BOOT_PARAMETERS_MAGIC
  45. configer = configparser.ConfigParser()
  46. configer.read(boot_ini_name)
  47. uart_baudrate = configer.get("serial config", "uart_baudrate")
  48. if uart_baudrate != None:
  49. boot_param.uart_baudrate = int(uart_baudrate, 0)
  50. print('uart id %s' %(uart_baudrate))
  51. uart_id = configer.get("serial config", "uart_id")
  52. if uart_id != None:
  53. boot_param.uart_id = int(uart_id, 0)
  54. print('uart id %s' %(uart_id))
  55. uart_mfp = configer.get("serial config", "uart_mfp")
  56. if uart_mfp != None:
  57. boot_param.uart_mfp = int(uart_mfp, 0)
  58. print('uart id %s' %(uart_mfp))
  59. jtag_groud = configer.get("jtag config", "jtag_groud")
  60. if jtag_groud != None:
  61. boot_param.jtag_groud = int(jtag_groud, 0)
  62. print('jtag groud %s' %(jtag_groud))
  63. psram_mfp = configer.get("psram_config", "psram_mfp")
  64. if psram_mfp != None:
  65. boot_param.psram_mfp = int(psram_mfp, 0)
  66. print('psram mfp %s' %(psram_mfp))
  67. if configer.has_option("adfu config", "adfu_txrx") :
  68. adfu_txrx = configer.get("adfu config", "adfu_txrx")
  69. boot_param.adfu_txrx = int(adfu_txrx, 0)
  70. print('adfu_txrx %s' %(adfu_txrx))
  71. if configer.has_option("adfu config", "adfu_gpio") :
  72. adfu_gpio = configer.get("adfu config", "adfu_gpio")
  73. boot_param.adfu_gpio = int(adfu_gpio, 0)
  74. print('adfu_gpio %s' %(adfu_gpio))
  75. if configer.has_option("psram_config", "psram_code") :
  76. psram_code = configer.get("psram_config", "psram_code")
  77. if psram_code != None:
  78. boot_param.psram_code = int(psram_code, 0)
  79. print('psram_code len %s' %(psram_code))
  80. boot_param.checksum = c_struct_crc(boot_param, SIZEOF_BOOT_PARAMETERS_VERSION - 4)
  81. if out_ini_bin is None :
  82. with open(boot_name, 'rb+') as f:
  83. f.seek(BOOT_PARAMETERS_OFFSET, 0)
  84. f.write(boot_param)
  85. f.close()
  86. else :
  87. with open(out_ini_bin, 'wb+') as f:
  88. f.write(boot_param)
  89. f.close()
  90. def boot_padding(filename, align = BINARY_BLOCK_SIZE_ALIGN):
  91. fsize = os.path.getsize(filename)
  92. if fsize % align:
  93. padding_size = align - (fsize % align)
  94. print('fsize %d, padding_size %d' %(fsize, padding_size))
  95. with open(filename, 'rb+') as f:
  96. f.seek(fsize, 0)
  97. buf = (c_byte * padding_size)();
  98. f.write(buf)
  99. f.close()
  100. def boot_append_nand_id_table(filename, id_table_name):
  101. if not os.path.exists(id_table_name):
  102. return None
  103. fsize = os.path.getsize(filename)
  104. id_table_size = os.path.getsize(id_table_name)
  105. if id_table_size != 0:
  106. print('padding nand id table size %d' %(id_table_size))
  107. with open(id_table_name, 'rb') as f:
  108. read_buf = f.read()
  109. f.close()
  110. with open(filename, 'rb+') as f:
  111. f.seek(fsize, 0)
  112. f.write(read_buf)
  113. f.close()
  114. def boot_calc_checksum(data):
  115. s = sum(array.array('H',data))
  116. s = s & 0xffff
  117. return s
  118. def lark_boot_post_build(boot_name, boot_ini_name, nand_id_name):
  119. boot_len = os.path.getsize(boot_name)
  120. print('lark boot loader origin length %d.' %boot_len)
  121. generate_boot_parameters(boot_name, boot_ini_name, None)
  122. boot_append_nand_id_table(boot_name, nand_id_name)
  123. boot_padding(boot_name)
  124. boot_len_new = os.path.getsize(boot_name)
  125. print('boot loader new length %d.' %boot_len_new)
  126. with open(boot_name, 'rb+') as f:
  127. f.seek(0, 0)
  128. data = f.read(32)
  129. h_magic0,h_magic1,h_load_addr,h_name,h_version, \
  130. h_header_size,h_header_chksm,h_data_chksm,\
  131. h_body_size,h_tail_size \
  132. = struct.unpack('III4sHHHHII',data)
  133. if(h_magic0 != 0x48544341 or h_magic1 != 0x41435448):
  134. print('boot loader header check fail.')
  135. return
  136. h_body_size = boot_len_new - h_header_size
  137. f.seek(0x18, 0)
  138. f.write(struct.pack('<I', h_body_size))
  139. # use tail_size to record origin boot size
  140. h_tail_size = boot_len
  141. f.seek(0x1c, 0)
  142. f.write(struct.pack('<I', h_tail_size))
  143. f.seek(h_header_size, 0)
  144. data = f.read(h_body_size)
  145. checksum = boot_calc_checksum(data)
  146. checksum = 0xffff - checksum
  147. f.seek(0x16, 0)
  148. f.write(struct.pack('<H', checksum))
  149. f.seek(0x14, 0)
  150. f.write(struct.pack('<H', 0))
  151. f.seek(0x0, 0)
  152. data = f.read(h_header_size)
  153. checksum = boot_calc_checksum(data)
  154. checksum = 0xffff - checksum
  155. f.seek(0x14, 0)
  156. f.write(struct.pack('<H', checksum))
  157. f.close()
  158. print('boot loader add cksum pass.')
  159. """
  160. ******lark use tlv*******************
  161. """
  162. """
  163. #define IMAGE_TLV_BOOTINI 0x1000 /* INI*/
  164. #define IMAGE_TLV_NANDID 0x2000 /* nand id */
  165. """
  166. IMAGE_TLV_BOOTINI=0x1000
  167. IMAGE_TLV_NANDID=0x2000
  168. IMAGE_TLV_INFO_MAGIC=0x5935
  169. IMAGE_TLV_PROT_INFO_MAGIC=0x593a
  170. def img_header_check(img_bin_f):
  171. """
  172. check img header, and add h_img_size
  173. """
  174. img_len = os.path.getsize(img_bin_f)
  175. print('img origin length 0x%x' %(img_len))
  176. if img_len % 4:
  177. boot_padding(img_bin_f, 4)
  178. img_len = os.path.getsize(img_bin_f)
  179. print('img align 4 length %d' %(img_len))
  180. with open(img_bin_f, 'rb+') as f:
  181. f.seek(0, 0)
  182. data = f.read(48)
  183. h_magic0,h_magic1,h_load_addr,h_name,h_run_addr,h_img_size,h_img_chksum, h_hdr_chksum, \
  184. h_header_size,h_ptlv_size,h_tlv_size,h_version,h_flags \
  185. = struct.unpack('III8sIIIIHHHHI',data)
  186. if(h_magic0 != 0x48544341 or h_magic1 != 0x41435448):
  187. print('magic header check fail.')
  188. sys.exit(1)
  189. if h_ptlv_size == 0:
  190. print('img h_header_size %d.' %h_header_size)
  191. h_img_size = img_len - h_header_size
  192. f.seek(0x18, 0)
  193. f.write(struct.pack('<I', h_img_size))
  194. print('img h_img_size %d.' %h_img_size)
  195. f.seek(0x26, 0)
  196. f.write(struct.pack('<h', 0))
  197. f.close()
  198. def Add_data_to_tlv(img_bin_f, tlv_data_bin_f, tlv_type):
  199. """
  200. add data tlv
  201. """
  202. if not os.path.exists(tlv_data_bin_f):
  203. return 0
  204. img_len = os.path.getsize(img_bin_f)
  205. tlv_len = os.path.getsize(tlv_data_bin_f)
  206. print('tlv data length 0x%x, img_len=0x%x' %(tlv_len,img_len))
  207. with open(tlv_data_bin_f, 'rb') as f:
  208. tlv_data = f.read()
  209. f.close()
  210. with open(img_bin_f, 'rb+') as f:
  211. f.seek(0, 0)
  212. data = f.read(48)
  213. h_magic0,h_magic1,h_load_addr,h_name,h_run_addr,h_img_size,h_img_chksum, h_hdr_chksum, \
  214. h_header_size,h_ptlv_size,h_tlv_size,h_version,h_flags \
  215. = struct.unpack('III8sIIIIHHHHI',data)
  216. if(h_magic0 != 0x48544341 or h_magic1 != 0x41435448):
  217. print('magic header check fail.')
  218. sys.exit(1)
  219. plv_start = h_header_size + h_img_size + h_ptlv_size
  220. print('plv_start 0x%x,header_size=0x%x img_len=0x%x ptlv_size=0x%x, tlv_size=0x%x' %(plv_start, h_header_size, h_img_size, h_ptlv_size, h_tlv_size))
  221. f.seek(plv_start, 0)
  222. tlv_all_size = tlv_len + 4
  223. tlv_tol_size = 0
  224. if(plv_start == img_len):#not tlv header
  225. print('add tlv magic')
  226. tlv_tol_size = tlv_all_size
  227. f.write(struct.pack('<h', IMAGE_TLV_INFO_MAGIC))
  228. f.write(struct.pack('<h', tlv_tol_size))
  229. else :
  230. data1 = f.read(4)
  231. tlv_magic, tlv_tol_size= struct.unpack('HH',data1)
  232. if(tlv_magic != IMAGE_TLV_INFO_MAGIC):
  233. print('tlv magic check fail.')
  234. sys.exit(1)
  235. print('old tlv_tol_size 0x%x' %(tlv_tol_size))
  236. new_tlv_start = plv_start + tlv_tol_size + 4
  237. tlv_tol_size = tlv_tol_size + tlv_all_size
  238. f.seek(plv_start+2, 0)
  239. f.write(struct.pack('<h', tlv_tol_size))
  240. f.seek(new_tlv_start, 0)
  241. print('tlv_tol_size %d' %(tlv_tol_size))
  242. f.write(struct.pack('<h', tlv_type))
  243. f.write(struct.pack('<h', tlv_len))
  244. f.write(tlv_data)
  245. f.close()
  246. tlv_tol_size = tlv_tol_size + 4
  247. #if(tlv_tol_size > h_tlv_size):
  248. # print('tlv_tol_size %d > header tlv size %d'%(tlv_tol_size, h_tlv_size))
  249. #sys.exit(1)
  250. return tlv_tol_size
  251. return 0
  252. def image_calc_checksum(data):
  253. s = sum(array.array('I',data))
  254. s = s & 0xffffffff
  255. return s
  256. def image_add_cksum(filename, tlv_size):
  257. with open(filename, 'rb+') as f:
  258. f.seek(0, 0)
  259. data = f.read(48)
  260. h_magic0,h_magic1,h_load_addr,h_name,h_run_addr,h_img_size,h_img_chksum, h_hdr_chksum, \
  261. h_header_size,h_ptlv_size,h_tlv_size,h_version,h_flags \
  262. = struct.unpack('III8sIIIIHHHHI',data)
  263. if(h_magic0 != 0x48544341 or h_magic1 != 0x41435448):
  264. print('magic header check fail.')
  265. sys.exit(1)
  266. print('img header_size %d, img size=%d, ptlv_size=%d' %(h_header_size,h_img_size, h_ptlv_size))
  267. if h_ptlv_size == 0:
  268. f.seek(h_header_size, 0)
  269. data = f.read(h_img_size)
  270. checksum = image_calc_checksum(data)
  271. checksum = 0xffffffff - checksum
  272. f.seek(0x1c, 0)
  273. f.write(struct.pack('<I', checksum))
  274. print('img checksum 0x%x.' %checksum)
  275. f.seek(0x28, 0)
  276. f.write(struct.pack('<H', tlv_size))
  277. f.seek(0x0, 0)
  278. data = f.read(h_header_size)
  279. checksum = image_calc_checksum(data)
  280. checksum = 0xffffffff - checksum
  281. f.seek(0x20, 0)
  282. f.write(struct.pack('<I', checksum))
  283. print('header checksum 0x%x.' %checksum)
  284. print('boot loader add cksum pass.')
  285. f.close()
  286. def lark_boot_post_build(boot_name, boot_ini_name, nand_id_name):
  287. print('lark boot add ini & nand id to tlv')
  288. img_header_check(boot_name)
  289. boot_ini_f = os.path.join(os.path.dirname(boot_name), 'bootini.bin')
  290. generate_boot_parameters(boot_name, boot_ini_name, boot_ini_f)
  291. tlv_size = Add_data_to_tlv(boot_name, boot_ini_f,IMAGE_TLV_BOOTINI)
  292. tmp_size = Add_data_to_tlv(boot_name, nand_id_name,IMAGE_TLV_NANDID)
  293. if (tmp_size != 0) :
  294. tlv_size = tmp_size
  295. image_add_cksum(boot_name, tlv_size)
  296. boot_padding(boot_name)
  297. def pearlriver_boot_post_build(boot_name, boot_ini_name):
  298. print('pearlriver boot add ini')
  299. img_header_check(boot_name)
  300. boot_ini_f = os.path.join(os.path.dirname(boot_name), 'bootini.bin')
  301. generate_boot_parameters(boot_name, boot_ini_name, boot_ini_f)
  302. tlv_size = Add_data_to_tlv(boot_name, boot_ini_f,IMAGE_TLV_BOOTINI)
  303. image_add_cksum(boot_name, tlv_size)
  304. boot_padding(boot_name)
  305. def boot_post_build(boot_name, boot_ini_name, nand_id_name):
  306. with open(boot_name, 'rb+') as f:
  307. f.seek(0, 0)
  308. data = f.read(16)
  309. f.close()
  310. h_magic0,h_magic1,h_load_addr,h_name = struct.unpack('III4s',data)
  311. if(h_magic0 != 0x48544341 or h_magic1 != 0x41435448):
  312. print('boot loader header check fail.')
  313. return
  314. print('boot name =%s'% h_name)
  315. if(h_name == b'boot'):
  316. lark_boot_post_build(boot_name, boot_ini_name, nand_id_name)
  317. elif(h_name == b'brec'):
  318. pearlriver_boot_post_build(boot_name, boot_ini_name)
  319. else:
  320. lark_boot_post_build(boot_name, boot_ini_name, nand_id_name)
  321. def main(argv):
  322. boot_post_build(argv[1], argv[2], argv[3])
  323. if __name__ == "__main__":
  324. main(sys.argv)