espefuse.py 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. #!/usr/bin/env python
  2. # ESP32 efuse get/set utility
  3. # https://github.com/themadinventor/esptool
  4. #
  5. # Copyright (C) 2016 Espressif Systems (Shanghai) PTE LTD
  6. #
  7. # This program is free software; you can redistribute it and/or modify it under
  8. # the terms of the GNU General Public License as published by the Free Software
  9. # Foundation; either version 2 of the License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful, but WITHOUT
  12. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License along with
  16. # this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
  17. # Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. from __future__ import division, print_function
  19. import argparse
  20. import os
  21. import struct
  22. import sys
  23. import time
  24. import esptool
  25. # Table of efuse values - (category, block, word in block, mask, write disable bit, read disable bit, type, description)
  26. # Match values in efuse_reg.h & Efuse technical reference chapter
  27. EFUSES = [
  28. ('WR_DIS', "efuse", 0, 0, 0x0000FFFF, 1, None, "int", "Efuse write disable mask"),
  29. ('RD_DIS', "efuse", 0, 0, 0x000F0000, 0, None, "int", "Efuse read disablemask"),
  30. ('FLASH_CRYPT_CNT', "security", 0, 0, 0x0FF00000, 2, None, "bitcount", "Flash encryption mode counter"),
  31. ('MAC', "identity", 0, 1, 0xFFFFFFFF, 3, None, "mac", "Factory MAC Address"),
  32. ('XPD_SDIO_FORCE', "config", 0, 4, 1 << 16, 5, None, "flag", "Ignore MTDI pin (GPIO12) for VDD_SDIO on reset"),
  33. ('XPD_SDIO_REG', "config", 0, 4, 1 << 14, 5, None, "flag", "If XPD_SDIO_FORCE, enable VDD_SDIO reg on reset"),
  34. ('XPD_SDIO_TIEH', "config", 0, 4, 1 << 15, 5, None, "flag", "If XPD_SDIO_FORCE & XPD_SDIO_REG, 1=3.3V 0=1.8V"),
  35. ('SPI_PAD_CONFIG_CLK', "config", 0, 5, 0x1F << 0, 6, None, "spipin", "Override SD_CLK pad (GPIO6/SPICLK)"),
  36. ('SPI_PAD_CONFIG_Q', "config", 0, 5, 0x1F << 5, 6, None, "spipin", "Override SD_DATA_0 pad (GPIO7/SPIQ)"),
  37. ('SPI_PAD_CONFIG_D', "config", 0, 5, 0x1F << 10, 6, None, "spipin", "Override SD_DATA_1 pad (GPIO8/SPID)"),
  38. ('SPI_PAD_CONFIG_HD', "config", 0, 3, 0x1F << 4, 6, None, "spipin", "Override SD_DATA_2 pad (GPIO9/SPIHD)"),
  39. ('SPI_PAD_CONFIG_CS0', "config", 0, 5, 0x1F << 15, 6, None, "spipin", "Override SD_CMD pad (GPIO11/SPICS0)"),
  40. ('FLASH_CRYPT_CONFIG', "security", 0, 5, 0x0F << 28, 10, 3, "int", "Flash encryption config (key tweak bits)"),
  41. ('CHIP_VER_REV1', "identity", 0, 3, 1 << 15, 3, None, "flag", "Silicon Revision 1"),
  42. ('BLK3_PART_RESERVE', "calibration", 0, 3, 1 << 14, 10, 3, "flag", "BLOCK3 partially served for ADC calibration data"),
  43. ('CHIP_VERSION', "identity", 0, 3, 0x03 << 12, 3, None, "int", "Reserved for future chip versions"),
  44. ('CHIP_PACKAGE', "identity", 0, 3, 0x07 << 9, 3, None, "int", "Chip package identifier"),
  45. ('CODING_SCHEME', "efuse", 0, 6, 0x3, 10, 3, "int", "Efuse variable block length scheme"),
  46. ('CONSOLE_DEBUG_DISABLE',"security", 0, 6, 1 << 2, 15, None, "flag", "Disable ROM BASIC interpreter fallback"),
  47. ('DISABLE_SDIO_HOST', "config", 0, 6, 1 << 3, None, None, "flag", "Disable SDIO host"),
  48. ('ABS_DONE_0', "security", 0, 6, 1 << 4, 12, None, "flag", "secure boot enabled for bootloader"),
  49. ('ABS_DONE_1', "security", 0, 6, 1 << 5, 13, None, "flag", "secure boot abstract 1 locked"),
  50. ('JTAG_DISABLE', "security", 0, 6, 1 << 6, 14, None, "flag", "Disable JTAG"),
  51. ('DISABLE_DL_ENCRYPT', "security", 0, 6, 1 << 7, 15, None, "flag", "Disable flash encryption in UART bootloader"),
  52. ('DISABLE_DL_DECRYPT', "security", 0, 6, 1 << 8, 15, None, "flag", "Disable flash decryption in UART bootloader"),
  53. ('DISABLE_DL_CACHE', "security", 0, 6, 1 << 9, 15, None, "flag", "Disable flash cache in UART bootloader"),
  54. ('KEY_STATUS', "efuse", 0, 6, 1 << 10, 10, 3, "flag", "Usage of efuse block 3 (reserved)"),
  55. ('ADC_VREF', "calibration", 0, 4,0x1F << 8,0, None, "vref", "Voltage reference calibration"),
  56. ('BLK1', "security", 1, 0, 0xFFFFFFFF, 7, 0, "keyblock", "Flash encryption key"),
  57. ('BLK2', "security", 2, 0, 0xFFFFFFFF, 8, 1, "keyblock", "Secure boot key"),
  58. ('BLK3', "security", 3, 0, 0xFFFFFFFF, 9, 2, "keyblock", "Variable Block 3"),
  59. ]
  60. # if BLK3_PART_RESERVE is set, these efuse fields are in BLK3:
  61. BLK3_PART_EFUSES = [
  62. ('ADC1_TP_LOW', "calibration", 3, 3, 0x7F << 0, 9, 2, "adc_tp", "ADC1 150mV reading"),
  63. ('ADC1_TP_HIGH', "calibration", 3, 3, 0x1FF << 7, 9, 2, "adc_tp", "ADC1 850mV reading"),
  64. ('ADC2_TP_LOW', "calibration", 3, 3, 0x7F << 16, 9, 2, "adc_tp", "ADC2 150mV reading"),
  65. ('ADC2_TP_HIGH', "calibration", 3, 3, 0x1FF << 23, 9, 2, "adc_tp", "ADC2 850mV reading"),
  66. ]
  67. # BLK3 can contain arbitrary information, and it is not possible to know whether the Custom MAC Address is present
  68. # there. Therefore, the following efuses are not shown in the efuse summary, and are accessed only by get_custom_mac
  69. # and burn_custom_mac commands.
  70. CUST_MAC_VER_EFUSE = ('CUST_MAC_VER', "identity", 3, 5, 0xFF << 24, None, None, "int", "Version of Custom MAC Address")
  71. CUST_MAC_EFUSE = ('CUST_MAC', "identity", 3, 0, 0xFFFFFFFF, None, None, "cmac", "Custom MAC Address")
  72. # Offsets and lengths of each of the 4 efuse blocks in register space
  73. #
  74. # These offsets/lens are for esptool.read_efuse(X) which takes
  75. # a word offset (into registers) not a byte offset.
  76. EFUSE_BLOCK_OFFS = [0, 14, 22, 30]
  77. EFUSE_BLOCK_LEN = [7, 8, 8, 8]
  78. # EFUSE registers & command/conf values
  79. EFUSE_REG_CONF = 0x3FF5A0FC
  80. EFUSE_CONF_WRITE = 0x5A5A
  81. EFUSE_CONF_READ = 0x5AA5
  82. EFUSE_REG_CMD = 0x3FF5A104
  83. EFUSE_CMD_WRITE = 0x2
  84. EFUSE_CMD_READ = 0x1
  85. # address of first word of write registers for each efuse
  86. EFUSE_REG_WRITE = [0x3FF5A01C, 0x3FF5A098, 0x3FF5A0B8, 0x3FF5A0D8]
  87. # 3/4 Coding scheme warnings registers
  88. EFUSE_REG_DEC_STATUS = 0x3FF5A11C
  89. EFUSE_REG_DEC_STATUS_MASK = 0xFFF
  90. EFUSE_BURN_TIMEOUT = 0.250 # seconds
  91. # Coding Scheme values
  92. CODING_SCHEME_NONE = 0
  93. CODING_SCHEME_34 = 1
  94. def confirm(action, args):
  95. print("%s%sThis is an irreversible operation." % (action, "" if action.endswith("\n") else ". "))
  96. if not args.do_not_confirm:
  97. print("Type 'BURN' (all capitals) to continue.")
  98. sys.stdout.flush() # required for Pythons which disable line buffering, ie mingw in mintty
  99. try:
  100. yes = raw_input() # raw_input renamed to input in Python 3
  101. except NameError:
  102. yes = input()
  103. if yes != "BURN":
  104. print("Aborting.")
  105. sys.exit(0)
  106. def efuse_write_reg_addr(block, word):
  107. """
  108. Return the physical address of the efuse write data register
  109. block X word X.
  110. """
  111. return EFUSE_REG_WRITE[block] + (4 * word)
  112. class EspEfuses(object):
  113. """
  114. Wrapper object to manage the efuse fields in a connected ESP bootloader
  115. """
  116. def __init__(self, esp):
  117. self._esp = esp
  118. self._efuses = [EfuseField.from_tuple(self, efuse) for efuse in EFUSES]
  119. if self["BLK3_PART_RESERVE"].get():
  120. # add these BLK3 efuses, if the BLK3_PART_RESERVE flag is set...
  121. self._efuses += [EfuseField.from_tuple(self, efuse) for efuse in BLK3_PART_EFUSES]
  122. self.coding_scheme = self["CODING_SCHEME"].get()
  123. def __getitem__(self, efuse_name):
  124. """ Return the efuse field with the given name """
  125. for e in self._efuses:
  126. if efuse_name == e.register_name:
  127. return e
  128. raise KeyError
  129. def __iter__(self):
  130. return self._efuses.__iter__()
  131. def write_efuses(self):
  132. """ Write the values in the efuse write registers to
  133. the efuse hardware, then refresh the efuse read registers.
  134. """
  135. self._esp.write_reg(EFUSE_REG_CONF, EFUSE_CONF_WRITE)
  136. self._esp.write_reg(EFUSE_REG_CMD, EFUSE_CMD_WRITE)
  137. def wait_idle():
  138. deadline = time.time() + EFUSE_BURN_TIMEOUT
  139. while time.time() < deadline:
  140. if self._esp.read_reg(EFUSE_REG_CMD) == 0:
  141. return
  142. raise esptool.FatalError("Timed out waiting for Efuse controller command to complete")
  143. wait_idle()
  144. self._esp.write_reg(EFUSE_REG_CONF, EFUSE_CONF_READ)
  145. self._esp.write_reg(EFUSE_REG_CMD, EFUSE_CMD_READ)
  146. wait_idle()
  147. def read_efuse(self, addr):
  148. return self._esp.read_efuse(addr)
  149. def read_reg(self, addr):
  150. return self._esp.read_reg(addr)
  151. def write_reg(self, addr, value):
  152. return self._esp.write_reg(addr, value)
  153. def get_coding_scheme_warnings(self):
  154. """ Check if the coding scheme has detected any errors.
  155. Meaningless for default coding scheme (0)
  156. """
  157. return self.read_reg(EFUSE_REG_DEC_STATUS) & EFUSE_REG_DEC_STATUS_MASK
  158. def get_block_len(self):
  159. """ Return the length of BLK1, BLK2, BLK3 in bytes """
  160. return 24 if self.coding_scheme == CODING_SCHEME_34 else 32
  161. class EfuseField(object):
  162. @staticmethod
  163. def from_tuple(parent, efuse_tuple):
  164. category = efuse_tuple[7]
  165. return {
  166. "mac": EfuseMacField,
  167. "cmac": EfuseCustMacField,
  168. "keyblock": EfuseKeyblockField,
  169. "spipin": EfuseSpiPinField,
  170. "vref": EfuseVRefField,
  171. "adc_tp": EfuseAdcPointCalibration,
  172. }.get(category, EfuseField)(parent, *efuse_tuple)
  173. def __init__(self, parent, register_name, category, block, word, mask, write_disable_bit, read_disable_bit, efuse_type, description):
  174. self.category = category
  175. self.parent = parent
  176. self.block = block
  177. self.word = word
  178. self.data_reg_offs = EFUSE_BLOCK_OFFS[self.block] + self.word
  179. self.mask = mask
  180. self.shift = 0
  181. # self.shift is the number of the least significant bit in the mask
  182. while mask & 0x1 == 0:
  183. self.shift += 1
  184. mask >>= 1
  185. self.write_disable_bit = write_disable_bit
  186. self.read_disable_bit = read_disable_bit
  187. self.register_name = register_name
  188. self.efuse_type = efuse_type
  189. self.description = description
  190. def get_raw(self):
  191. """ Return the raw (unformatted) numeric value of the efuse bits
  192. Returns a simple integer or (for some subclasses) a bitstring.
  193. """
  194. value = self.parent.read_efuse(self.data_reg_offs)
  195. return (value & self.mask) >> self.shift
  196. def get(self):
  197. """ Get a formatted version of the efuse value, suitable for display """
  198. return self.get_raw()
  199. def is_readable(self):
  200. """ Return true if the efuse is readable by software """
  201. if self.read_disable_bit is None:
  202. return True # read cannot be disabled
  203. value = (self.parent.read_efuse(0) >> 16) & 0xF # RD_DIS values
  204. return (value & (1 << self.read_disable_bit)) == 0
  205. def disable_read(self):
  206. if self.read_disable_bit is None:
  207. raise esptool.FatalError("This efuse cannot be read-disabled")
  208. rddis_reg_addr = efuse_write_reg_addr(0, 0)
  209. self.parent.write_reg(rddis_reg_addr, 1 << (16 + self.read_disable_bit))
  210. self.parent.write_efuses()
  211. return self.get()
  212. def is_writeable(self):
  213. if self.write_disable_bit is None:
  214. return True # write cannot be disabled
  215. value = self.parent.read_efuse(0) & 0xFFFF # WR_DIS values
  216. return (value & (1 << self.write_disable_bit)) == 0
  217. def disable_write(self):
  218. wrdis_reg_addr = efuse_write_reg_addr(0, 0)
  219. self.parent.write_reg(wrdis_reg_addr, 1 << self.write_disable_bit)
  220. self.parent.write_efuses()
  221. return self.get()
  222. def burn(self, new_value):
  223. raw_value = (new_value << self.shift) & self.mask
  224. # don't both reading old value as we can only set bits 0->1
  225. write_reg_addr = efuse_write_reg_addr(self.block, self.word)
  226. self.parent.write_reg(write_reg_addr, raw_value)
  227. self.parent.write_efuses()
  228. return self.get()
  229. class EfuseMacField(EfuseField):
  230. def get_raw(self):
  231. # MAC values are high half of second efuse word, then first efuse word
  232. words = [self.parent.read_efuse(self.data_reg_offs + word) for word in [1,0]]
  233. # endian-swap into a bitstring
  234. bitstring = struct.pack(">II", *words)
  235. return bitstring[2:] # trim 2 byte CRC from the beginning
  236. def get(self):
  237. stored_crc = self.get_stored_crc()
  238. calc_crc = self.calc_crc(self.get_raw())
  239. if calc_crc == stored_crc:
  240. valid_msg = "(CRC %02x OK)" % stored_crc
  241. else:
  242. valid_msg = "(CRC %02x invalid - calculated 0x%02x)" % (stored_crc, calc_crc)
  243. return "%s %s" % (hexify(self.get_raw(), ":"), valid_msg)
  244. def burn(self, new_value):
  245. # Writing the BLK0 default MAC is not sensible, as it's written in the factory.
  246. raise esptool.FatalError("Writing Factory MAC address is not supported")
  247. def get_stored_crc(self):
  248. return (self.parent.read_efuse(self.data_reg_offs + 1) >> 16) & 0xFF
  249. @staticmethod
  250. def calc_crc(raw_mac):
  251. """
  252. This algorithm is the equivalent of esp_crc8() in ESP32 ROM code
  253. This is CRC-8 w/ inverted polynomial value 0x8C & initial value 0x00.
  254. """
  255. result = 0x00
  256. for b in struct.unpack("B" * 6, raw_mac):
  257. result ^= b
  258. for _ in range(8):
  259. lsb = result & 1
  260. result >>= 1
  261. if lsb != 0:
  262. result ^= 0x8c
  263. return result
  264. class EfuseCustMacField(EfuseMacField):
  265. """
  266. The custom MAC field uses the formatting according to the specification for version 1
  267. """
  268. def get_raw(self):
  269. words = [self.parent.read_efuse(self.data_reg_offs + word) for word in [0,1]]
  270. bitstring = struct.pack("<II", *words)
  271. return bitstring[1:-1] # trim a byte from the beginning and one (CRC) from the end
  272. def burn(self, new_value):
  273. if len(new_value) != 6:
  274. raise RuntimeError("Invalid new value length for MAC Address (%d)!" % len(new_value))
  275. crc = self.calc_crc(new_value)
  276. # Q has 8 bytes so new_value is extended by two bytes before unpacking:
  277. i_new_value = struct.unpack("<Q", new_value + b'\x00\x00')[0]
  278. word0 = ((i_new_value & 0xFFFFFF) << 8) | crc
  279. word1 = i_new_value >> 24
  280. write_reg_addr = efuse_write_reg_addr(self.block, self.word + 0)
  281. self.parent.write_reg(write_reg_addr, word0)
  282. write_reg_addr = efuse_write_reg_addr(self.block, self.word + 1)
  283. self.parent.write_reg(write_reg_addr, word1)
  284. self.parent.write_efuses()
  285. return self.get()
  286. def get_stored_crc(self):
  287. return self.parent.read_efuse(self.data_reg_offs) & 0xFF
  288. class EfuseKeyblockField(EfuseField):
  289. def get_raw(self):
  290. words = self.get_words()
  291. return struct.pack("<" + ("I" * len(words)), *words)
  292. def get_key(self):
  293. # Keys are stored in reverse byte order
  294. result = self.get_raw()
  295. result = result[::-1]
  296. return result
  297. def get_words(self):
  298. num_words = self.parent.get_block_len() // 4
  299. return [self.parent.read_efuse(self.data_reg_offs + word) for word in range(num_words)]
  300. def get(self):
  301. return hexify(self.get_raw(), " ")
  302. def apply_34_encoding(self, inbits):
  303. """ Takes 24 byte sequence to be represented in 3/4 encoding,
  304. returns 8 words suitable for writing "encoded" to an efuse block
  305. """
  306. def popcnt(b):
  307. """ Return number of "1" bits set in 'b' """
  308. return len([x for x in bin(b) if x == "1"])
  309. outbits = b""
  310. while len(inbits) > 0: # process in chunks of 6 bytes
  311. bits = inbits[0:6]
  312. inbits = inbits[6:]
  313. xor_res = 0
  314. mul_res = 0
  315. index = 1
  316. for b in struct.unpack("B" * 6, bits):
  317. xor_res ^= b
  318. mul_res += index * popcnt(b)
  319. index += 1
  320. outbits += bits
  321. outbits += struct.pack("BB", xor_res, mul_res)
  322. return struct.unpack("<" + "I" * (len(outbits) // 4), outbits)
  323. def burn_key(self, new_value):
  324. new_value = new_value[::-1] # AES keys are stored in reverse order in efuse
  325. return self.burn(new_value)
  326. def burn(self, new_value):
  327. key_len = self.parent.get_block_len()
  328. if len(new_value) != key_len:
  329. raise RuntimeError("Invalid new value length for key block (%d), %d is required" % len(new_value), key_len)
  330. if self.parent.coding_scheme == CODING_SCHEME_34:
  331. words = self.apply_34_encoding(new_value)
  332. else:
  333. words = struct.unpack("<" + ("I" * 8), new_value)
  334. return self.burn_words(words)
  335. def burn_words(self, words, word_offset=0):
  336. write_reg_addr = efuse_write_reg_addr(self.block, self.word + word_offset)
  337. for word in words:
  338. self.parent.write_reg(write_reg_addr, word)
  339. write_reg_addr += 4
  340. warnings_before = self.parent.get_coding_scheme_warnings()
  341. self.parent.write_efuses()
  342. warnings_after = self.parent.get_coding_scheme_warnings()
  343. if warnings_after & ~warnings_before != 0:
  344. print("WARNING: Burning efuse block added coding scheme warnings 0x%x -> 0x%x. Encoding bug?" % (warnings_before, warnings_after))
  345. return self.get()
  346. class EfuseSpiPinField(EfuseField):
  347. def get(self):
  348. val = self.get_raw()
  349. if val >= 30:
  350. val += 2 # values 30,31 map to 32, 33
  351. return val
  352. def burn(self, new_value):
  353. if new_value in [30, 31]:
  354. raise esptool.FatalError("IO pins 30 & 31 cannot be set for SPI flash. 0-29, 32 & 33 only.")
  355. if new_value > 33:
  356. raise esptool.FatalError("IO pin %d cannot be set for SPI flash. 0-29, 32 & 33 only." % new_value)
  357. if new_value > 30:
  358. new_value -= 2 # values 32,33 map to 30, 31
  359. return super(EfuseSpiPinField, self).burn(new_value)
  360. class EfuseVRefField(EfuseField):
  361. VREF_OFFSET = 1100 # ideal efuse value in mV
  362. VREF_STEP_SIZE = 7 # 1 count in efuse == 7mV
  363. VREF_SIGN_BIT = 0x10
  364. VREF_MAG_BITS = 0x0F
  365. def get(self):
  366. val = self.get_raw()
  367. # sign-magnitude format
  368. if (val & self.VREF_SIGN_BIT):
  369. val = -(val & self.VREF_MAG_BITS)
  370. else:
  371. val = (val & self.VREF_MAG_BITS)
  372. val *= self.VREF_STEP_SIZE
  373. return self.VREF_OFFSET + val
  374. def burn(self, new_value):
  375. raise RuntimeError("Writing to VRef is not supported.")
  376. class EfuseAdcPointCalibration(EfuseField):
  377. TP_OFFSET = { # See TP_xxxx_OFFSET in esp_adc_cal.c in ESP-IDF
  378. "ADC1_TP_LOW": 278,
  379. "ADC2_TP_LOW": 421,
  380. "ADC1_TP_HIGH": 3265,
  381. "ADC2_TP_HIGH": 3406,
  382. }
  383. SIGN_BIT = (0x40, 0x100) # LOW, HIGH (2s complement format)
  384. STEP_SIZE = 4
  385. def get(self):
  386. idx = 0 if self.register_name.endswith("LOW") else 1
  387. sign_bit = self.SIGN_BIT[idx]
  388. offset = self.TP_OFFSET[self.register_name]
  389. raw = self.get_raw()
  390. delta = (raw & (sign_bit - 1)) - (raw & sign_bit)
  391. return offset + (delta * self.STEP_SIZE)
  392. def dump(esp, _efuses, args):
  393. """ Dump raw efuse data registers """
  394. for block in range(len(EFUSE_BLOCK_OFFS)):
  395. print("EFUSE block %d:" % block)
  396. offsets = [x + EFUSE_BLOCK_OFFS[block] for x in range(EFUSE_BLOCK_LEN[block])]
  397. print(" ".join(["%08x" % esp.read_efuse(offs) for offs in offsets]))
  398. def summary(esp, efuses, args):
  399. """ Print a human-readable summary of efuse contents """
  400. ROW_FORMAT = "%-22s %-50s%s= %s %s %s"
  401. print(ROW_FORMAT.replace("-50", "-12") % ("EFUSE_NAME", "Description", "", "[Meaningful Value]", "[Readable/Writeable]", "(Hex Value)"))
  402. print("-" * 88)
  403. for category in set(e.category for e in efuses):
  404. print("%s fuses:" % category.title())
  405. for e in (e for e in efuses if e.category == category):
  406. raw = e.get_raw()
  407. try:
  408. raw = "(0x%x)" % raw
  409. except TypeError:
  410. raw = ""
  411. (readable, writeable) = (e.is_readable(), e.is_writeable())
  412. if readable and writeable:
  413. perms = "R/W"
  414. elif readable:
  415. perms = "R/-"
  416. elif writeable:
  417. perms = "-/W"
  418. else:
  419. perms = "-/-"
  420. value = str(e.get())
  421. if not readable:
  422. value = value.replace("0", "?")
  423. print(ROW_FORMAT % (e.register_name, e.description, "\n " if len(value) > 20 else "", value, perms, raw))
  424. print("")
  425. sdio_force = efuses["XPD_SDIO_FORCE"]
  426. sdio_tieh = efuses["XPD_SDIO_TIEH"]
  427. sdio_reg = efuses["XPD_SDIO_REG"]
  428. if sdio_force.get() == 0:
  429. print("Flash voltage (VDD_SDIO) determined by GPIO12 on reset (High for 1.8V, Low/NC for 3.3V).")
  430. elif sdio_reg.get() == 0:
  431. print("Flash voltage (VDD_SDIO) internal regulator disabled by efuse.")
  432. elif sdio_tieh.get() == 0:
  433. print("Flash voltage (VDD_SDIO) set to 1.8V by efuse.")
  434. else:
  435. print("Flash voltage (VDD_SDIO) set to 3.3V by efuse.")
  436. warnings = efuses.get_coding_scheme_warnings()
  437. if warnings:
  438. print("WARNING: Coding scheme has encoding bit error warnings (0x%x)" % warnings)
  439. def burn_efuse(esp, efuses, args):
  440. efuse = efuses[args.efuse_name]
  441. old_value = efuse.get()
  442. if efuse.efuse_type == "flag":
  443. if args.new_value not in [None, 1]:
  444. raise esptool.FatalError("Efuse %s is type 'flag'. New value is not accepted for this efuse (will always burn 0->1)" % efuse.register_name)
  445. args.new_value = 1
  446. if old_value:
  447. print("Efuse %s is already burned." % efuse.register_name)
  448. return
  449. elif efuse.efuse_type == "int":
  450. if args.new_value is None:
  451. raise esptool.FatalError("New value required for efuse %s" % efuse.register_name)
  452. elif efuse.efuse_type == "spipin":
  453. if args.new_value is None or args.new_value == 0:
  454. raise esptool.FatalError("New value required for efuse %s" % efuse.register_name)
  455. elif efuse.efuse_type == "bitcount":
  456. if args.new_value is None: # find the first unset bit and set it
  457. args.new_value = old_value
  458. bit = 1
  459. while args.new_value == old_value:
  460. args.new_value = bit | old_value
  461. bit <<= 1
  462. if args.new_value & (efuse.mask >> efuse.shift) != args.new_value:
  463. raise esptool.FatalError("Value mask for efuse %s is 0x%x. Value 0x%x is too large." % (efuse.register_name, efuse.mask >> efuse.shift, args.new_value))
  464. if args.new_value | old_value != args.new_value:
  465. print("WARNING: New value contains some bits that cannot be cleared (value will be 0x%x)" % (old_value | args.new_value))
  466. confirm("Burning efuse %s (%s) 0x%x -> 0x%x" % (efuse.register_name, efuse.description, old_value, args.new_value | old_value), args)
  467. burned_value = efuse.burn(args.new_value)
  468. if burned_value == old_value:
  469. raise esptool.FatalError("Efuse %s failed to burn. Protected?" % efuse.register_name)
  470. def read_protect_efuse(esp, efuses, args):
  471. efuse = efuses[args.efuse_name]
  472. if not efuse.is_readable():
  473. print("Efuse %s is already read protected" % efuse.register_name)
  474. else:
  475. # make full list of which efuses will be disabled (ie share a read disable bit)
  476. all_disabling = [e for e in efuses if e.read_disable_bit == efuse.read_disable_bit]
  477. names = ", ".join(e.register_name for e in all_disabling)
  478. confirm("Permanently read-disabling efuse%s %s" % ("s" if len(all_disabling) > 1 else "",names), args)
  479. efuse.disable_read()
  480. def write_protect_efuse(esp, efuses, args):
  481. efuse = efuses[args.efuse_name]
  482. if not efuse.is_writeable():
  483. print("]fuse %s is already write protected" % efuse.register_name)
  484. else:
  485. # make full list of which efuses will be disabled (ie share a write disable bit)
  486. all_disabling = [e for e in efuses if e.write_disable_bit == efuse.write_disable_bit]
  487. names = ", ".join(e.register_name for e in all_disabling)
  488. confirm("Permanently write-disabling efuse%s %s" % ("s" if len(all_disabling) > 1 else "",names), args)
  489. efuse.disable_write()
  490. def burn_key(esp, efuses, args):
  491. # check block choice
  492. if args.block in ["flash_encryption", "BLK1"]:
  493. block_num = 1
  494. elif args.block in ["secure_boot", "BLK2"]:
  495. block_num = 2
  496. elif args.block == "BLK3":
  497. block_num = 3
  498. else:
  499. raise RuntimeError("args.block argument not in list!")
  500. num_bytes = efuses.get_block_len()
  501. # check keyfile
  502. keyfile = args.keyfile
  503. keyfile.seek(0,2) # seek t oend
  504. size = keyfile.tell()
  505. keyfile.seek(0)
  506. if size != num_bytes:
  507. raise esptool.FatalError("Incorrect key file size %d. Key file must be %d bytes (%d bits) of raw binary key data." %
  508. (size, num_bytes, num_bytes * 8))
  509. # check existing data
  510. efuse = [e for e in efuses if e.register_name == "BLK%d" % block_num][0]
  511. original = efuse.get_raw()
  512. EMPTY_KEY = b'\x00' * num_bytes
  513. if original != EMPTY_KEY:
  514. if not args.force_write_always:
  515. raise esptool.FatalError("Key block already has value %s." % efuse.get())
  516. else:
  517. print("WARNING: Key appears to have a value already. Trying anyhow, due to --force-write-always (result will be bitwise OR of new and old values.)")
  518. if not efuse.is_writeable():
  519. if not args.force_write_always:
  520. raise esptool.FatalError("The efuse block has already been write protected.")
  521. else:
  522. print("WARNING: Key appears to be write protected. Trying anyhow, due to --force-write-always")
  523. msg = "Write key in efuse block %d. " % block_num
  524. if args.no_protect_key:
  525. msg += "The key block will left readable and writeable (due to --no-protect-key)"
  526. else:
  527. msg += "The key block will be read and write protected (no further changes or readback)"
  528. confirm(msg, args)
  529. new_value = keyfile.read(num_bytes)
  530. new = efuse.burn_key(new_value)
  531. print("Burned key data. New value: %s" % (new,))
  532. if not args.no_protect_key:
  533. print("Disabling read/write to key efuse block...")
  534. efuse.disable_write()
  535. efuse.disable_read()
  536. if efuse.is_readable():
  537. print("WARNING: Key does not appear to have been read protected. Perhaps read disable efuse is write protected?")
  538. if efuse.is_writeable():
  539. print("WARNING: Key does not appear to have been write protected. Perhaps write disable efuse is write protected?")
  540. else:
  541. print("Key is left unprotected as per --no-protect-key argument.")
  542. def burn_block_data(esp, efuses, args):
  543. num_bytes = efuses.get_block_len()
  544. offset = args.offset
  545. data = args.datafile.read()
  546. if offset >= num_bytes:
  547. raise RuntimeError("Invalid offset: Key block only holds %d bytes." % num_bytes)
  548. if len(data) > num_bytes - offset:
  549. raise RuntimeError("Data will not fit: Key block size %d bytes, data file is %d bytes" % (num_bytes, len(data)))
  550. if efuses.coding_scheme == CODING_SCHEME_34:
  551. if offset % 6 != 0:
  552. raise RuntimeError("Device has 3/4 Coding Scheme. Can only write at offsets which are a multiple of 6.")
  553. if len(data) % 6 != 0:
  554. raise RuntimeError("Device has 3/4 Coding Scheme. Can only write data lengths which are a multiple of 6 (data is %d bytes)" % len(data))
  555. efuse = [e for e in efuses if e.register_name == args.block.upper()][0]
  556. if not args.force_write_always and \
  557. efuse.get_raw() != b'\x00' * num_bytes:
  558. raise esptool.FatalError("Efuse block already has values written.")
  559. if efuses.coding_scheme == CODING_SCHEME_NONE:
  560. pad = offset % 4
  561. if pad != 0: # left-pad to a word boundary
  562. data = (b'\x00' * pad) + data
  563. offset -= pad
  564. pad = len(data) % 4
  565. if pad != 0: # right-pad to a word boundary
  566. data += (b'\x00' * (4 - pad))
  567. words = struct.unpack("<" + "I" * (len(data) // 4), data)
  568. word_offset = offset // 4
  569. else: # CODING_SCHEME_34
  570. words = efuse.apply_34_encoding(data)
  571. word_offset = (offset // 6) * 2
  572. confirm("Burning efuse %s (%s) with %d bytes of data at offset %d in the block" % (efuse.register_name, efuse.description, len(data), offset), args)
  573. efuse.burn_words(words, word_offset)
  574. def set_flash_voltage(esp, efuses, args):
  575. sdio_force = efuses["XPD_SDIO_FORCE"]
  576. sdio_tieh = efuses["XPD_SDIO_TIEH"]
  577. sdio_reg = efuses["XPD_SDIO_REG"]
  578. # check efuses aren't burned in a way which makes this impossible
  579. if args.voltage == 'OFF' and sdio_reg.get() != 0:
  580. raise esptool.FatalError("Can't set flash regulator to OFF as XPD_SDIO_REG efuse is already burned")
  581. if args.voltage == '1.8V' and sdio_tieh.get() != 0:
  582. raise esptool.FatalError("Can't set regulator to 1.8V is XPD_SDIO_TIEH efuse is already burned")
  583. if args.voltage == 'OFF':
  584. msg = """
  585. Disable internal flash voltage regulator (VDD_SDIO). SPI flash will need to be powered from an external source.
  586. The following efuse is burned: XPD_SDIO_FORCE.
  587. It is possible to later re-enable the internal regulator (%s) by burning an additional efuse
  588. """ % ("to 3.3V" if sdio_tieh.get() != 0 else "to 1.8V or 3.3V")
  589. elif args.voltage == '1.8V':
  590. msg = """
  591. Set internal flash voltage regulator (VDD_SDIO) to 1.8V.
  592. The following efuses are burned: XPD_SDIO_FORCE, XPD_SDIO_REG.
  593. It is possible to later increase the voltage to 3.3V (permanently) by burning additional efuse XPD_SDIO_TIEH
  594. """
  595. elif args.voltage == '3.3V':
  596. msg = """
  597. Enable internal flash voltage regulator (VDD_SDIO) to 3.3V.
  598. The following efuses are burned: XPD_SDIO_FORCE, XPD_SDIO_REG, XPD_SDIO_TIEH.
  599. """
  600. confirm(msg, args)
  601. sdio_force.burn(1) # Disable GPIO12
  602. if args.voltage != 'OFF':
  603. sdio_reg.burn(1) # Enable internal regulator
  604. if args.voltage == '3.3V':
  605. sdio_tieh.burn(1)
  606. print("VDD_SDIO setting complete.")
  607. def adc_info(esp, efuses, args):
  608. adc_vref = efuses["ADC_VREF"]
  609. blk3_reserve = efuses["BLK3_PART_RESERVE"]
  610. vref_raw = adc_vref.get_raw()
  611. if vref_raw == 0:
  612. print("ADC VRef calibration: None (1100mV nominal)")
  613. else:
  614. print("ADC VRef calibration: %dmV" % adc_vref.get())
  615. if blk3_reserve.get():
  616. print("ADC readings stored in efuse BLK3:")
  617. print(" ADC1 Low reading (150mV): %d" % efuses["ADC1_TP_LOW"].get())
  618. print(" ADC1 High reading (850mV): %d" % efuses["ADC1_TP_HIGH"].get())
  619. print(" ADC2 Low reading (150mV): %d" % efuses["ADC2_TP_LOW"].get())
  620. print(" ADC2 High reading (850mV): %d" % efuses["ADC2_TP_HIGH"].get())
  621. def burn_custom_mac(esp, efuses, args):
  622. ver_fuse = EfuseField.from_tuple(efuses, CUST_MAC_VER_EFUSE)
  623. ver = ver_fuse.get()
  624. new_ver = ver | 1 # Only version 1 MAC Addresses are supported yet
  625. if ver not in [0, new_ver]:
  626. raise esptool.FatalError("The version of the custom MAC Address is already burned ({})!".format(ver))
  627. mac_fuse = EfuseField.from_tuple(efuses, CUST_MAC_EFUSE)
  628. old_mac = mac_fuse.get_raw()
  629. new_mac = struct.pack(">Q", args.mac)[2:] # Q has 8 bytes -> removing two MSBs to form a valid 6-byte MAC Address
  630. # It doesn't make sense ORing together the old_mac and new_mac because probably the old and the new CRC won't be
  631. # OR-able together.
  632. if old_mac != b'\x00' * 6:
  633. raise esptool.FatalError("Custom MAC Address was previously burned ({})!".format(hexify(old_mac, ":")))
  634. old_crc = mac_fuse.get_stored_crc()
  635. if old_crc != 0:
  636. raise esptool.FatalError("The CRC of the custom MAC Address was previously burned ({})!".format(old_crc))
  637. if ver != new_ver:
  638. confirm("Burning efuse %s (%s) 0x%x -> 0x%x" % (ver_fuse.register_name, ver_fuse.description, ver, new_ver), args)
  639. ver_fuse.burn(new_ver)
  640. confirm("Burning efuse %s (%s) %s -> %s" % (mac_fuse.register_name, mac_fuse.description, hexify(old_mac, ":"), hexify(new_mac, ":")), args)
  641. mac_fuse.burn(new_mac)
  642. def get_custom_mac(esp, efuses, args):
  643. cust_mac_ver = EfuseField.from_tuple(efuses, CUST_MAC_VER_EFUSE).get()
  644. if cust_mac_ver > 0:
  645. cust_mac = EfuseField.from_tuple(efuses, CUST_MAC_EFUSE).get()
  646. print("Custom MAC Address version {}: {}".format(cust_mac_ver, cust_mac))
  647. else:
  648. print("Custom MAC Address is not set in the device.")
  649. def hexify(bitstring, separator=""):
  650. try:
  651. as_bytes = tuple(ord(b) for b in bitstring)
  652. except TypeError: # python 3, items in bitstring already ints
  653. as_bytes = tuple(b for b in bitstring)
  654. return separator.join(("%02x" % b) for b in as_bytes)
  655. def arg_auto_int(x):
  656. return int(x, 0)
  657. def mac_int(string):
  658. if string.count(":") != 5:
  659. raise argparse.ArgumentTypeError("MAC Address needs to be a 6-byte hexadecimal format separated by colons (:)!")
  660. hexad = string.replace(":", "")
  661. if len(hexad) != 12:
  662. raise argparse.ArgumentTypeError("MAC Address needs to be a 6-byte hexadecimal number (12 hexadecimal characters)!")
  663. return int(hexad, 16)
  664. def main():
  665. parser = argparse.ArgumentParser(description='espefuse.py v%s - ESP32 efuse get/set tool' % esptool.__version__, prog='espefuse')
  666. parser.add_argument(
  667. '--baud', '-b',
  668. help='Serial port baud rate used when flashing/reading',
  669. type=arg_auto_int,
  670. default=os.environ.get('ESPTOOL_BAUD', esptool.ESPLoader.ESP_ROM_BAUD))
  671. parser.add_argument(
  672. '--port', '-p',
  673. help='Serial port device',
  674. default=os.environ.get('ESPTOOL_PORT', esptool.ESPLoader.DEFAULT_PORT))
  675. parser.add_argument(
  676. '--before',
  677. help='What to do before connecting to the chip',
  678. choices=['default_reset', 'no_reset', 'esp32r1', 'no_reset_no_sync'],
  679. default='default_reset')
  680. parser.add_argument('--do-not-confirm',
  681. help='Do not pause for confirmation before permanently writing efuses. Use with caution.', action='store_true')
  682. def add_force_write_always(p):
  683. p.add_argument('--force-write-always', help="Write the efuse even if it looks like it's already been written, or is write protected. " +
  684. "Note that this option can't disable write protection, or clear any bit which has already been set.", action='store_true')
  685. subparsers = parser.add_subparsers(
  686. dest='operation',
  687. help='Run espefuse.py {command} -h for additional help')
  688. subparsers.add_parser('dump', help='Dump raw hex values of all efuses')
  689. subparsers.add_parser('summary',
  690. help='Print human-readable summary of efuse values')
  691. p = subparsers.add_parser('burn_efuse',
  692. help='Burn the efuse with the specified name')
  693. p.add_argument('efuse_name', help='Name of efuse register to burn',
  694. choices=[efuse[0] for efuse in EFUSES])
  695. p.add_argument('new_value', help='New value to burn (not needed for flag-type efuses', nargs='?', type=esptool.arg_auto_int)
  696. p = subparsers.add_parser('read_protect_efuse',
  697. help='Disable readback for the efuse with the specified name')
  698. p.add_argument('efuse_name', help='Name of efuse register to burn',
  699. choices=[efuse[0] for efuse in EFUSES if efuse[6] is not None]) # only allow if read_disable_bit is not None
  700. p = subparsers.add_parser('write_protect_efuse',
  701. help='Disable writing to the efuse with the specified name')
  702. p.add_argument('efuse_name', help='Name of efuse register to burn',
  703. choices=[efuse[0] for efuse in EFUSES])
  704. p = subparsers.add_parser('burn_key',
  705. help='Burn a 256-bit AES key to EFUSE BLK1,BLK2 or BLK3 (flash_encryption, secure_boot).')
  706. p.add_argument('--no-protect-key', help='Disable default read- and write-protecting of the key. ' +
  707. 'If this option is not set, once the key is flashed it cannot be read back or changed.', action='store_true')
  708. add_force_write_always(p)
  709. p.add_argument('block', help='Key block to burn. "flash_encryption" is an alias for BLK1, ' +
  710. '"secure_boot" is an alias for BLK2.', choices=["secure_boot", "flash_encryption","BLK1","BLK2","BLK3"])
  711. p.add_argument('keyfile', help='File containing 256 bits of binary key data', type=argparse.FileType('rb'))
  712. p = subparsers.add_parser('burn_block_data',
  713. help="Burn non-key data to EFUSE BLK1, BLK2 or BLK3. " +
  714. " Don't use this command to burn key data for Flash Encryption or Secure Boot, " +
  715. "as the byte order of keys is swapped (use burn_key).")
  716. p.add_argument('--offset', '-o', help='Byte offset in the efuse block', type=int, default=0)
  717. add_force_write_always(p)
  718. p.add_argument('block', help='Efuse block to burn.', choices=["BLK1","BLK2","BLK3"])
  719. p.add_argument('datafile', help='File containing data to burn into the efuse block', type=argparse.FileType('rb'))
  720. p = subparsers.add_parser('set_flash_voltage',
  721. help='Permanently set the internal flash voltage regulator to either 1.8V, 3.3V or OFF. ' +
  722. 'This means GPIO12 can be high or low at reset without changing the flash voltage.')
  723. p.add_argument('voltage', help='Voltage selection',
  724. choices=['1.8V', '3.3V', 'OFF'])
  725. p = subparsers.add_parser('adc_info',
  726. help='Display information about ADC calibration data stored in efuse.')
  727. p = subparsers.add_parser('burn_custom_mac',
  728. help='Burn a 48-bit Custom MAC Address to EFUSE BLK3.')
  729. p.add_argument('mac', help='Custom MAC Address to burn given in hexadecimal format with bytes separated by colons' +
  730. ' (e.g. AB:CD:EF:01:02:03).', type=mac_int)
  731. p = subparsers.add_parser('get_custom_mac',
  732. help='Prints the Custom MAC Address.')
  733. args = parser.parse_args()
  734. print('espefuse.py v%s' % esptool.__version__)
  735. if args.operation is None:
  736. parser.print_help()
  737. parser.exit(1)
  738. # each 'operation' is a module-level function of the same name
  739. operation_func = globals()[args.operation]
  740. esp = esptool.ESP32ROM(args.port, baud=args.baud)
  741. esp.connect(args.before)
  742. # dict mapping register name to its efuse object
  743. efuses = EspEfuses(esp)
  744. operation_func(esp, efuses, args)
  745. def _main():
  746. try:
  747. main()
  748. except esptool.FatalError as e:
  749. print('\nA fatal error occurred: %s' % e)
  750. sys.exit(2)
  751. if __name__ == '__main__':
  752. _main()