efuse.cpp 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. #include <Arduino.h>
  2. #include "efuse.h"
  3. #include <soc/efuse_reg.h>
  4. #include <esp_efuse.h>
  5. #include <esp_efuse_table.h>
  6. #include "parameters.h"
  7. static const struct {
  8. const esp_efuse_desc_t **desc;
  9. const char *name;
  10. } fuses[] = {
  11. { ESP_EFUSE_DIS_DOWNLOAD_MODE, "DIS_DOWNLOAD_MODE" },
  12. { ESP_EFUSE_DIS_USB_JTAG, "DIS_USB_JTAG" },
  13. #ifdef ESP_EFUSE_DIS_PAD_JTAG
  14. { ESP_EFUSE_DIS_PAD_JTAG, "DIS_PAD_JTAG" },
  15. #endif
  16. #ifdef ESP_EFUSE_DIS_USB_SERIAL_JTAG
  17. { ESP_EFUSE_DIS_USB_SERIAL_JTAG, "DIS_USB_SERIAL_JTAG" },
  18. #endif
  19. #ifdef ESP_EFUSE_DIS_USB_DOWNLOAD_MODE
  20. { ESP_EFUSE_DIS_USB_DOWNLOAD_MODE, "DIS_USB_DOWNLOAD_MODE" },
  21. #endif
  22. #ifdef ESP_EFUSE_DIS_FORCE_DOWNLOAD
  23. { ESP_EFUSE_DIS_FORCE_DOWNLOAD, "DIS_FORCE_DOWNLOAD" },
  24. #endif
  25. #ifdef ESP_EFUSE_DIS_LEGACY_SPI_BOOT
  26. { ESP_EFUSE_DIS_LEGACY_SPI_BOOT, "DIS_LEGACY_SPI_BOOT" },
  27. #endif
  28. };
  29. /*
  30. set efuses to prevent firmware upload except via signed web
  31. interface
  32. 当模块被设置为最高级别锁定(lock_level≥2)时,检查并永久熔断 ESP32 的关键 eFuse 位
  33. (如禁用 JTAG、禁用固件烧录、禁用 NVS 擦除等),实现硬件级防篡改,且熔断后无法恢复。
  34. */
  35. void set_efuses(void)
  36. {
  37. bool some_unset = false;
  38. for (const auto &f : fuses) {
  39. const bool v = esp_efuse_read_field_bit(f.desc); // 读取单个eFuse位的值
  40. Serial.printf("%s = %u\n", f.name, unsigned(v)); // 打印当前状态(0=未熔断,1=已熔断)
  41. some_unset |= !v; // 只要有一个eFuse位未熔断,some_unset=true
  42. }
  43. if (g.lock_level >= 2 && some_unset) { // 仅当:1.锁定级别≥2(最高级锁定);2.有未熔断的熔丝 → 执行熔断
  44. Serial.printf("Burning efuses\n");
  45. esp_efuse_batch_write_begin();
  46. for (const auto &f : fuses) {
  47. const bool v = esp_efuse_read_field_bit(f.desc); // 启动eFuse批量写入(ESP32要求批量操作)
  48. if (!v) {
  49. Serial.printf("%s -> 1\n", f.name);
  50. auto ret = esp_efuse_write_field_bit(f.desc); // 熔断该位(写入1)
  51. if (ret != ESP_OK) {
  52. Serial.printf("%s change failed\n", f.name); // 打印熔断失败日志
  53. }
  54. }
  55. }
  56. esp_efuse_batch_write_commit(); // 提交批量写入(真正执行熔断)
  57. }
  58. }