build_firmware.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197
  1. #!/usr/bin/env python3
  2. #
  3. # Build Actions SoC firmware (RAW/USB/OTA)
  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 time
  12. import struct
  13. import argparse
  14. import platform
  15. import subprocess
  16. import array
  17. import hashlib
  18. import shutil
  19. import zipfile
  20. import xml.etree.ElementTree as ET
  21. import zlib
  22. import json
  23. import traceback
  24. import csv
  25. import re
  26. from ctypes import *
  27. # private module
  28. from nvram_prop import *;
  29. CFG_TEST_GENERATE_OTA_FIRMWARES_COUNT = 3
  30. CFG_FIRMWARE_NEED_ENCYPT = False
  31. PRODUCTION_GLOBAL_BUFFER_DEFAULT_SIZE = 0x1000000
  32. PARTITION_ALIGNMENT = 0x1000
  33. class PARTITION_ENTRY(Structure): # import from ctypes
  34. _pack_ = 1
  35. _fields_ = [
  36. ("name", c_uint8 * 8),
  37. ("type", c_uint8),
  38. ("file_id", c_uint8),
  39. ("mirror_id", c_uint8, 4),
  40. ("storage_id", c_uint8, 4),
  41. ("flag", c_uint8),
  42. ("offset", c_uint32),
  43. ("size", c_uint32),
  44. ("entry_offs", c_uint32),
  45. ] # 64 bytes
  46. SIZEOF_PARTITION_ENTRY = 0x18
  47. class PARTITION_TABLE(Structure): # import from ctypes
  48. _pack_ = 1
  49. _fields_ = [
  50. ("magic", c_uint32),
  51. ("version", c_uint16),
  52. ("table_size", c_uint16),
  53. ("part_cnt", c_uint16),
  54. ("part_entry_size", c_uint16),
  55. ("reserved1", c_uint8 * 4),
  56. ("parts", PARTITION_ENTRY * 30),
  57. ("reserved2", c_uint8 * 4),
  58. ("table_crc", c_uint32),
  59. ] # 64 bytes
  60. SIZEOF_PARTITION_TABLE = 0x2e8
  61. PARTITION_TABLE_MAGIC = 0x54504341 #'ACPT'
  62. partition_type_table = {'RESERVED':0, 'BOOT':1, 'SYSTEM':2, 'RECOVERY':3, 'DATA':4, 'TEMP':5, 'SYS_PARAM':6}
  63. class FIRMWARE_VERSION(Structure): # import from ctypes
  64. _pack_ = 1
  65. _fields_ = [
  66. ("magic", c_uint32),
  67. ("version_code", c_uint32),
  68. ("version_res", c_uint32),
  69. ("sys_version_code",c_uint32),
  70. ("version_name", c_uint8 * 64),
  71. ("board_name", c_uint8 * 32),
  72. ("reserved", c_uint8 * 12),
  73. ("checksum", c_uint32),
  74. ] # 128 bytes
  75. SIZEOF_FIRMWARE_VERSION = 0x80
  76. FIRMWARE_VERSION_MAGIC = 0x52455646 #'FVER'
  77. class IMAGE_HEADER(Structure): # import from ctypes
  78. _pack_ = 1
  79. _fields_ = [
  80. ("magic", c_uint32),
  81. ("version", c_uint16),
  82. ("header_size", c_uint16),
  83. ("data_type", c_uint16),
  84. ("data_flag", c_uint16),
  85. ("data_offset", c_uint32),
  86. ("data_size", c_uint32),
  87. ("data_base_vaddr", c_uint32),
  88. ("data_entry_vaddr", c_uint32),
  89. ("data_checksum", c_uint32),
  90. ("reserved", c_uint8 * 28),
  91. ("header_crc", c_uint32),
  92. ] # 64 bytes
  93. SIZEOF_IMAGE_HEADER = 64
  94. IMAGE_HEADER_MAGIC = 0x4d494341 #'ACIM'
  95. MP_CARD_CFG_NAME="mp_card.cfg"
  96. FW_MAKER_EXT_CFG_NAME="fw_maker_ext.cfg"
  97. FW_BUILD_TIME_FILE_NAME="fw_build_time.bin";
  98. script_path = os.path.split(os.path.realpath(__file__))[0]
  99. soc_name = ''
  100. board_name = ''
  101. encrypt_fw = ''
  102. efuse_bin = ''
  103. ext_name = ''
  104. # table for calculating CRC
  105. CRC16_TABLE = [
  106. 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
  107. 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
  108. 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
  109. 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
  110. 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
  111. 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
  112. 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
  113. 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
  114. 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
  115. 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
  116. 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
  117. 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
  118. 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
  119. 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
  120. 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
  121. 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
  122. 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
  123. 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
  124. 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
  125. 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
  126. 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
  127. 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
  128. 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
  129. 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
  130. 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
  131. 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
  132. 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
  133. 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
  134. 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
  135. 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
  136. 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
  137. 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78,
  138. ]
  139. def reflect(crc):
  140. """
  141. :type n: int
  142. :rtype: int
  143. """
  144. m = ['0' for i in range(16)]
  145. b = bin(crc)[2:]
  146. m[:len(b)] = b[::-1]
  147. return int(''.join(m) ,2)
  148. def _crc16(data, crc, table):
  149. """Calculate CRC16 using the given table.
  150. `data` - data for calculating CRC, must be bytes
  151. `crc` - initial value
  152. `table` - table for caclulating CRC (list of 256 integers)
  153. Return calculated value of CRC
  154. polynom : 0x1021
  155. order : 16
  156. crcinit : 0xffff
  157. crcxor : 0x0
  158. refin : 1
  159. refout : 1
  160. """
  161. crc = reflect(crc)
  162. for byte in data:
  163. crc = ((crc >> 8) & 0xff) ^ table[(crc & 0xff) ^ byte]
  164. crc = reflect(crc)
  165. # swap byte
  166. crc = ((crc >> 8) & 0xff) | ((crc & 0xff) << 8)
  167. return crc
  168. def crc16(data, crc=0xffff):
  169. """Calculate CRC16.
  170. `data` - data for calculating CRC, must be bytes
  171. `crc` - initial value
  172. Return calculated value of CRC
  173. """
  174. return _crc16(data, crc, CRC16_TABLE)
  175. def md5_file(filename):
  176. if os.path.isfile(filename):
  177. with open(filename, 'rb') as f:
  178. md5 = hashlib.md5()
  179. md5.update(f.read())
  180. hash = md5.hexdigest()
  181. return str(hash)
  182. return None
  183. def crc32_file(filename):
  184. if os.path.isfile(filename):
  185. with open(filename, 'rb') as f:
  186. crc = zlib.crc32(f.read(), 0) & 0xffffffff
  187. return crc
  188. return 0
  189. def pad_file(filename, align = 4, fillbyte = 0xff):
  190. with open(filename, 'ab') as f:
  191. filesize = f.tell()
  192. if (filesize % align):
  193. padsize = align - filesize & (align - 1)
  194. f.write(bytearray([fillbyte]*padsize))
  195. def new_file(filename, filesize, fillbyte = 0xff):
  196. with open(filename, 'wb') as f:
  197. f.write(bytearray([fillbyte]*filesize))
  198. def dd_file(input_file, output_file, count=None, seek=None, skip=None):
  199. inf = open(input_file, mode='rb')
  200. outf = open(output_file, mode='rb+')
  201. if skip is not None:
  202. inf.seek(skip)
  203. if seek is not None:
  204. outf.seek(seek)
  205. if count is None:
  206. count = os.path.getsize(input_file)
  207. outf.write(inf.read(count))
  208. inf.close
  209. outf.close
  210. def file_link(filename, file_add):
  211. if not os.path.exists(filename):
  212. return
  213. if not os.path.exists(file_add):
  214. return
  215. #print("file %s, link %s \n" %(filename, file_add))
  216. with open(file_add, 'rb') as fa:
  217. file_data = fa.read()
  218. fa.close()
  219. fsize = os.path.getsize(filename)
  220. with open(filename, 'rb+') as f:
  221. f.seek(fsize, 0)
  222. f.write(file_data)
  223. f.close()
  224. def zip_dir(source_dir, output_filename):
  225. zf = zipfile.ZipFile(output_filename, 'w')
  226. pre_len = len(os.path.dirname(source_dir))
  227. for parent, dirnames, filenames in os.walk(source_dir):
  228. for filename in filenames:
  229. pathfile = os.path.join(parent, filename)
  230. arcname = pathfile[pre_len:].strip(os.path.sep)
  231. zf.write(pathfile, arcname)
  232. zf.close()
  233. def memcpy_n(cbuffer, bufsize, pylist):
  234. size = min(bufsize, len(pylist))
  235. for i in range(size):
  236. cbuffer[i]= ord(pylist[i])
  237. def c_struct_crc(c_struct, length):
  238. crc_buf = (c_byte * length)()
  239. memmove(addressof(crc_buf), addressof(c_struct), length)
  240. return zlib.crc32(crc_buf, 0) & 0xffffffff
  241. def align_down(data, alignment):
  242. return data // alignment * alignment
  243. def align_up(data, alignment):
  244. return align_down(data + alignment - 1, alignment)
  245. def run_cmd(cmd):
  246. """Echo and run the given command.
  247. Args:
  248. cmd: the command represented as a list of strings.
  249. Returns:
  250. A tuple of the output and the exit code.
  251. """
  252. # print("Running: ", " ".join(cmd))
  253. p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  254. output, _ = p.communicate()
  255. # print("%s" % (output.rstrip()))
  256. return (output, p.returncode)
  257. def panic(err_msg):
  258. #print('\033[1;31;40m')
  259. print('\nFW: Error: %s\n' %err_msg)
  260. #print('\033[0m')
  261. sys.exit(1)
  262. def print_notice(msg):
  263. print('\033[1;32;40m%s\033[0m' %msg)
  264. def cygpath(upath):
  265. cmd = ['cygpath', '-w', upath]
  266. (wpath, exit_code) = run_cmd(cmd)
  267. if (0 != exit_code):
  268. return upath
  269. return wpath.decode().strip()
  270. def is_windows():
  271. sysstr = platform.system()
  272. if (sysstr.startswith('Windows') or \
  273. sysstr.startswith('MSYS') or \
  274. sysstr.startswith('MINGW') or \
  275. sysstr.startswith('CYGWIN')):
  276. return True
  277. else:
  278. return False
  279. def is_msys():
  280. sysstr = platform.system()
  281. if (sysstr.startswith('MSYS') or \
  282. sysstr.startswith('MINGW') or \
  283. sysstr.startswith('CYGWIN')):
  284. return True
  285. else:
  286. return False
  287. def soc_is_andes():
  288. if soc_name == 'andes':
  289. return True
  290. else:
  291. return False
  292. class firmware(object):
  293. def __init__(self, cfg_file):
  294. self.crc_chunk_size = 32
  295. self.crc_full_chunk_size = self.crc_chunk_size + 2
  296. self.part_num = 0
  297. self.partitions = []
  298. self.disk_size = 0x400000 # 4MB by default
  299. self.fw_xml_file = cfg_file
  300. self.fw_dir = os.path.dirname(cfg_file)
  301. self.bin_dir = os.path.join(self.fw_dir, 'bin')
  302. self.ota_dir = os.path.join(self.fw_dir, 'ota')
  303. self.orig_bin_dir = self.bin_dir + '_orig'
  304. self.orig_ota_dir = self.ota_dir + '_orig'
  305. self.fw_version = {}
  306. self.boot_file_name = ''
  307. self.param_file_name = ''
  308. self.is_earphone_app = False
  309. self.upgrade_baudrate = 2000000
  310. self.atf_file_list = []
  311. if "bt_earphone" in os.path.abspath(self.fw_dir).split('\\'):
  312. self.is_earphone_app = True
  313. print("is earphone SDK")
  314. # self.parse_config(cfg_file)
  315. def _get_partition_info(self, keyword, keystr):
  316. if self.partitions:
  317. for info_dict in self.partitions:
  318. if keyword in info_dict and keystr == info_dict[keyword]:
  319. return info_dict
  320. return {}
  321. def parse_config(self):
  322. #print('FW: Parse config file: %s' %self.fw_xml_file)
  323. tree = ET.ElementTree(file=self.fw_xml_file)
  324. root = tree.getroot()
  325. if (root.tag != 'firmware'):
  326. sys.stderr.write('error: invalid firmware config file')
  327. sys.exit(1)
  328. disk_size_prop = root.find('disk_size')
  329. if disk_size_prop is not None:
  330. self.disk_size = int(disk_size_prop.text.strip(), 0)
  331. firmware_version = root.find('firmware_version')
  332. for prop in firmware_version:
  333. self.fw_version[prop.tag] = prop.text.strip()
  334. if 'version_name' in self.fw_version.keys():
  335. cur_time = time.strftime('%y%m%d%H%M',time.localtime(time.time()))
  336. version_name = self.fw_version['version_name'].replace('$(build_time)', cur_time)
  337. self.fw_version['version_name'] = version_name
  338. # gen fw build time file
  339. fw_build_time_file = os.path.join(self.fw_dir, FW_BUILD_TIME_FILE_NAME)
  340. with open(fw_build_time_file, 'w') as f:
  341. f.write(cur_time)
  342. part_list = root.find('partitions').findall('partition')
  343. for part in part_list:
  344. part_prop = {}
  345. for prop in part:
  346. part_prop[prop.tag] = prop.text.strip()
  347. if 'file_name' in part_prop.keys():
  348. bin_file = os.path.join(self.bin_dir, part_prop['file_name'])
  349. else:
  350. bin_file = None
  351. if bin_file and ('SYS_PARAM' != part_prop['type']) and not os.path.exists(bin_file):
  352. print_notice('partition %s ignored: cannot found bin %s' %(part_prop['name'], bin_file))
  353. else:
  354. self.partitions.append(part_prop)
  355. self.part_num = self.part_num + 1
  356. self.part_num = len(self.partitions);
  357. # print(self.part_num)
  358. # print(self.partitions)
  359. if (0 == self.part_num):
  360. panic('cannot found parition config')
  361. for part in self.partitions:
  362. if ('file_name' in part.keys()) and ('BOOT' == part['type']):
  363. self.boot_file_name = part['file_name']
  364. for part in self.partitions:
  365. if ('file_name' in part.keys()) and ('SYS_PARAM' == part['type']):
  366. self.param_file_name = part['file_name']
  367. param_file = os.path.join(self.bin_dir, self.param_file_name)
  368. self.generate_partition_table(param_file)
  369. self.generate_firmware_version(param_file)
  370. if os.path.isdir(self.orig_bin_dir):
  371. shutil.rmtree(self.orig_bin_dir)
  372. time.sleep(0.1)
  373. shutil.copytree(self.bin_dir, self.orig_bin_dir)
  374. self.rebuild_sdfs(self.bin_dir)
  375. self.check_part_file_size()
  376. self.generate_crc_file()
  377. if os.path.isfile(efuse_bin):
  378. self.encrypt_files()
  379. elif CFG_FIRMWARE_NEED_ENCYPT:
  380. panic('firmware encryt must be enabled')
  381. def __find_key_info(self, key, cfg_str):
  382. # key defintion pattern: key = "string0, string1";
  383. key_p = re.compile('^\s*%s\s*=\s*"(.+)"\s*;\s*$' %key, re.M)
  384. cfg_info_list = key_p.findall(cfg_str)
  385. if cfg_info_list:
  386. info_str = ', '.join(cfg_info_list)
  387. info_list = [i.strip() for i in info_str.split(',')]
  388. return info_list
  389. else:
  390. return []
  391. def rebuild_sdfs(self, bin_dir):
  392. """rebuild sdfs, in order to append configuration and tone files.
  393. """
  394. fw_cfg_file = os.path.join(bin_dir, "fw_configuration.cfg")
  395. if not os.path.isfile(fw_cfg_file):
  396. return False
  397. try:
  398. with open(fw_cfg_file, 'r') as f:
  399. cfg_str = f.read()
  400. except:
  401. with open(fw_cfg_file, 'r', encoding = 'utf-8') as f:
  402. cfg_str = f.read()
  403. count = 0
  404. dst_dir = None
  405. key_list = self.__find_key_info('CFG_FILE_KEY', cfg_str)
  406. if key_list:
  407. config_dir = os.path.join(bin_dir, 'config')
  408. if "TONE_SDFS" in key_list:
  409. key_list.remove("TONE_SDFS")
  410. dst_dir = os.path.join(bin_dir, 'sdfs')
  411. if not os.path.isdir(dst_dir):
  412. dst_dir = os.path.join(bin_dir, 'tone')
  413. elif "SYS_SDFS" in key_list:
  414. key_list.remove("SYS_SDFS")
  415. dst_dir = os.path.join(bin_dir, 'ksdfs')
  416. if dst_dir and os.path.isdir(dst_dir) and os.path.isdir(config_dir):
  417. for key in key_list:
  418. file_name_list = self.__find_key_info(key, cfg_str)
  419. count += len(file_name_list)
  420. for file_name in file_name_list:
  421. #print(file_name)
  422. shutil.copyfile(os.path.join(config_dir, file_name),
  423. os.path.join(dst_dir, file_name))
  424. if count > 0:
  425. sdfs_name = os.path.basename(dst_dir)
  426. script_sdfs_path = os.path.join(script_path, 'build_sdfs.py')
  427. sdfs_bin_path = os.path.join(bin_dir, sdfs_name+".bin")
  428. cmd = ['python', '-B', script_sdfs_path, '-o', sdfs_bin_path, '-d', dst_dir]
  429. (outmsg, exit_code) = run_cmd(cmd)
  430. if exit_code !=0:
  431. print('make build_sdfs_bin error')
  432. print(outmsg.decode('utf-8'))
  433. sys.exit(1)
  434. #print("\n build_sdfs %s finshed\n\n" %(sdfs_name))
  435. return True
  436. return False
  437. def check_part_file_size(self):
  438. csv_file = os.path.join(self.bin_dir, 'partition_size.csv')
  439. csv_f = open(csv_file, 'w', newline = '')
  440. csv_writer = csv.writer(csv_f, dialect = 'excel')
  441. csv_writer.writerow(['partition', 'size', 'real size', 'free'])
  442. for part in self.partitions:
  443. if not 'file_name' in part.keys():
  444. continue
  445. partfile = os.path.join(self.bin_dir, part['file_name']);
  446. if os.path.isfile(partfile):
  447. partfile_size = os.path.getsize(partfile)
  448. part_size = int(part['size'], 0);
  449. part_addr = int(part['address'], 0);
  450. file_addr = int(part['file_address'], 0);
  451. if part['type'] == 'SYSTEM':
  452. ksdfs_bin_file = os.path.join(self.bin_dir, "ksdfs.bin")
  453. if os.path.isfile(ksdfs_bin_file):
  454. file_link(partfile, ksdfs_bin_file)
  455. partfile_size += os.path.getsize(ksdfs_bin_file)
  456. if file_addr < part_addr or file_addr >= (part_addr + part_size) :
  457. panic('partition %s: invalid file_address 0x%x' \
  458. %(part['name'], file_addr))
  459. part_file_max_size = part_size - (file_addr - part_addr)
  460. csv_writer.writerow([part['file_name'],
  461. "%.2f" %(part_file_max_size / 1024),
  462. "%.2f" %(partfile_size / 1024),
  463. "%.2f" %((part_file_max_size - partfile_size) / 1024)])
  464. print('partition %s: \'%s\' file size 0x%x(%d KB), max size 0x%x(%d KB)!' \
  465. %(part['name'], part['file_name'], partfile_size, partfile_size/1024, \
  466. part_file_max_size, part_file_max_size/1024))
  467. if partfile_size > part_file_max_size:
  468. csv_f.close()
  469. panic('partition %s: \'%s\' file size 0x%x is bigger than partition size 0x%x!' \
  470. %(part['name'], part['file_name'], partfile_size, part_size))
  471. csv_f.close()
  472. def boot_calc_checksum(self, data):
  473. s = sum(array.array('H',data))
  474. s = s & 0xffff
  475. return s
  476. def get_nvram_prop(self, name):
  477. prop_file = os.path.join(self.bin_dir, 'nvram.prop');
  478. if os.path.isfile(prop_file):
  479. with open(prop_file) as f:
  480. properties = PropFile(f.readlines())
  481. return properties.get(name)
  482. return ''
  483. def generate_crc_file(self):
  484. crc_files = []
  485. for part in self.partitions:
  486. if ('file_name' in part.keys()) and ('true' == part['enable_crc']):
  487. crc_files.append(part['file_name'])
  488. crc_files = list(set(crc_files))
  489. for crc_file in crc_files:
  490. self.add_crc(os.path.join(self.bin_dir, crc_file), self.crc_chunk_size)
  491. def encrypt_file(self, file_path, blk_size):
  492. #print ('FW: encrypt file %s' %(file_path))
  493. if not os.path.isfile(encrypt_fw):
  494. panic('Cannot found encrypt fw')
  495. if (is_windows()):
  496. # windows
  497. fw2x_path = script_path + '/utils/windows/fw2x.exe'
  498. else:
  499. if ('32bit' == platform.architecture()[0]):
  500. # linux x86
  501. fw2x_path = script_path + '/utils/linux-x86/fw2x/fw2x'
  502. else:
  503. # linux x86_64
  504. fw2x_path = script_path + '/utils/linux-x86_64/fw2x/fw2x'
  505. chip_name = "DVB"
  506. fwimage_cfg_file = os.path.join(self.orig_bin_dir, "fwimage.cfg")
  507. if os.path.isfile(fwimage_cfg_file):
  508. with open(fwimage_cfg_file, 'r') as f:
  509. cfg_str = f.read()
  510. # CHIP_NAME = "ATS3085C";
  511. name_p = re.compile('^\s*CHIP_NAME\s*=\s*\"\s*(\w+)\s*\";$', re.M)
  512. name_obj = name_p.search(cfg_str)
  513. if name_obj:
  514. chip_name = name_obj.groups()[0]
  515. # extrace lfi.bin from btsys.fw
  516. fw2x_cmd = [fw2x_path, '-fsssfffs', encrypt_fw, 'MakeEncryptBin',\
  517. 'Encrypt', str(blk_size), file_path, file_path, efuse_bin, chip_name]
  518. (outmsg, exit_code) = run_cmd(fw2x_cmd)
  519. if exit_code != 0:
  520. print('FW2X: encrypt file %s error' %(file_path))
  521. print(outmsg.decode('utf-8'))
  522. sys.exit(1)
  523. def encrypt_files(self):
  524. for part in self.partitions:
  525. if CFG_FIRMWARE_NEED_ENCYPT:
  526. if ('BOOT' == part['type'] or 'SYSTEM' == part['type'] or 'RECOVERY' == part['type']) or 'SYS_PARAM' == part['type'] \
  527. and ('true' != part['enable_encryption']):
  528. panic('BOOT/SYSTEM partition must enable encryption')
  529. sys.exit(3)
  530. if not 'file_name' in part.keys():
  531. continue
  532. if ('true' == part['enable_encryption']):
  533. print ('FW: encrypt file \'' + part['file_name'] + '\'')
  534. encrypt_unit = self.crc_chunk_size
  535. if 'BOOT' == part['type']:
  536. encrypt_unit = 512
  537. if ('true' == part['enable_crc']):
  538. self.encrypt_file(os.path.join(self.bin_dir, part['file_name']), encrypt_unit + 2)
  539. else:
  540. self.encrypt_file(os.path.join(self.bin_dir, part['file_name']), encrypt_unit)
  541. def encrypt_param_file(self, param_file):
  542. for part in self.partitions:
  543. if ('file_name' in part.keys() and 'SYS_PARAM' == part['type']):
  544. if ('true' == part['enable_encryption']):
  545. if ('true' == part['enable_crc']):
  546. self.encrypt_file(param_file, self.crc_full_chunk_size)
  547. else:
  548. self.encrypt_file(param_file, self.crc_chunk_size)
  549. def generate_partition_table(self, param_file):
  550. part_tbl = PARTITION_TABLE()
  551. memset(addressof(part_tbl), 0, SIZEOF_PARTITION_TABLE)
  552. part_tbl.magic = PARTITION_TABLE_MAGIC
  553. part_tbl.version = 0x0101
  554. part_tbl.table_size = SIZEOF_PARTITION_TABLE
  555. part_tbl.table_crc = 0x0
  556. part_tbl.part_entry_size = SIZEOF_PARTITION_ENTRY
  557. idx = 0
  558. for part in self.partitions:
  559. memcpy_n(part_tbl.parts[idx].name, 8, part['name'])
  560. part_tbl.parts[idx].type = partition_type_table[part['type']]
  561. part_tbl.parts[idx].file_id = int(part['file_id'])
  562. if 'mirror_id' in part.keys():
  563. part_tbl.parts[idx].mirror_id = int(part['mirror_id'])
  564. else:
  565. part_tbl.parts[idx].mirror_id = 0xf
  566. if 'storage_id' in part.keys():
  567. part_tbl.parts[idx].storage_id = int(part['storage_id'])
  568. else:
  569. part_tbl.parts[idx].storage_id = 0x0
  570. #print('part [%d] mirror id %d' %(idx, part_tbl.parts[idx].mirror_id))
  571. part_tbl.parts[idx].flag = 0
  572. if 'enable_crc' in part.keys() and 'true' == part['enable_crc']:
  573. part_tbl.parts[idx].flag |= 0x1
  574. if 'enable_encryption' in part.keys() and 'true' == part['enable_encryption']:
  575. part_tbl.parts[idx].flag |= 0x2
  576. if 'enable_boot_check' in part.keys() and 'true' == part['enable_boot_check']:
  577. part_tbl.parts[idx].flag |= 0x4
  578. if 'enable_sector' in part.keys() and 'true' == part['enable_sector']:
  579. part_tbl.parts[idx].flag |= 0x8
  580. part_addr = int(part['address'], 0)
  581. part_size = int(part['size'], 0)
  582. file_addr = int(part['file_address'], 0)
  583. if part_addr & (PARTITION_ALIGNMENT - 1):
  584. panic('partition %s: unaligned part address 0x%x, need be aligned with 0x%x' \
  585. %(part['name'], part_addr, PARTITION_ALIGNMENT))
  586. if part_size & (PARTITION_ALIGNMENT - 1):
  587. panic('partition %s: unaligned part size 0x%x, need be aligned with 0x%x' \
  588. %(part['name'], part_size, PARTITION_ALIGNMENT))
  589. if file_addr < part_addr or file_addr >= (part_addr + part_size) :
  590. panic('partition %s: file_address 0x%x is not in part' \
  591. %(part['name'], file_addr))
  592. if 'enable_sector' in part.keys() and 'true' == part['enable_sector'] :
  593. part_tbl.parts[idx].offset = int(part_addr / 512)
  594. part_tbl.parts[idx].size = int(part_size / 512)
  595. part_tbl.parts[idx].entry_offs = int(file_addr / 512)
  596. else:
  597. part_tbl.parts[idx].offset = part_addr
  598. part_tbl.parts[idx].size = part_size
  599. part_tbl.parts[idx].entry_offs = file_addr
  600. #print('%d: 0x%x, 0x%x' %(idx, part_tbl.parts[idx].offset, part_tbl.parts[idx].size))
  601. idx = idx + 1
  602. part_tbl.part_cnt = idx
  603. part_tbl.table_crc = c_struct_crc(part_tbl, SIZEOF_PARTITION_TABLE - 4)
  604. """
  605. with open('parttbl.bin', 'wb') as f:
  606. f.write(part_tbl)
  607. """
  608. with open(param_file, 'wb') as f:
  609. f.seek(0, 0)
  610. f.write(part_tbl)
  611. def generate_firmware_version(self, param_file):
  612. global board_name
  613. if 'version_code' not in self.fw_version:
  614. print('\033[1;31;40minfo: no version code\033[0m');
  615. self.fw_version['version_code'] = '0'
  616. if 'version_res' not in self.fw_version:
  617. print('\033[1;31;40minfo: no version res\033[0m');
  618. self.fw_version['version_res'] = '0'
  619. #print(self.fw_version)
  620. fw_ver = FIRMWARE_VERSION()
  621. memset(addressof(fw_ver), 0, SIZEOF_FIRMWARE_VERSION)
  622. fw_ver.magic = FIRMWARE_VERSION_MAGIC
  623. fw_ver.version_code = int(self.fw_version['version_code'], 0)
  624. fw_ver.version_res = int(self.fw_version['version_res'], 0)
  625. version_name = self.fw_version['version_name']
  626. if len(version_name) > len(fw_ver.version_name):
  627. panic('max version_name is t' %(len(fw_ver.version_name)))
  628. memcpy_n(fw_ver.version_name, len(self.fw_version['version_name']), \
  629. self.fw_version['version_name'])
  630. memcpy_n(fw_ver.board_name, len(board_name), board_name)
  631. self.fw_version['board_name'] = board_name
  632. fw_ver.checksum = c_struct_crc(fw_ver, SIZEOF_FIRMWARE_VERSION - 4)
  633. #time.strftime('%y%m%d-%H%M%S',time.localtime(time.time()))
  634. """
  635. with open('fw.bin', 'wb') as f:
  636. f.write(fw_ver)
  637. """
  638. with open(param_file, 'rb+') as f:
  639. f.seek(SIZEOF_PARTITION_TABLE, 0)
  640. f.write(fw_ver)
  641. f.seek(1020, 0)
  642. f.write(b'part')
  643. def generate_maker_ext_config(self, m_ext_cfg_file):
  644. with open(m_ext_cfg_file, 'a') as f:
  645. f.write('\n//nvram partition infor\n')
  646. nvram_partition_find = 0
  647. for part in self.partitions:
  648. if (('nvram_factory' == part['name'])):
  649. f.write('NVRAM_FACTORY_RO=' + str(part['address']) + ',' + str(part['size']) + ';\n')
  650. nvram_partition_find = 1;
  651. if (nvram_partition_find == 0):
  652. f.write('NVRAM_FACTORY_RO=0,0;\n')
  653. nvram_partition_find = 0
  654. for part in self.partitions:
  655. if (('nvram_user' == part['name'])):
  656. f.write('NVRAM_USER_RW=' + str(part['address']) + ',' + str(part['size']) + ';\n')
  657. nvram_partition_find = 1;
  658. if (nvram_partition_find == 0):
  659. f.write('NVRAM_USER_RW=0,0;\n')
  660. nvram_partition_find = 0
  661. for part in self.partitions:
  662. if (('nvram_factory_rw' == part['name'])):
  663. f.write('NVRAM_FACTORY_RW=' + str(part['address']) + ',' + str(part['size']) + ';\n')
  664. nvram_partition_find = 1;
  665. if (nvram_partition_find == 0):
  666. f.write('NVRAM_FACTORY_RW=0,0;\n')
  667. def generate_maker_config(self, mcfg_file):
  668. with open(mcfg_file, 'w') as f:
  669. f.write('SETPATH=\".\\";\n')
  670. f.write('SPI_STG_CAP=' + str(self.disk_size // 0x200) + ';\n')
  671. f.write('BASEFILE=\"afi.bin\";\n')
  672. """
  673. storage_id definition:
  674. - 0: NOR
  675. - 1: EMMC
  676. - 2: NAND
  677. INF_STORAGE_SOLUTION definition:
  678. - 0: NAND
  679. - 1: NOR
  680. - 2: MMC
  681. - 3: NOR + NAND
  682. - 4: NOR + EMMC
  683. """
  684. boot_storage_id = 0
  685. data_storage_id = 0
  686. # check boot storage id
  687. for part in self.partitions:
  688. if (('file_name' in part.keys()) and ('true' == part['enable_dfu']) and ('BOOT' == part['type'])):
  689. boot_storage_id = int(part['storage_id'], 0)
  690. # write normal partition first
  691. for part in self.partitions:
  692. if (('file_name' in part.keys()) and ('true' == part['enable_dfu']) and ('BOOT' != part['type'])):
  693. if (boot_storage_id == int(part['storage_id'], 0)) :
  694. f.write('WFILE=\"' + part['file_name'] + '\",' + part['file_address'])
  695. f.write(';\n')
  696. # nor boot ,can have extern data storage
  697. if (boot_storage_id == 0):
  698. for part in self.partitions:
  699. if (('file_name' in part.keys()) and ('true' == part['enable_dfu']) and ('BOOT' != part['type'])):
  700. if (boot_storage_id != int(part['storage_id'], 0) ) :
  701. f.write('EXTERN_DATA_FILE=\"' + part['file_name'] + '\",' + part['file_address'])
  702. f.write(';\n')
  703. data_storage_id = int(part['storage_id'], 0)
  704. # write boot partition
  705. for part in self.partitions:
  706. if (('file_name' in part.keys()) and ('true' == part['enable_dfu']) and ('BOOT' == part['type'])):
  707. if (boot_storage_id == int(part['storage_id'], 0)):
  708. f.write('WFILE=\"' + part['file_name'] + '\",' + part['file_address'])
  709. f.write(';\n')
  710. # check the current solution such as NOR-only, NAND-only, NOR + NAND
  711. # check the current solution such as NOR-only, EMMC-only NAND-only, NOR + NAND, NOR + EMMC
  712. if (boot_storage_id == 0):
  713. if (data_storage_id == 0):
  714. f.write('INF_TDK_STORAGE_TYPE=1' + ';\n') # NOR-only solution
  715. elif (data_storage_id == 1):
  716. f.write('INF_TDK_STORAGE_TYPE=4' + ';\n') # NOR + EMMC solution
  717. else :
  718. f.write('INF_TDK_STORAGE_TYPE=3' + ';\n') # NOR + NAND solution
  719. f.write('EXTERN_DATA_STG_CAP=0x80000' + ';\n')
  720. elif (boot_storage_id == 1): # EMMC-only solution
  721. f.write('INF_TDK_STORAGE_TYPE=2' + ';\n') # EMMC-only solution
  722. else: # NAND-only solution
  723. f.write('INF_TDK_STORAGE_TYPE=0' + ';\n') # NAND-only solution
  724. global_buffer_size = max(self.disk_size, 0)
  725. if global_buffer_size > PRODUCTION_GLOBAL_BUFFER_DEFAULT_SIZE:
  726. f.write('INF_GLOBAL_BUFFER_SIZE=' + str(global_buffer_size) + ';\n')
  727. # The length of 'VER' field is limited to 32 bytes
  728. if len(self.fw_version['version_name']) > 32:
  729. fw_ver_temp = self.fw_version['version_name'][0:31]
  730. else:
  731. fw_ver_temp = self.fw_version['version_name']
  732. f.write('VER=\"' + fw_ver_temp + '\"' + ';\n');
  733. #add mp card config
  734. if os.path.exists(os.path.join(self.bin_dir, MP_CARD_CFG_NAME)):
  735. f.write('#include \"' + MP_CARD_CFG_NAME + '\"\n')
  736. #add extern data config
  737. if os.path.exists(os.path.join(self.bin_dir, FW_MAKER_EXT_CFG_NAME)):
  738. f.write('#include \"' + FW_MAKER_EXT_CFG_NAME + '\"\n')
  739. def generate_raw_image(self, rawfw_name):
  740. print('FW: Build raw spinor image')
  741. rawfw_file = os.path.join(self.fw_dir, rawfw_name)
  742. if os.path.exists(rawfw_file):
  743. os.remove(rawfw_file)
  744. new_file(rawfw_file, self.disk_size, 0xff)
  745. for part in self.partitions:
  746. if ('file_name' in part.keys()) and ('true' == part['enable_raw']) and (int(part['storage_id'], 0) == 0):
  747. addr = int(part["address"], 16)
  748. srcfile = os.path.join(self.bin_dir, part['file_name'])
  749. dd_file(srcfile, rawfw_file, seek=addr)
  750. if not os.path.exists(rawfw_file):
  751. panic('Failed to generate SPINOR raw image')
  752. def generate_firmware(self, fw_name):
  753. print('FW: Build USB DFU image')
  754. maker_cfgfile = os.path.join(self.bin_dir, 'fw_maker.cfg')
  755. self.generate_maker_config(maker_cfgfile);
  756. maker_ext_cfgfile = os.path.join(self.bin_dir, FW_MAKER_EXT_CFG_NAME)
  757. self.generate_maker_ext_config(maker_ext_cfgfile);
  758. fw_file = os.path.join(self.fw_dir, fw_name);
  759. if (is_windows()):
  760. cmd = [script_path + '/utils/windows/maker.exe', '-c', maker_cfgfile, \
  761. '-o', fw_file, '-mf']
  762. else:
  763. if os.path.exists(fw_file):
  764. os.remove(fw_file)
  765. if ('32bit' == platform.architecture()[0]):
  766. # linux x86
  767. maker_path = script_path + '/utils/linux-x86/maker/PyMaker.pyo'
  768. else:
  769. # linux x86_64
  770. maker_path = script_path + '/utils/linux-x86_64/maker/PyMaker.pyo'
  771. cmd = ['python2', '-O', maker_path, '-c', maker_cfgfile, '-o', fw_file, '--mf', '1']
  772. (outmsg, exit_code) = run_cmd(cmd)
  773. if not os.path.exists(fw_file):
  774. panic('Maker error: %s' %(outmsg))
  775. print_notice('Build successfully!')
  776. if is_msys():
  777. print_notice('Firmware: ' + cygpath(fw_file))
  778. else:
  779. print_notice('Firmware: ' + fw_file)
  780. def build_ota_image(self, ota_fw_name):
  781. ota_fw_name = os.path.join(self.fw_dir, ota_fw_name)
  782. script_ota_path = os.path.join(script_path, 'build_ota_image.py')
  783. cmd = [sys.executable, script_ota_path, '-i', self.bin_dir, '-c', self.fw_xml_file,
  784. '-o', ota_fw_name, '-b', board_name]
  785. (outmsg, exit_code) = run_cmd(cmd)
  786. if exit_code !=0:
  787. print('make ota error')
  788. print(outmsg.decode('utf-8'))
  789. sys.exit(1)
  790. def generate_att_image(self, att_filename, fw_filename):
  791. att_dir = os.path.join(self.fw_dir, 'att')
  792. if not os.path.isdir(att_dir):
  793. return
  794. print('ATT: Build ATT image')
  795. for part in self.partitions:
  796. if ('file_name' in part.keys())and ('true' == part['enable_dfu']):
  797. shutil.copyfile(os.path.join(self.bin_dir, part['file_name']), \
  798. os.path.join(att_dir, part['file_name']))
  799. maker_cfgfile = os.path.join(self.bin_dir, 'fw_maker.cfg')
  800. self.generate_maker_config(maker_cfgfile);
  801. temp_maker_cfgfile = os.path.join(self.bin_dir, 'fw_maker_temp.cfg')
  802. with open(temp_maker_cfgfile, 'wb') as f:
  803. with open(maker_cfgfile, 'rb') as f1:
  804. f1_data = f1.read()
  805. f.write(f1_data)
  806. mp_card_cfgfile = os.path.join(self.bin_dir, 'mp_card.cfg')
  807. with open(mp_card_cfgfile, 'rb') as f2:
  808. f2_data = f2.read()
  809. f.write(f2_data)
  810. maker_ext_cfgfile = os.path.join(self.bin_dir, 'fw_maker_ext.cfg')
  811. with open(maker_ext_cfgfile, 'rb') as f3:
  812. f3_data = f3.read()
  813. f.write(f3_data)
  814. shutil.copyfile(temp_maker_cfgfile, \
  815. os.path.join(att_dir, 'fw_maker.cfg'))
  816. shutil.copyfile(os.path.join(self.fw_dir, fw_filename),
  817. os.path.join(att_dir, 'attdfu.fw'))
  818. print('ATT: Generate ATT image %s' %(os.path.join(self.fw_dir, att_filename)))
  819. self.build_atf_image(os.path.join(self.fw_dir, att_filename), att_dir)
  820. def build_atf_image(self, image_path, atf_file_dir, files = []):
  821. script_atf_path = os.path.join(script_path, 'build_atf_image.py')
  822. cmd = [sys.executable, script_atf_path, '-o', image_path]
  823. for parent, dirnames, filenames in os.walk(atf_file_dir):
  824. for filename in filenames:
  825. files.append(os.path.join(parent, filename))
  826. cmd = cmd + files
  827. (outmsg, exit_code) = run_cmd(cmd)
  828. if exit_code !=0:
  829. print('make att error')
  830. print(outmsg.decode('utf-8'))
  831. sys.exit(1)
  832. def add_crc(self, filename, chunk_size):
  833. with open(filename, 'rb') as f:
  834. filedata = f.read()
  835. length = len(filedata)
  836. i = 0
  837. with open(filename, 'wb') as f:
  838. while (length > 0):
  839. if (length < chunk_size):
  840. chunk = filedata[i : i + length] + bytearray(chunk_size - length)
  841. else:
  842. chunk = filedata[i : i + chunk_size]
  843. crc = crc16(bytearray(chunk), 0xffff)
  844. f.write(chunk + struct.pack('<H',crc))
  845. length -= chunk_size
  846. i += chunk_size
  847. def generate_earphone_config(self, mcfg_file, upg_ini_file):
  848. with open(mcfg_file, 'w') as f, open(upg_ini_file, 'w') as f_u:
  849. fw_ver_str = str(self.fw_version).strip()[1:-1]
  850. f.write('\nFW_VERSION="%s";\n\n' %fw_ver_str.replace("\'", ""))
  851. f.write('\nSETPATH="..\\";\n')
  852. f.write('FIRMWARE_XML="firmware.xml";\n')
  853. f.write('\nSETPATH=".\\";\n')
  854. f.write('SPI_STG_CAP=%d;\n' %(self.disk_size // 0x200))
  855. f.write('BASEFILE="afi.bin";\n')
  856. f.write('UPGRADE_BAUDRATE=%d;\n' %self.upgrade_baudrate)
  857. f.write('PRODUCT_CONFIG="%s";\n' %os.path.basename(upg_ini_file))
  858. f.write('SYS_SDFS="ksdfs.bin";\n')
  859. f_u.write("adfu_switch\n")
  860. f_u.write("baudrate = %d\n" %self.upgrade_baudrate)
  861. f_u.write("payload = 32768\n")
  862. # f_u.write("adfu_start\n")
  863. swrite_data_list = []
  864. # write dfu data
  865. for part in self.partitions:
  866. if ('file_name' in part.keys()) and ('true' == part['enable_dfu']):
  867. w_file_name = part['file_name']
  868. storage_id = int(part['storage_id'], 0)
  869. w_file_addr = int(part['file_address'], 0)
  870. if 'BOOT' == part['type']:
  871. info_tuple = (w_file_name, storage_id, w_file_addr, True)
  872. else:
  873. info_tuple = (w_file_name, storage_id, w_file_addr)
  874. swrite_data_list.append(info_tuple)
  875. swrite_data_list.sort(key = lambda x:(x[1], x[2]))
  876. prv_storage_id = -1
  877. b_clear_history_set = 0
  878. for info_tuple in swrite_data_list:
  879. w_file_name = info_tuple[0]
  880. storage_id = info_tuple[1]
  881. w_file_addr = info_tuple[2]
  882. if storage_id != prv_storage_id:
  883. if prv_storage_id >= 0:
  884. f_u.write("verify_fw\n")
  885. if prv_storage_id != -1:
  886. if b_clear_history_set == 0:
  887. f_u.write("clear_history\n")
  888. b_clear_history_set = 1
  889. f.write("\n")
  890. f_u.write("\n")
  891. f_u.write("renew_flash_id %d\n" %storage_id)
  892. f_u.write("sinit %d\n" %storage_id)
  893. prv_storage_id = storage_id
  894. if len(info_tuple) > 3:
  895. f_u.write("serase 0x%x %d 0\n" %(w_file_addr, 0x4000))
  896. else:
  897. f_u.write("swrite 0x%08x 0 %s\n" %(w_file_addr, w_file_name))
  898. file_path = os.path.join(self.orig_bin_dir, w_file_name)
  899. if os.path.getsize(file_path) > 0x400000:
  900. self.atf_file_list.append(file_path)
  901. else:
  902. f.write('WFILE="%s",0x%x;\n' %(w_file_name, w_file_addr))
  903. if prv_storage_id >= 0:
  904. f_u.write("verify_fw\n")
  905. if b_clear_history_set == 0:
  906. f_u.write("clear_history\n")
  907. for info_tuple in swrite_data_list:
  908. if len(info_tuple) <= 3:
  909. continue
  910. w_file_name = info_tuple[0]
  911. storage_id = info_tuple[1]
  912. w_file_addr = info_tuple[2]
  913. if storage_id != prv_storage_id:
  914. f_u.write("\n")
  915. f_u.write("renew_flash_id %d\n" %storage_id)
  916. f_u.write("sinit %d\n" %storage_id)
  917. prv_storage_id = storage_id
  918. f_u.write("swrite 0x%08x 0 %s\n" %(w_file_addr, w_file_name))
  919. f_u.write("\ndisconnect reboot\n")
  920. #add extern data config
  921. f.write('\n#include "fw_product.cfg"\n')
  922. if os.path.isfile(os.path.join(self.orig_bin_dir, "fwimage.cfg")):
  923. f.write('#include "fwimage.cfg"\n')
  924. f.write('\nSETPATH=".\\config";\n')
  925. f.write('#include "fw_configuration.cfg"\n')
  926. def generate_earphone_firmware(self, fw_name):
  927. print('FW: Build earphone firmware image')
  928. maker_cfgfile = os.path.join(self.orig_bin_dir, 'fw_maker.cfg')
  929. upg_cfgfile = os.path.join(self.orig_bin_dir, 'product.ini')
  930. self.generate_earphone_config(maker_cfgfile, upg_cfgfile);
  931. att_dir = os.path.join(self.orig_bin_dir, 'ATT')
  932. upg_file = os.path.join(att_dir, 'upgrade.fw')
  933. fw_file = os.path.join(self.fw_dir, fw_name)
  934. if (is_windows()):
  935. cmd = [script_path + '/utils/windows/maker.exe', '-c', maker_cfgfile, \
  936. '-o', upg_file, '-mf']
  937. else:
  938. if ('32bit' == platform.architecture()[0]):
  939. # linux x86
  940. maker_path = script_path + '/utils/linux-x86/maker/PyMaker.pyo'
  941. else:
  942. # linux x86_64
  943. maker_path = script_path + '/utils/linux-x86_64/maker/PyMaker.pyo'
  944. cmd = ['python2', '-O', maker_path, '-c', maker_cfgfile, '-o', upg_file, '--mf', '1']
  945. (outmsg, exit_code) = run_cmd(cmd)
  946. if not os.path.exists(upg_file):
  947. panic('Maker error: %s' %(outmsg))
  948. self.build_atf_image(fw_file, att_dir, self.atf_file_list)
  949. print_notice('Build successfully!')
  950. def main(argv):
  951. global ext_name, soc_name, board_name, encrypt_fw, efuse_bin
  952. parser = argparse.ArgumentParser(
  953. description='Build firmware',
  954. )
  955. parser.add_argument('-c', dest = 'fw_cfgfile')
  956. parser.add_argument('-e', dest = 'encrypt_fw')
  957. parser.add_argument('-ef', dest = 'efuse_bin')
  958. parser.add_argument('-b', dest = 'board_name')
  959. parser.add_argument('-s', dest = 'soc_name')
  960. parser.add_argument('-v', dest = 'fw_ver_file')
  961. parser.add_argument('-x', dest = 'ext_name')
  962. args = parser.parse_args();
  963. fw_cfgfile = args.fw_cfgfile
  964. encrypt_fw = args.encrypt_fw
  965. efuse_bin = args.efuse_bin
  966. board_name = args.board_name
  967. date_stamp = time.strftime('%y%m%d',time.localtime(time.time()))
  968. fw_prefix = board_name + '_' + date_stamp
  969. soc_name = args.soc_name
  970. ext_name = args.ext_name
  971. if (not os.path.isfile(fw_cfgfile)):
  972. print('firmware config file is not exist')
  973. sys.exit(1)
  974. try:
  975. fw = firmware(fw_cfgfile)
  976. fw.crc_chunk_size = 32
  977. fw.parse_config()
  978. if (ext_name == "debug"):
  979. fw.generate_raw_image(fw_prefix + '_raw_debug.bin')
  980. fw.generate_earphone_firmware(fw_prefix + '_' + ext_name + '.fw')
  981. else:
  982. fw.generate_raw_image(fw_prefix + '_raw.bin')
  983. fw.generate_earphone_firmware(fw_prefix + '.fw')
  984. # build ota for firmware
  985. fw.fw_xml_file = os.path.join(fw.fw_dir, 'ota_firmware.xml')
  986. if os.path.exists(fw.fw_xml_file):
  987. fw.build_ota_image('ota_firmware.bin')
  988. # build ota for fonts
  989. fw.fw_xml_file = os.path.join(fw.fw_dir, 'ota_fonts.xml')
  990. if os.path.exists(fw.fw_xml_file):
  991. fw.build_ota_image('ota_fonts.bin')
  992. fw.fw_xml_file = os.path.join(fw.fw_dir, 'ota_full.xml')
  993. if os.path.exists(fw.fw_xml_file):
  994. fw.build_ota_image('ota_full.bin')
  995. # build ota for res
  996. fw.fw_xml_file = os.path.join(fw.fw_dir, 'ota_res.xml')
  997. if os.path.exists(fw.fw_xml_file):
  998. fw.build_ota_image('ota_res.bin')
  999. # build ota for res_b
  1000. fw.fw_xml_file = os.path.join(fw.fw_dir, 'ota_res_b.xml')
  1001. if os.path.exists(fw.fw_xml_file):
  1002. fw.build_ota_image('ota_res_b.bin')
  1003. except Exception as e:
  1004. print('unknown exception, %s' %(str(e)))
  1005. traceback.print_exc()
  1006. sys.exit(2)
  1007. if __name__ == '__main__':
  1008. main(sys.argv[1:])