efuse_bingen_v2.py 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. import binascii
  2. import os.path
  3. import sys
  4. from xml.dom import minidom
  5. import argparse
  6. import re
  7. import base64
  8. import subprocess
  9. import os
  10. import hashlib
  11. import logging
  12. log_file_path = ""
  13. def convert_to_int_value(val, tag_name, attr_name=None) :
  14. if (val == "") or (val == 0) or (val == "0") :
  15. return 0
  16. if (val == 1) or (val == "1") :
  17. return 1
  18. if isinstance(val, basestring) : #check if "val" is string type (only string has lower() method)
  19. if val.lower() == "true" :
  20. return 1
  21. if val.lower() == "false" :
  22. return 0
  23. if attr_name : #has Atribute
  24. PrintError_RaiseException_StopBuild("Attribute Name: " + attr_name + " => I got value: \"" + str(val) + "\". The value should be: \"1\" or \"0\" or \"true\" or \"false\" or empty(=false)")
  25. else :
  26. PrintError_RaiseException_StopBuild("Tag Name: " + tag_name + " => I got value: \"" + str(val) + "\". The value should be: \"1\" or \"0\" or \"true\" or \"false\" or empty(=false)")
  27. def isReverseEndianEnabled(val) :
  28. if isinstance(val, basestring) : #check if "val" is string type (only string has lower() method)
  29. if val.lower() == "true" :
  30. return True
  31. if val.lower() == "false" :
  32. return False
  33. PrintError_RaiseException_StopBuild("[definition] \"reverse_endian\" should be in value \"true\" or \"false\".")
  34. else :
  35. PrintError_RaiseException_StopBuild("[definition] \"reverse_endian\" should be in String(\"true\" or \"false\") format.")
  36. def reverseEndian(val, enableReverse=False) :
  37. if enableReverse :
  38. if not isinstance(val, basestring) :
  39. PrintError_RaiseException_StopBuild("The type of input value of \"reverseEndian\" should be String")
  40. if (len(val) == 4) :
  41. return val[2:4] + val[0:2]
  42. elif (len(val) == 8) :
  43. return val[6:8] + val[4:6] + val[2:4] + val[0:2]
  44. else :
  45. return val
  46. PrintError_RaiseException_StopBuild("The input value of \"reverseEndian\" should be the multiply of 4")
  47. def writeBitValueAndOneHexStringToFile(fstream, lstBitValue, hexString) :
  48. """
  49. Notice: The priority of bit input(lstBitValue) is higher than hex input(hexString) if hexString overlaps lstBitValue
  50. """
  51. result = 0;
  52. priority_mask = 0xFFFFFFFF
  53. for bit_number, value in lstBitValue :
  54. if value == 1 :
  55. result = result + (2 ** bit_number) #transform bit to decimal
  56. priority_mask = priority_mask & ~(2 ** bit_number)
  57. hexString2Decimal = int(hexString, 16) #transform hex to decimal
  58. result = (hexString2Decimal & priority_mask) | result #merge
  59. plain_hex_string = str(hex(result))[2:] #result is decimal, transform to hex
  60. plain_hex_string = plain_hex_string.zfill(8) #padding 0 at right to 8 digits
  61. lstHexArr = re.findall('..', plain_hex_string)
  62. fstream.write(chr(int(lstHexArr[3], 16)))
  63. fstream.write(chr(int(lstHexArr[2], 16)))
  64. fstream.write(chr(int(lstHexArr[1], 16)))
  65. fstream.write(chr(int(lstHexArr[0], 16)))
  66. def getBitValueAndOneHexString(lstBitValue, hexString) :
  67. """
  68. Notice: The priority of bit input(lstBitValue) is higher than hex input(hexString) if hexString overlaps lstBitValue
  69. This function is the same as function "writeBitValueAndOneHexStringToFile" except it return the merged value rather than writing to file
  70. """
  71. result = 0;
  72. priority_mask = 0xFFFFFFFF
  73. for bit_number, value in lstBitValue :
  74. if value == 1 :
  75. result = result + (2 ** bit_number) #transform bit to decimal
  76. priority_mask = priority_mask & ~(2 ** bit_number)
  77. hexString2Decimal = int(hexString, 16) #transform hex to decimal
  78. result = (hexString2Decimal & priority_mask) | result #merge
  79. plain_hex_string = str(hex(result))[2:] #result is decimal, transform to hex
  80. plain_hex_string = plain_hex_string.zfill(len(hexString)) #padding 0 at right to 8 digits
  81. return plain_hex_string.upper()
  82. def writeBitValueToFile(fstream, lstBitValue) :
  83. result = 0;
  84. for bit_number, value in lstBitValue :
  85. if value == 1 :
  86. result = result + (2 ** bit_number)
  87. plain_hex_string = str(hex(result))[2:] #result is decimal
  88. plain_hex_string = plain_hex_string.zfill(8)
  89. lstHexArr = re.findall('..', plain_hex_string)
  90. fstream.write(chr(int(lstHexArr[3], 16)))
  91. fstream.write(chr(int(lstHexArr[2], 16)))
  92. fstream.write(chr(int(lstHexArr[1], 16)))
  93. fstream.write(chr(int(lstHexArr[0], 16)))
  94. def get_file_sha256hexdigest(file_name):
  95. hash_result = ""
  96. with open(file_name) as f:
  97. m = hashlib.sha256()
  98. m.update(f.read())
  99. hash_result = m.hexdigest()
  100. return hash_result.upper()
  101. def writeHexStringToFile(fstream, hexString) :
  102. plain_hex_string = hexString.ljust(8, '0') #padding 0 at right to 8 digits
  103. lstHexArr = re.findall('..', plain_hex_string)
  104. fstream.write(chr(int(lstHexArr[0], 16)))
  105. fstream.write(chr(int(lstHexArr[1], 16)))
  106. fstream.write(chr(int(lstHexArr[2], 16)))
  107. fstream.write(chr(int(lstHexArr[3], 16)))
  108. def checkLessThan32BitsHexStringLength(tag_name, hexString, min_index, max_index, attribute_name="") :
  109. if (max_index <= min_index) :
  110. PrintError_RaiseException_StopBuild("[Coding Error] Maximum index should be bigger than minimum index!")
  111. plain_hex_string = hexString.ljust(8, '0') #padding 0 at right to 8 digits
  112. lstHexArr = re.findall('..', plain_hex_string)
  113. result = 0;
  114. mask = 0xFFFFFFFF
  115. for bit_number in range(0, 32) :
  116. if (min_index <= bit_number <= max_index) :
  117. mask = mask & ~(2 ** bit_number)
  118. input_length_mask = int(lstHexArr[3] + lstHexArr[2] + lstHexArr[1] + lstHexArr[0], 16)
  119. forbidden_field_mask = mask
  120. # print(hex(input_length_mask))
  121. # print(hex(forbidden_field_mask))
  122. if (input_length_mask & forbidden_field_mask) != 0 :
  123. if attribute_name == "" :
  124. PrintError_RaiseException_StopBuild("Tag Name: " + tag_name + " (Wrong value length. The length of value should be \"" + tag_name + "[" + str(max_index) + ":" + str(min_index) + "]\")")
  125. else :
  126. PrintError_RaiseException_StopBuild("Tag Name: " + tag_name + " (Wrong value length. The length of value should be \"" + attribute_name + "[" + str(max_index) + ":" + str(min_index) + "]\")")
  127. def parseXmlTagAndAttribute(xml_file, tag_name, attr_name, inputValueLengthLimit=1, inputIsStringType=False) :
  128. if inputIsStringType :
  129. retVal = '0' * inputValueLengthLimit
  130. else :
  131. retVal = 0
  132. try:
  133. if not xml_file.getElementsByTagName(tag_name) :
  134. raise KeyError
  135. tag_number = len(xml_file.getElementsByTagName(tag_name))
  136. if tag_number > 1 :
  137. raise ValueError("Duplicated tag name. It appears " + str(tag_number) + " times!!")
  138. tmp_parse_value = xml_file.getElementsByTagName(tag_name)[0].attributes[attr_name].value
  139. if inputIsStringType :
  140. if (tmp_parse_value == "") :
  141. return retVal
  142. if (inputValueLengthLimit <> len(tmp_parse_value)) :
  143. raise ValueError("Wrong value length. The length of value should be: " + str(inputValueLengthLimit))
  144. if isinstance(tmp_parse_value, basestring) : #check if "tmp_parse_value" is string type (only string has upper() method)
  145. if not isValidHexString(tmp_parse_value) : #only string can be processed by regex
  146. raise ValueError("Wrong hex value type! The value should be within [0-9|A-F]")
  147. return tmp_parse_value.upper()
  148. return tmp_parse_value
  149. else : #not string
  150. return convert_to_int_value(tmp_parse_value, tag_name, attr_name)
  151. except IndexError:
  152. #Tag or Attribute not exist
  153. #printAndLog("[Warning][Not Exist] Tag Name: " + tag_name + ", Attribute Name: " + attr_name + " => Set to default value: " + str(retVal))
  154. return retVal
  155. except KeyError:
  156. #Tag or Attribute not exist
  157. #printAndLog("[Warning][Not Exist] Tag Name: " + tag_name + ", Attribute Name: " + attr_name + " => Set to default value: " + str(retVal))
  158. return retVal
  159. except ValueError as err:
  160. PrintError_RaiseException_StopBuild("Tag Name: " + tag_name + ", Attribute Name: " + attr_name + " (" + str(err) + ")")
  161. def parseXmlTagInnerValue(xml_file, tag_name, inputValueLengthLimit=1, inputIsStringType=False) :
  162. if inputIsStringType :
  163. retVal = '0' * inputValueLengthLimit
  164. else :
  165. retVal = 0
  166. try:
  167. if not xml_file.getElementsByTagName(tag_name) :
  168. raise KeyError
  169. tag_number = len(xml_file.getElementsByTagName(tag_name))
  170. if tag_number > 1 :
  171. raise ValueError("Duplicated tag name. It appears " + str(tag_number) + " times!!")
  172. tmp_parse_value = xml_file.getElementsByTagName(tag_name)[0].childNodes[0].data
  173. if inputIsStringType :
  174. if (tmp_parse_value == "") :
  175. return retVal
  176. if (inputValueLengthLimit <> len(tmp_parse_value)) :
  177. raise ValueError("Wrong value length. The length of value should be: " + str(inputValueLengthLimit))
  178. if isinstance(tmp_parse_value, basestring) : #check if "tmp_parse_value" is string type (only string has upper() method)
  179. if not isValidHexString(tmp_parse_value) : #only string can be processed by regex
  180. raise ValueError("Wrong hex value type! The value should be within [0-9|A-F]")
  181. return tmp_parse_value.upper()
  182. return tmp_parse_value
  183. else : #not string
  184. return convert_to_int_value(tmp_parse_value, tag_name)
  185. except IndexError:
  186. #Tag or Attribute not exist
  187. #printAndLog("[Warning][Not Exist] Tag Name: " + tag_name + " => Set to default value: " + str(retVal))
  188. return retVal
  189. except KeyError:
  190. #Tag or Attribute not exist
  191. #printAndLog("[Warning][Not Exist] Tag Name: " + tag_name + " => Set to default value: " + str(retVal))
  192. return retVal
  193. except ValueError as err:
  194. PrintError_RaiseException_StopBuild("Tag Name: " + tag_name + " (" + str(err) + ")")
  195. def isValidHexString(hex_input) :
  196. if re.match(r"^[0-9A-F]*$", hex_input, re.IGNORECASE) :
  197. return True
  198. return False
  199. def isValidNumberString(number_input) :
  200. if re.match(r"^[0-9]*$", number_input, re.IGNORECASE) :
  201. return True
  202. return False
  203. def isValidRegisterLengthString(number_input) :
  204. if re.match(r"^[0-9]*$", number_input, re.IGNORECASE) :
  205. if 1 <= int(number_input) <= 32 :
  206. return True
  207. return False
  208. def isValidRegisterIndexString(index_input) :
  209. if re.match(r"^[0-9]*$", index_input, re.IGNORECASE) :
  210. if 0 <= int(index_input) <= 31 :
  211. return True
  212. return False
  213. def printAndLog(msg, criticalLevel=False):
  214. print(msg)
  215. global log_file_path
  216. if (log_file_path) :
  217. logging.basicConfig(format='[%(asctime)s] %(message)s', filename=log_file_path, level=logging.DEBUG)
  218. if criticalLevel :
  219. logging.critical(msg)
  220. else :
  221. logging.info(msg)
  222. def PrintError_RaiseException_StopBuild(err) :
  223. printAndLog("[Error] " + err, criticalLevel=True)
  224. raise Exception("[Error] " + err)
  225. def main():
  226. WRITE_TYPE_BIT = 1
  227. WRITE_TYPE_STRING = 2
  228. WRITE_TYPE_BIT_AND_STRING = 3
  229. parser = argparse.ArgumentParser(description='MediaTek EFUSE XML Parser')
  230. parser.add_argument('--file', '-f',
  231. required=True,
  232. help='Provide the EFUSE blowing xml file')
  233. parser.add_argument('--definition_file', '-d',
  234. required=True,
  235. help='Provide the EFUSE definition file')
  236. parser.add_argument('--output_bin_name', '-o',
  237. required=False,
  238. default='xml_output.bin',
  239. help='Provide output file name')
  240. parser.add_argument('--key_hash', '-k',
  241. required=False,
  242. help='Provide the file name path of key hash')
  243. parser.add_argument('--log_output_file', '-l',
  244. required=False,
  245. help='Provide the log output file name')
  246. args = parser.parse_args()
  247. if (args.log_output_file) :
  248. if os.path.isfile(args.log_output_file) :
  249. try :
  250. os.remove(args.log_output_file)
  251. except :
  252. pass
  253. global log_file_path
  254. log_file_path = args.log_output_file
  255. printAndLog("***************************************************************************")
  256. printAndLog("**************** MediaTek EFUSE XML Parser ([MTK_XML2BIN]) ****************")
  257. printAndLog("****************************** version 2.0.2 ******************************")
  258. printAndLog("***************************************************************************")
  259. printAndLog("Loading XML file: " + os.path.abspath(args.file))
  260. if os.path.isfile(args.output_bin_name) :
  261. os.remove(args.output_bin_name)
  262. printAndLog("Remove old image file: " + os.path.abspath(args.output_bin_name))
  263. printAndLog("-----------------------------------------------")
  264. if not os.path.isfile(args.file) :
  265. PrintError_RaiseException_StopBuild("XML file not exist!!")
  266. if not os.path.isfile(args.definition_file) :
  267. PrintError_RaiseException_StopBuild("EFUSE definition file not exist!!")
  268. try :
  269. xml_file = minidom.parse(args.file)
  270. except Exception:
  271. printAndLog("[Error] ***** XML format is NOT CORRECT. Please check your XML input file. *****")
  272. printAndLog("[Error] ***** XML format is NOT CORRECT. Please check your XML input file. *****")
  273. PrintError_RaiseException_StopBuild("***** XML format is NOT CORRECT. Please check your XML input file. *****")
  274. try :
  275. definition_file = minidom.parse(args.definition_file)
  276. except Exception:
  277. printAndLog("[Error] ***** EFUSE Definition XML format is NOT CORRECT. Please check your XML input file. *****")
  278. printAndLog("[Error] ***** EFUSE Definition XML format is NOT CORRECT. Please check your XML input file. *****")
  279. PrintError_RaiseException_StopBuild("***** EFUSE Definition XML format is NOT CORRECT. Please check your XML input file. *****")
  280. efuse_writer_tag = definition_file.getElementsByTagName("efuse_writer")[0]
  281. if len(definition_file.getElementsByTagName("efuse_writer")) > 1 :
  282. PrintError_RaiseException_StopBuild("[definitions] Should only have one \"efuse_writer\" tag.")
  283. efuse_writer_chip = efuse_writer_tag.getAttribute("chip").strip()
  284. if (efuse_writer_chip == "") :
  285. PrintError_RaiseException_StopBuild("[definitions] chip name should not be empty in definition file.")
  286. printAndLog("Definition Target Platform: " + efuse_writer_chip)
  287. efuse_writer_output_binary_size = efuse_writer_tag.getAttribute("output_bin_size").strip()
  288. if (efuse_writer_output_binary_size == "") :
  289. PrintError_RaiseException_StopBuild("[definitions] output_bin_size should not be empty in definition file.")
  290. if not isValidNumberString(efuse_writer_output_binary_size) :
  291. PrintError_RaiseException_StopBuild("[definitions] output_bin_size is not a valid number.")
  292. try :
  293. MAX_OUTPUT_OFFSET_DECIMAL = int(efuse_writer_output_binary_size) - 32
  294. except ValueError :
  295. PrintError_RaiseException_StopBuild("[definitions] " + efuse_writer_output_binary_size + " is not a valid type of number.")
  296. printAndLog("Definition Expected Output Binary Size: " + efuse_writer_output_binary_size + " bytes")
  297. #Parsing XML to variable
  298. printAndLog("Parsing XML file ...")
  299. dict_definition_inner_value = {}
  300. dict_definition_inner_text = {}
  301. dict_definition_boolean = {}
  302. dict_definition_external = {}
  303. printAndLog("-----------------------------------------------")
  304. if not definition_file.getElementsByTagName("definitions") :
  305. PrintError_RaiseException_StopBuild("[definitions] No \"definitions\" tag found in EFUSE definition file.")
  306. if len(definition_file.getElementsByTagName("definitions")) > 1 :
  307. PrintError_RaiseException_StopBuild("[definitions] Should only have one \"definitions\" tag.")
  308. definition_alllist = definition_file.getElementsByTagName("definitions")[0]
  309. definition_inner_value_list = definition_alllist.getElementsByTagName("inner_value")
  310. definition_inner_text_list = definition_alllist.getElementsByTagName("inner_text")
  311. definition_boolean_list = definition_alllist.getElementsByTagName("boolean")
  312. definition_merge_inner_text_and_value_list = definition_inner_value_list + definition_inner_text_list
  313. for tag in definition_merge_inner_text_and_value_list :
  314. tag_type = tag.tagName
  315. tag_name = tag.getAttribute("tag").strip()
  316. tag_attribute = ""
  317. if tag_name == "" :
  318. PrintError_RaiseException_StopBuild("[definitions] Type: " + tag_type + ", \"tag\" value should not be null.")
  319. if tag_type == "inner_value" :
  320. tag_attribute = tag.getAttribute("attribute").strip()
  321. if tag_attribute == "" :
  322. PrintError_RaiseException_StopBuild("[definitions] Type: " + tag_type + ", \"attribute\" value should not be null.")
  323. suppress_log = tag.getElementsByTagName("suppress_log")
  324. log_display = True
  325. if suppress_log :
  326. log_display = False
  327. if tag_type == "inner_value" :
  328. prepared_error_msg = "Type: " + tag_type + " => tag: " + tag_name + ", attribute: " + tag_attribute
  329. if tag_name not in dict_definition_inner_value :
  330. dict_definition_inner_value[tag_name] = {}
  331. if tag_attribute in dict_definition_inner_value[tag_name] :
  332. PrintError_RaiseException_StopBuild("[definitions] Duplicated attribute name for the same tag name. (" + prepared_error_msg + ")")
  333. else : # tag_type == "inner_text"
  334. prepared_error_msg = "Type: " + tag_type + " => tag: " + tag_name
  335. if tag_name in dict_definition_inner_text :
  336. PrintError_RaiseException_StopBuild("[definitions] Duplicated tag name. (" + prepared_error_msg + ")")
  337. require_conditions = tag.getElementsByTagName("require")
  338. dict_tmp_require_conditions = {"length": None,
  339. "valid_start_bit": None,
  340. "valid_end_bit": None}
  341. for condition in require_conditions :
  342. for condition_name in dict_tmp_require_conditions :
  343. tmp_condition_value = condition.getAttribute(condition_name).strip()
  344. if (tmp_condition_value != "") :
  345. if (dict_tmp_require_conditions[condition_name] is not None) :
  346. PrintError_RaiseException_StopBuild("[definitions] Duplicated \"" + condition_name + "\" declaration. (" + prepared_error_msg + ")")
  347. dict_tmp_require_conditions[condition_name] = tmp_condition_value
  348. if dict_tmp_require_conditions["length"] == None :
  349. PrintError_RaiseException_StopBuild("[definitions] Length is required. (" + prepared_error_msg + ")")
  350. #value check and transform string to integer
  351. if not isValidRegisterLengthString(dict_tmp_require_conditions["length"]) :
  352. PrintError_RaiseException_StopBuild("[definitions] Length is not a valid number(should be 1-32). (" + prepared_error_msg + ")")
  353. dict_tmp_require_conditions["length"] = int(dict_tmp_require_conditions["length"])
  354. if tag_type == "inner_value" :
  355. tag_value = parseXmlTagAndAttribute(xml_file, tag_name, tag_attribute, dict_tmp_require_conditions["length"], True)
  356. else : # tag_type == "inner_text"
  357. tag_value = parseXmlTagInnerValue(xml_file, tag_name, dict_tmp_require_conditions["length"], True)
  358. if (dict_tmp_require_conditions["valid_start_bit"] != None) or (dict_tmp_require_conditions["valid_end_bit"] != None) :
  359. if (dict_tmp_require_conditions["valid_start_bit"] == None) or (dict_tmp_require_conditions["valid_end_bit"] == None) :
  360. PrintError_RaiseException_StopBuild("[definitions] valid_start_bit and valid_end_bit should appear at the same time or not. (" + prepared_error_msg + ")")
  361. #value check and transform string to integer
  362. if (not isValidRegisterIndexString(dict_tmp_require_conditions["valid_start_bit"])) :
  363. PrintError_RaiseException_StopBuild("[definitions] valid_start_bit is not a valid index(should be 0-31). (" + prepared_error_msg + ")")
  364. if (not isValidRegisterIndexString(dict_tmp_require_conditions["valid_end_bit"])) :
  365. PrintError_RaiseException_StopBuild("[definitions] valid_end_bit is not a valid index(should be 0-31). (" + prepared_error_msg + ")")
  366. dict_tmp_require_conditions["valid_start_bit"] = int(dict_tmp_require_conditions["valid_start_bit"])
  367. dict_tmp_require_conditions["valid_end_bit"] = int(dict_tmp_require_conditions["valid_end_bit"])
  368. checkLessThan32BitsHexStringLength(tag_name, tag_value, dict_tmp_require_conditions["valid_start_bit"], dict_tmp_require_conditions["valid_end_bit"], tag_attribute);
  369. if tag_type == "inner_value" :
  370. dict_definition_inner_value[tag_name][tag_attribute] = tag_value
  371. else : # tag_type == "inner_text"
  372. dict_definition_inner_text[tag_name] = tag_value
  373. if log_display :
  374. printAndLog("EFUSE_" + tag_name + " = " + tag_value)
  375. #print(dict_definition_inner_text)
  376. #print(dict_definition_inner_value)
  377. for tag in definition_boolean_list :
  378. tag_name = tag.getAttribute("tag").strip()
  379. tag_attribute = tag.getAttribute("attribute").strip()
  380. if (tag_name == "") or (tag_attribute == "") :
  381. PrintError_RaiseException_StopBuild("[definitions] boolean type, tag or attribute value should not be null.")
  382. suppress_log = tag.getElementsByTagName("suppress_log")
  383. log_display = True
  384. if suppress_log :
  385. log_display = False
  386. if tag_name not in dict_definition_boolean :
  387. dict_definition_boolean[tag_name] = {}
  388. if tag_attribute in dict_definition_boolean[tag_name] :
  389. PrintError_RaiseException_StopBuild("[definitions] Duplicated attribute name. (boolean type, tag: " + tag_name + ", attribute: " + tag_attribute + ")")
  390. tag_value = parseXmlTagAndAttribute(xml_file, tag_name, tag_attribute)
  391. dict_definition_boolean[tag_name][tag_attribute] = tag_value
  392. if log_display :
  393. printAndLog("EFUSE_" + tag_attribute + " = " + str(tag_value))
  394. #print(dict_definition_boolean)
  395. printAndLog("-----------------------------------------------")
  396. EFUSE_SBC_PUBK_HASH = '0' * 64
  397. if args.key_hash :
  398. printAndLog("[Info] Loading SBC_PUBK_HASH from key hash file: " + os.path.abspath(args.key_hash))
  399. if os.path.isfile(args.key_hash) :
  400. try:
  401. with open(args.key_hash, 'r') as f:
  402. EFUSE_SBC_PUBK_HASH = f.read()
  403. except Exception:
  404. PrintError_RaiseException_StopBuild("***** Error while reading key hash file *****")
  405. EFUSE_SBC_PUBK_HASH = EFUSE_SBC_PUBK_HASH.strip()
  406. if EFUSE_SBC_PUBK_HASH == "" :
  407. PrintError_RaiseException_StopBuild("SBC_PUBK_HASH is empty and not generated")
  408. if len(EFUSE_SBC_PUBK_HASH) <> 64 :
  409. PrintError_RaiseException_StopBuild("SBC_PUBK_HASH is not in length 64. Current length of SBC_PUBK_HASH is: " + str(len(EFUSE_SBC_PUBK_HASH)))
  410. EFUSE_SBC_PUBK_HASH = EFUSE_SBC_PUBK_HASH.upper()
  411. if not isValidHexString(EFUSE_SBC_PUBK_HASH) :
  412. PrintError_RaiseException_StopBuild("SBC_PUBK_HASH contains invalid hex string(s)! The value should be within [0-9|A-F]")
  413. else :
  414. PrintError_RaiseException_StopBuild(args.key_hash + " is not generated from getKeyHash.sh for SBC_Key_Hash!!")
  415. else :
  416. printAndLog("[Info] SBC_PUBK_HASH is not loaded from key hash file.")
  417. EFUSE_SBC_PUBK_HASH = '0' * 64
  418. dict_definition_external["SBC_PUBK_HASH"] = EFUSE_SBC_PUBK_HASH
  419. printAndLog("EFUSE_SBC_PUBK_HASH = " + EFUSE_SBC_PUBK_HASH)
  420. printAndLog("-----------------------------------------------")
  421. dict_definition_output = {}
  422. lst_supported_output_type = ["inner_value", "inner_text", "external", "boolean", "mix_type"]
  423. lst_supported_output_mix_type = ["inner_value", "inner_text", "external", "boolean"]
  424. if not definition_file.getElementsByTagName("blow_list") :
  425. PrintError_RaiseException_StopBuild("[definitions] No \"blow_list\" tag found in EFUSE definition file.")
  426. if len(definition_file.getElementsByTagName("blow_list")) > 1 :
  427. PrintError_RaiseException_StopBuild("[definitions] Should only have one \"blow_list\" tag.")
  428. definition_blow_list = definition_file.getElementsByTagName("blow_list")[0]
  429. definition_blow_efuse_items = definition_blow_list.getElementsByTagName("efuse")
  430. for tag in definition_blow_efuse_items :
  431. tag_type = tag.getAttribute("type").strip()
  432. tag_offset = tag.getAttribute("offset").strip()
  433. offset_int_decimal = 0
  434. if (tag_offset == "") :
  435. PrintError_RaiseException_StopBuild("[definitions] \"efuse\" tag => \"tag_offset\" should not be null.")
  436. if (tag_type == "") :
  437. PrintError_RaiseException_StopBuild("[definitions] \"efuse\" tag => \"tag_type\" should not be null.")
  438. if tag_type not in lst_supported_output_type :
  439. PrintError_RaiseException_StopBuild("[definitions] Output type \"" + tag_type + "\" is not supported.")
  440. try :
  441. offset_int_decimal = int(tag_offset, 16)
  442. if (offset_int_decimal % 4) != 0 :
  443. PrintError_RaiseException_StopBuild("[definitions] offset \"" + tag_offset + "\" should be 4bytes align.")
  444. except ValueError :
  445. PrintError_RaiseException_StopBuild("[definitions] offset \"" + tag_offset + "\" is not a valid hex.")
  446. if offset_int_decimal in dict_definition_output :
  447. PrintError_RaiseException_StopBuild("[definitions] offset \"" + tag_offset + "\" is duplicated.")
  448. if (offset_int_decimal >= MAX_OUTPUT_OFFSET_DECIMAL) :
  449. PrintError_RaiseException_StopBuild("[definitions] Since the biggest size of output binary file is 512 bytes, the offset \"" + str(offset_int_decimal) + "\" in decimal should not exceeds " + str(MAX_OUTPUT_OFFSET_DECIMAL) + ".")
  450. dict_definition_output[offset_int_decimal] = {}
  451. input_data_items = tag.getElementsByTagName("input")
  452. #value checking
  453. if input_data_items.length == 0 :
  454. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => No input declaration")
  455. if (tag_type not in ["mix_type", "boolean"]) :
  456. if input_data_items.length > 1 :
  457. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => This type only allows one declaration")
  458. if (tag_type == "mix_type") :
  459. dict_definition_output[offset_int_decimal]["write_data"] = "" #set the default empty string value because it will append the string for this kind of type
  460. tmp_dict_input_bit_duplicated_counter = {}
  461. for input_field in input_data_items :
  462. dict_tmp_input_fields = {"key": None,
  463. "tag": None,
  464. "attribute": None,
  465. "bit": None,
  466. "start_index": None,
  467. "end_index": None,
  468. "reverse_endian": None,
  469. "type": None}
  470. for attribute_name_in_input_tag in input_field.attributes.keys() : #loop attribute and attribute value
  471. if (attribute_name_in_input_tag != "") :
  472. attribute_value_in_input_tag = input_field.getAttribute(attribute_name_in_input_tag).strip()
  473. if attribute_name_in_input_tag not in dict_tmp_input_fields :
  474. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => The input attribute \"" + attribute_name_in_input_tag + "\" is not supported.")
  475. if (dict_tmp_input_fields[attribute_name_in_input_tag] is not None) :
  476. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => Duplicated attribute: \"" + attribute_name_in_input_tag + "\".")
  477. if attribute_value_in_input_tag == "" :
  478. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => Attribute: \"" + attribute_name_in_input_tag + "\" value cannot be null.")
  479. if attribute_name_in_input_tag == "key" :
  480. if attribute_value_in_input_tag not in dict_definition_external :
  481. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => Key: \"" + attribute_value_in_input_tag + "\" cannot be found in external storage (current external storage: " + str(dict_definition_external) + ").")
  482. dict_tmp_input_fields[attribute_name_in_input_tag] = attribute_value_in_input_tag
  483. elif attribute_name_in_input_tag == "type" :
  484. if tag_type != "mix_type" :
  485. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => You must set the overall \"type\" to \"mix_type\" first if you want to specify the \"type\" attribute in each input field.")
  486. if attribute_value_in_input_tag not in lst_supported_output_mix_type :
  487. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => input type: \"" + attribute_value_in_input_tag + "\" is not supported.")
  488. dict_tmp_input_fields[attribute_name_in_input_tag] = attribute_value_in_input_tag
  489. elif attribute_name_in_input_tag == "bit" :
  490. if not isValidRegisterIndexString(attribute_value_in_input_tag) :
  491. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => Attribute: \"" + attribute_name_in_input_tag + "\" should be in valid index range(0-31).")
  492. dict_tmp_input_fields["bit"] = int(attribute_value_in_input_tag)
  493. elif attribute_name_in_input_tag == "reverse_endian" :
  494. if (isReverseEndianEnabled(attribute_value_in_input_tag)) :
  495. dict_tmp_input_fields["reverse_endian"] = reverseEndian(attribute_value_in_input_tag)
  496. elif (attribute_name_in_input_tag == "start_index") or (attribute_name_in_input_tag == "end_index") :
  497. if not isValidNumberString(attribute_value_in_input_tag) :
  498. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => Attribute: \"" + attribute_name_in_input_tag + "\" should be a valid number.")
  499. if (attribute_name_in_input_tag == "start_index") :
  500. dict_tmp_input_fields["start_index"] = int(attribute_value_in_input_tag)
  501. elif (attribute_name_in_input_tag == "end_index") :
  502. dict_tmp_input_fields["end_index"] = int(attribute_value_in_input_tag)
  503. else :
  504. dict_tmp_input_fields[attribute_name_in_input_tag] = attribute_value_in_input_tag
  505. #print(dict_tmp_input_fields)
  506. need_slice_string = False
  507. query_tag = dict_tmp_input_fields["tag"]
  508. query_attribute = dict_tmp_input_fields["attribute"]
  509. query_key = dict_tmp_input_fields["key"]
  510. query_start_index = dict_tmp_input_fields["start_index"]
  511. query_end_index = dict_tmp_input_fields["end_index"]
  512. query_reverse_endian = dict_tmp_input_fields["reverse_endian"]
  513. query_tag_type = dict_tmp_input_fields["type"]
  514. if (query_tag_type == None) :
  515. query_tag_type = tag_type
  516. if (query_start_index != None) or (query_end_index != None) :
  517. if (query_start_index is None) or (query_end_index is None) :
  518. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"start_index\" and \"end_index\" should appear at the same time or not.")
  519. if (query_end_index <= query_start_index) :
  520. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"end_index\" should be bigger than \"start_index\".")
  521. if (query_end_index - query_start_index) > 7 :
  522. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"start_index\" or \"end_index\" is not within the correct range.")
  523. need_slice_string = True
  524. #check: (1)start_index and end_index (2)end_index-start_index<=7 (3)xxx_index should be valid
  525. if (query_tag_type == "inner_value") :
  526. if (dict_tmp_input_fields["tag"] is None) or (dict_tmp_input_fields["attribute"] is None) :
  527. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"tag\" and \"attribute\" are necessary for this type.")
  528. if query_tag not in dict_definition_inner_value :
  529. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => You must declare the tag \"" + query_tag + "\" first.")
  530. if query_attribute not in dict_definition_inner_value[query_tag] :
  531. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => You must declare the attribute \"" + query_attribute + "\" in tag \"" + query_tag + "\" first.")
  532. dict_definition_output[offset_int_decimal]["write_type"] = WRITE_TYPE_STRING
  533. if need_slice_string :
  534. tmp_length = len(dict_definition_inner_value[query_tag][query_attribute])
  535. if (tmp_length < (query_end_index + 1)) or (tmp_length < (query_start_index + 1)) :
  536. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"end_index\" exceeds the maximum length \"" + str(tmp_length) + "\" defined in declaration area.")
  537. tmp_write_data = reverseEndian(dict_definition_inner_value[query_tag][query_attribute][query_start_index:query_end_index + 1], query_reverse_endian)
  538. else :
  539. tmp_write_data = reverseEndian(dict_definition_inner_value[query_tag][query_attribute], query_reverse_endian)
  540. if (tag_type == "mix_type") :
  541. dict_definition_output[offset_int_decimal]["write_data"] = dict_definition_output[offset_int_decimal]["write_data"] + tmp_write_data
  542. else :
  543. dict_definition_output[offset_int_decimal]["write_data"] = tmp_write_data
  544. # dict_definition_output[offset_int_decimal]["write_data"]
  545. elif (query_tag_type == "inner_text") :
  546. if (dict_tmp_input_fields["tag"] is None) :
  547. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"tag\" is necessary for this type.")
  548. if query_tag not in dict_definition_inner_text :
  549. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => You must declare the tag \"" + query_tag + "\" first.")
  550. dict_definition_output[offset_int_decimal]["write_type"] = WRITE_TYPE_STRING
  551. if need_slice_string :
  552. tmp_length = len(dict_definition_inner_text[query_tag])
  553. if (tmp_length < (query_end_index + 1)) or (tmp_length < (query_start_index + 1)) :
  554. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"end_index\" exceeds the maximum length \"" + str(tmp_length) + "\" defined in declaration area.")
  555. tmp_write_data = reverseEndian(dict_definition_inner_text[query_tag][query_start_index:query_end_index + 1], query_reverse_endian)
  556. else :
  557. tmp_write_data = reverseEndian(dict_definition_inner_text[query_tag], query_reverse_endian)
  558. if (tag_type == "mix_type") :
  559. dict_definition_output[offset_int_decimal]["write_data"] = dict_definition_output[offset_int_decimal]["write_data"] + tmp_write_data
  560. else :
  561. dict_definition_output[offset_int_decimal]["write_data"] = tmp_write_data
  562. elif (query_tag_type == "external") :
  563. if (dict_tmp_input_fields["key"] is None) :
  564. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"key\" is necessary for this type.")
  565. dict_definition_output[offset_int_decimal]["write_type"] = WRITE_TYPE_STRING
  566. if query_key not in dict_definition_external :
  567. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => You must declare the external key \"" + query_key + "\" in Python code first.")
  568. dict_definition_output[offset_int_decimal]["write_type"] = WRITE_TYPE_STRING
  569. if need_slice_string :
  570. tmp_length = len(dict_definition_external[query_key])
  571. if (tmp_length < (query_end_index + 1)) or (tmp_length < (query_start_index + 1)) :
  572. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"end_index\" exceeds the maximum length \"" + str(tmp_length) + "\" defined in declaration area.")
  573. tmp_write_data = reverseEndian(dict_definition_external[query_key][query_start_index:query_end_index + 1], query_reverse_endian)
  574. else :
  575. tmp_write_data = reverseEndian(dict_definition_external[query_key], query_reverse_endian)
  576. if (tag_type == "mix_type") :
  577. dict_definition_output[offset_int_decimal]["write_data"] = dict_definition_output[offset_int_decimal]["write_data"] + tmp_write_data
  578. else :
  579. dict_definition_output[offset_int_decimal]["write_data"] = tmp_write_data
  580. elif (query_tag_type == "boolean") :
  581. if (dict_tmp_input_fields["tag"] is None) or (dict_tmp_input_fields["attribute"] is None) or (dict_tmp_input_fields["bit"] is None) :
  582. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => \"tag\" and \"attribute\" and \"bit\" are necessary for this type.")
  583. tmp_current_bit = dict_tmp_input_fields["bit"]
  584. if tmp_current_bit in tmp_dict_input_bit_duplicated_counter :
  585. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => Duplicated \"bit\" index value \"" + str(tmp_current_bit) + "\" for the same efuse field.")
  586. if query_tag not in dict_definition_boolean :
  587. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => You must declare the tag \"" + query_tag + "\" first.")
  588. if query_attribute not in dict_definition_boolean[query_tag] :
  589. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => You must declare the attribute \"" + query_attribute + "\" in tag \"" + query_tag + "\" first.")
  590. tmp_dict_input_bit_duplicated_counter[tmp_current_bit] = dict_definition_boolean[query_tag][query_attribute]
  591. #later summarize in outer loop
  592. else :
  593. if (tag_type == "mix_type") :
  594. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => The \"type\" of the input field should not be empty if you use mix_type.")
  595. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => This type is not supported.")
  596. if (tag_type == "boolean") :
  597. tmp_lst_all_input_bits_in_this_efuse_field = []
  598. for idx in tmp_dict_input_bit_duplicated_counter :
  599. tmp_lst_all_input_bits_in_this_efuse_field.append( (idx, tmp_dict_input_bit_duplicated_counter[idx]) )
  600. dict_definition_output[offset_int_decimal]["write_data"] = tmp_lst_all_input_bits_in_this_efuse_field
  601. dict_definition_output[offset_int_decimal]["write_type"] = WRITE_TYPE_BIT
  602. elif (tag_type == "mix_type") :
  603. if not tmp_dict_input_bit_duplicated_counter :
  604. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => You should not use \"mix_type\" type because you do not set the type of any input field to \"boolean\".")
  605. tmp_lst_all_input_bits_in_this_efuse_field = []
  606. for idx in tmp_dict_input_bit_duplicated_counter :
  607. tmp_lst_all_input_bits_in_this_efuse_field.append( (idx, tmp_dict_input_bit_duplicated_counter[idx]) )
  608. if (len(dict_definition_output[offset_int_decimal]["write_data"]) > 8) :
  609. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => If you want to use \"mix_type\" type, the total length of \"inner_value\" and \"inner_text\" input type of field should not exceed 8.")
  610. if (len(dict_definition_output[offset_int_decimal]["write_data"]) == 0) :
  611. PrintError_RaiseException_StopBuild("[definitions] Output offset at \"" + tag_offset + "\", type \"" + tag_type + "\" => If you want to use \"mix_type\" type, you should add at least one \"inner_value\" or one \"inner_text\" input type of field.")
  612. dict_definition_output[offset_int_decimal]["write_data2"] = tmp_lst_all_input_bits_in_this_efuse_field
  613. dict_definition_output[offset_int_decimal]["write_type"] = WRITE_TYPE_BIT_AND_STRING
  614. #print(dict_definition_output)
  615. #dic key: offset
  616. #dic value: type, final_value
  617. current_offset = 0
  618. with open(args.output_bin_name, "wb") as f :
  619. while (current_offset < MAX_OUTPUT_OFFSET_DECIMAL) :
  620. if current_offset in dict_definition_output :
  621. write_data = dict_definition_output[current_offset]["write_data"]
  622. write_type = dict_definition_output[current_offset]["write_type"]
  623. if write_type == WRITE_TYPE_BIT :
  624. writeBitValueToFile(f, write_data)
  625. elif write_type == WRITE_TYPE_STRING :
  626. writeHexStringToFile(f, write_data)
  627. elif write_type == WRITE_TYPE_BIT_AND_STRING :
  628. write_data_bits = dict_definition_output[current_offset]["write_data2"]
  629. writeBitValueAndOneHexStringToFile(f, write_data_bits, write_data)
  630. else :
  631. writeBitValueToFile(f, [(0, 0)])
  632. printAndLog("[definition] Unsupported write type in offset decimal: " + str(current_offset) + ".")
  633. else :
  634. writeBitValueToFile(f, [(0, 0)])
  635. current_offset = current_offset + 4
  636. bin_file_size_before_hash = os.path.getsize(args.output_bin_name)
  637. printAndLog("")
  638. sha256_hash = get_file_sha256hexdigest(args.output_bin_name)
  639. printAndLog("Image file(" + str(bin_file_size_before_hash) + " bytes) sha256 hash: " + sha256_hash)
  640. with open(args.output_bin_name, "ab") as f :
  641. writeHexStringToFile(f, sha256_hash[0:8]) #0x1E0 if 512bytes in size
  642. writeHexStringToFile(f, sha256_hash[8:16])
  643. writeHexStringToFile(f, sha256_hash[16:24])
  644. writeHexStringToFile(f, sha256_hash[24:32])
  645. writeHexStringToFile(f, sha256_hash[32:40])
  646. writeHexStringToFile(f, sha256_hash[40:48])
  647. writeHexStringToFile(f, sha256_hash[48:56])
  648. writeHexStringToFile(f, sha256_hash[56:64])
  649. printAndLog("Append sha256 hash to bin: Done!")
  650. bin_file_size = os.path.getsize(args.output_bin_name)
  651. printAndLog("")
  652. printAndLog("[Success] Write to bin: " + os.path.abspath(args.output_bin_name) + " (size: " + str(bin_file_size) + " bytes)")
  653. printAndLog("")
  654. if __name__ == '__main__':
  655. main()