flash.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. #!/usr/bin/env python3
  2. from flipper.app import App
  3. from flipper.assets.coprobin import CoproBinary
  4. from flipper.cube import CubeProgrammer
  5. STATEMENT = "AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE"
  6. class Main(App):
  7. def init(self):
  8. self.subparsers = self.parser.add_subparsers(help="sub-command help")
  9. # Wipe
  10. self.parser_wipe = self.subparsers.add_parser("wipe", help="Wipe MCU Flash")
  11. self._addArgsSWD(self.parser_wipe)
  12. self.parser_wipe.set_defaults(func=self.wipe)
  13. # Core 1 boot
  14. self.parser_core1bootloader = self.subparsers.add_parser(
  15. "core1bootloader", help="Flash Core1 Bootloader"
  16. )
  17. self._addArgsSWD(self.parser_core1bootloader)
  18. self.parser_core1bootloader.add_argument(
  19. "bootloader", type=str, help="Bootloader binary"
  20. )
  21. self.parser_core1bootloader.set_defaults(func=self.core1bootloader)
  22. # Core 1 firmware
  23. self.parser_core1firmware = self.subparsers.add_parser(
  24. "core1firmware", help="Flash Core1 Firmware"
  25. )
  26. self._addArgsSWD(self.parser_core1firmware)
  27. self.parser_core1firmware.add_argument(
  28. "firmware", type=str, help="Firmware binary"
  29. )
  30. self.parser_core1firmware.set_defaults(func=self.core1firmware)
  31. # Core 1 all
  32. self.parser_core1 = self.subparsers.add_parser(
  33. "core1", help="Flash Core1 Bootloader and Firmware"
  34. )
  35. self._addArgsSWD(self.parser_core1)
  36. self.parser_core1.add_argument("bootloader", type=str, help="Bootloader binary")
  37. self.parser_core1.add_argument("firmware", type=str, help="Firmware binary")
  38. self.parser_core1.set_defaults(func=self.core1)
  39. # Core 2 fus
  40. self.parser_core2fus = self.subparsers.add_parser(
  41. "core2fus", help="Flash Core2 Firmware Update Service"
  42. )
  43. self._addArgsSWD(self.parser_core2fus)
  44. self.parser_core2fus.add_argument(
  45. "--statement",
  46. type=str,
  47. help="NEVER FLASH FUS, IT WILL ERASE CRYPTO ENCLAVE",
  48. required=True,
  49. )
  50. self.parser_core2fus.add_argument(
  51. "fus_address", type=str, help="Firmware Update Service Address"
  52. )
  53. self.parser_core2fus.add_argument(
  54. "fus", type=str, help="Firmware Update Service Binary"
  55. )
  56. self.parser_core2fus.set_defaults(func=self.core2fus)
  57. # Core 2 radio stack
  58. self.parser_core2radio = self.subparsers.add_parser(
  59. "core2radio", help="Flash Core2 Radio stack"
  60. )
  61. self._addArgsSWD(self.parser_core2radio)
  62. self.parser_core2radio.add_argument(
  63. "radio", type=str, help="Radio Stack Binary"
  64. )
  65. self.parser_core2radio.add_argument(
  66. "--addr",
  67. dest="radio_address",
  68. help="Radio Stack Binary Address, as per release_notes",
  69. type=lambda x: int(x, 16),
  70. default=0,
  71. required=False,
  72. )
  73. self.parser_core2radio.set_defaults(func=self.core2radio)
  74. def _addArgsSWD(self, parser):
  75. parser.add_argument(
  76. "--port", type=str, help="Port to connect: swd or usb1", default="swd"
  77. )
  78. parser.add_argument("--serial", type=str, help="ST-Link Serial Number")
  79. def _getCubeParams(self):
  80. return {
  81. "port": self.args.port,
  82. "serial": self.args.serial,
  83. }
  84. def wipe(self):
  85. self.logger.info("Wiping flash")
  86. cp = CubeProgrammer(self._getCubeParams())
  87. self.logger.info("Setting RDP to 0xBB")
  88. cp.setOptionBytes({"RDP": ("0xBB", "rw")})
  89. self.logger.info("Verifying RDP")
  90. r = cp.checkOptionBytes({"RDP": ("0xBB", "rw")})
  91. assert r is True
  92. self.logger.info(f"Result: {r}")
  93. self.logger.info("Setting RDP to 0xAA")
  94. cp.setOptionBytes({"RDP": ("0xAA", "rw")})
  95. self.logger.info("Verifying RDP")
  96. r = cp.checkOptionBytes({"RDP": ("0xAA", "rw")})
  97. assert r is True
  98. self.logger.info(f"Result: {r}")
  99. self.logger.info("Complete")
  100. return 0
  101. def core1bootloader(self):
  102. self.logger.info("Flashing bootloader")
  103. cp = CubeProgrammer(self._getCubeParams())
  104. cp.flashBin("0x08000000", self.args.bootloader)
  105. self.logger.info("Complete")
  106. cp.resetTarget()
  107. return 0
  108. def core1firmware(self):
  109. self.logger.info("Flashing firmware")
  110. cp = CubeProgrammer(self._getCubeParams())
  111. cp.flashBin("0x08008000", self.args.firmware)
  112. self.logger.info("Complete")
  113. cp.resetTarget()
  114. return 0
  115. def core1(self):
  116. self.logger.info("Flashing bootloader")
  117. cp = CubeProgrammer(self._getCubeParams())
  118. cp.flashBin("0x08000000", self.args.bootloader)
  119. self.logger.info("Flashing firmware")
  120. cp.flashBin("0x08008000", self.args.firmware)
  121. cp.resetTarget()
  122. self.logger.info("Complete")
  123. return 0
  124. def core2fus(self):
  125. if self.args.statement != STATEMENT:
  126. self.logger.error(
  127. "PLEASE DON'T. THIS FEATURE INTENDED ONLY FOR FACTORY FLASHING"
  128. )
  129. return 1
  130. self.logger.info("Flashing Firmware Update Service")
  131. cp = CubeProgrammer(self._getCubeParams())
  132. cp.flashCore2(self.args.fus_address, self.args.fus)
  133. self.logger.info("Complete")
  134. return 0
  135. def core2radio(self):
  136. stack_info = CoproBinary(self.args.radio)
  137. if not stack_info.is_stack():
  138. self.logger.error("Not a Radio Stack")
  139. return 1
  140. self.logger.info(f"Will flash {stack_info.img_sig.get_version()}")
  141. radio_address = self.args.radio_address
  142. if not radio_address:
  143. radio_address = stack_info.get_flash_load_addr()
  144. self.logger.warning(
  145. f"Radio address not provided, guessed as 0x{radio_address:X}"
  146. )
  147. if radio_address > 0x080E0000:
  148. self.logger.error("I KNOW WHAT YOU DID LAST SUMMER")
  149. return 1
  150. cp = CubeProgrammer(self._getCubeParams())
  151. self.logger.info("Removing Current Radio Stack")
  152. cp.deleteCore2RadioStack()
  153. self.logger.info("Flashing Radio Stack")
  154. cp.flashCore2(radio_address, self.args.radio)
  155. self.logger.info("Complete")
  156. return 0
  157. if __name__ == "__main__":
  158. Main()()