fw_update.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. * fw_update.c
  3. *
  4. * Update bootloader for main firmware.
  5. *
  6. * Written & released by Keir Fraser <keir.xen@gmail.com>
  7. *
  8. * This is free and unencumbered software released into the public domain.
  9. * See the file COPYING for more details, or visit <http://unlicense.org>.
  10. */
  11. /* Main bootloader: flashes the main firmware (last 96kB of Flash). */
  12. #define FIRMWARE_START 0x08002000
  13. #define FIRMWARE_END 0x08010000
  14. int EXC_reset(void) __attribute__((alias("main")));
  15. static void canary_init(void)
  16. {
  17. _irq_stackbottom[0] = _thread_stackbottom[0] = 0xdeadbeef;
  18. }
  19. static void canary_check(void)
  20. {
  21. ASSERT(_irq_stackbottom[0] == 0xdeadbeef);
  22. ASSERT(_thread_stackbottom[0] == 0xdeadbeef);
  23. }
  24. static void erase_old_firmware(void)
  25. {
  26. uint32_t p;
  27. for (p = FIRMWARE_START; p < FIRMWARE_END; p += FLASH_PAGE_SIZE)
  28. fpec_page_erase(p);
  29. }
  30. static enum {
  31. ST_inactive,
  32. ST_command_wait,
  33. ST_update,
  34. } state = ST_inactive;
  35. static uint8_t u_buf[256];
  36. static uint32_t u_prod;
  37. static struct gw_info gw_info = {
  38. /* Max Revs == 0 signals that this is the Bootloader. */
  39. .max_rev = 0,
  40. /* Only support two commands: GET_INFO and UPDATE. */
  41. .max_cmd = CMD_UPDATE,
  42. };
  43. static void update_reset(void)
  44. {
  45. state = ST_inactive;
  46. }
  47. static void update_configure(void)
  48. {
  49. state = ST_command_wait;
  50. u_prod = 0;
  51. }
  52. const struct usb_class_ops usb_cdc_acm_ops = {
  53. .reset = update_reset,
  54. .configure = update_configure
  55. };
  56. static void end_command(void *ack, unsigned int ack_len)
  57. {
  58. usb_write(EP_TX, ack, ack_len);
  59. u_prod = 0;
  60. }
  61. static struct {
  62. uint32_t len;
  63. uint32_t cur;
  64. } update;
  65. static void update_prep(uint32_t len)
  66. {
  67. fpec_init();
  68. erase_old_firmware();
  69. state = ST_update;
  70. memset(&update, 0, sizeof(update));
  71. update.len = len;
  72. printk("Update: %u bytes\n", len);
  73. }
  74. static void update_continue(void)
  75. {
  76. int len;
  77. if ((len = ep_rx_ready(EP_RX)) >= 0) {
  78. usb_read(EP_RX, &u_buf[u_prod], len);
  79. u_prod += len;
  80. }
  81. if ((len = u_prod) >= 2) {
  82. int nr = len & ~1;
  83. fpec_write(u_buf, nr, FIRMWARE_START + update.cur);
  84. update.cur += nr;
  85. u_prod -= nr;
  86. memcpy(u_buf, &u_buf[nr], u_prod);
  87. }
  88. if (update.cur >= update.len) {
  89. uint16_t crc = crc16_ccitt((void *)FIRMWARE_START, update.len, 0xffff);
  90. printk("Final CRC: %04x (%s)\n", crc, crc ? "FAIL" : "OK");
  91. u_buf[0] = !!crc;
  92. state = ST_command_wait;
  93. end_command(u_buf, 1);
  94. }
  95. }
  96. static void process_command(void)
  97. {
  98. uint8_t cmd = u_buf[0];
  99. uint8_t len = u_buf[1];
  100. uint8_t resp_sz = 2;
  101. switch (cmd) {
  102. case CMD_GET_INFO: {
  103. uint8_t idx = u_buf[2];
  104. if (len != 3) goto bad_command;
  105. if (idx != 0) goto bad_command;
  106. memset(&u_buf[2], 0, 32);
  107. gw_info.fw_major = fw_major;
  108. gw_info.fw_minor = fw_minor;
  109. /* sample_freq is used as flags: bit 0 indicates if we entered
  110. * the bootloader because PA14 is strapped to GND. */
  111. gw_info.sample_freq = !gpio_read_pin(gpioa, 14);
  112. memcpy(&u_buf[2], &gw_info, sizeof(gw_info));
  113. resp_sz += 32;
  114. break;
  115. }
  116. case CMD_UPDATE: {
  117. uint32_t u_len = *(uint32_t *)&u_buf[2];
  118. if (len != 6) goto bad_command;
  119. if (u_len & 3) goto bad_command;
  120. update_prep(u_len);
  121. break;
  122. }
  123. default:
  124. goto bad_command;
  125. }
  126. u_buf[1] = ACK_OKAY;
  127. out:
  128. end_command(u_buf, resp_sz);
  129. return;
  130. bad_command:
  131. u_buf[1] = ACK_BAD_COMMAND;
  132. goto out;
  133. }
  134. static void update_process(void)
  135. {
  136. int len;
  137. switch (state) {
  138. case ST_command_wait:
  139. len = ep_rx_ready(EP_RX);
  140. if ((len >= 0) && (len < (sizeof(u_buf)-u_prod))) {
  141. usb_read(EP_RX, &u_buf[u_prod], len);
  142. u_prod += len;
  143. }
  144. if ((u_prod >= 2) && (u_prod >= u_buf[1]) && ep_tx_ready(EP_TX)) {
  145. process_command();
  146. }
  147. break;
  148. case ST_update:
  149. update_continue();
  150. break;
  151. default:
  152. break;
  153. }
  154. }
  155. int main(void)
  156. {
  157. /* Relocate DATA. Initialise BSS. */
  158. if (_sdat != _ldat)
  159. memcpy(_sdat, _ldat, _edat-_sdat);
  160. memset(_sbss, 0, _ebss-_sbss);
  161. /* Turn off serial-wire JTAG and reclaim the GPIOs. */
  162. afio->mapr = AFIO_MAPR_SWJ_CFG_DISABLED;
  163. /* Enable GPIOA, set all pins as floating, except PA14 = weak pull-up. */
  164. rcc->apb2enr = RCC_APB2ENR_IOPAEN;
  165. gpioa->odr = 0xffffu;
  166. gpioa->crh = 0x48444444u;
  167. gpioc->crl = 0x44444444u;
  168. /* Enter update mode only if PA14 (DCLK) is strapped to GND. */
  169. if (gpio_read_pin(gpioa, 14)) {
  170. /* Nope, so jump straight at the main firmware. */
  171. uint32_t sp = *(uint32_t *)FIRMWARE_START;
  172. uint32_t pc = *(uint32_t *)(FIRMWARE_START + 4);
  173. if (sp != ~0u) { /* only if firmware is apparently not erased */
  174. asm volatile (
  175. "mov sp,%0 ; blx %1"
  176. :: "r" (sp), "r" (pc));
  177. }
  178. }
  179. canary_init();
  180. stm32_init();
  181. console_init();
  182. console_crash_on_input();
  183. board_init();
  184. delay_ms(200); /* 5v settle */
  185. printk("\n** Greaseweazle Update Bootloader v%u.%u\n", fw_major, fw_minor);
  186. printk("** Keir Fraser <keir.xen@gmail.com>\n");
  187. printk("** https://github.com/keirf/Greaseweazle\n\n");
  188. gpio_configure_pin(gpioa, 14, GPI_pull_up);
  189. usb_init();
  190. for (;;) {
  191. canary_check();
  192. usb_process();
  193. update_process();
  194. }
  195. return 0;
  196. }
  197. /*
  198. * Local variables:
  199. * mode: C
  200. * c-file-style: "Linux"
  201. * c-basic-offset: 4
  202. * tab-width: 4
  203. * indent-tabs-mode: nil
  204. * End:
  205. */