flash.py 6.4 KB

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