stm32cubeprogrammer_usb.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. * Copyright (c) 2021-2022, STMicroelectronics - All Rights Reserved
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. */
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #include <tools_share/firmware_image_package.h>
  10. #include <stm32cubeprogrammer.h>
  11. #include <usb_dfu.h>
  12. /* Undefined download address */
  13. #define UNDEFINED_DOWN_ADDR 0xFFFFFFFF
  14. struct dfu_state {
  15. uint8_t phase;
  16. uintptr_t base;
  17. size_t len;
  18. uintptr_t address;
  19. /* working buffer */
  20. uint8_t buffer[UCHAR_MAX];
  21. };
  22. static struct dfu_state dfu_state;
  23. /* minimal size of Get Pḧase = offset for additionnl information */
  24. #define GET_PHASE_LEN 9
  25. #define DFU_ERROR(...) \
  26. { \
  27. ERROR(__VA_ARGS__); \
  28. if (dfu->phase != PHASE_RESET) { \
  29. snprintf((char *)&dfu->buffer[GET_PHASE_LEN], \
  30. sizeof(dfu->buffer) - GET_PHASE_LEN, \
  31. __VA_ARGS__); \
  32. dfu->phase = PHASE_RESET; \
  33. dfu->address = UNDEFINED_DOWN_ADDR; \
  34. dfu->len = 0; \
  35. } \
  36. }
  37. static bool is_valid_header(fip_toc_header_t *header)
  38. {
  39. if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0U)) {
  40. return true;
  41. }
  42. return false;
  43. }
  44. static int dfu_callback_upload(uint8_t alt, uintptr_t *buffer, uint32_t *len,
  45. void *user_data)
  46. {
  47. int result = 0;
  48. uint32_t length = 0;
  49. struct dfu_state *dfu = (struct dfu_state *)user_data;
  50. switch (usb_dfu_get_phase(alt)) {
  51. case PHASE_CMD:
  52. /* Get Pḧase */
  53. dfu->buffer[0] = dfu->phase;
  54. dfu->buffer[1] = (uint8_t)(dfu->address);
  55. dfu->buffer[2] = (uint8_t)(dfu->address >> 8);
  56. dfu->buffer[3] = (uint8_t)(dfu->address >> 16);
  57. dfu->buffer[4] = (uint8_t)(dfu->address >> 24);
  58. dfu->buffer[5] = 0x00;
  59. dfu->buffer[6] = 0x00;
  60. dfu->buffer[7] = 0x00;
  61. dfu->buffer[8] = 0x00;
  62. length = GET_PHASE_LEN;
  63. if (dfu->phase == PHASE_FLASHLAYOUT &&
  64. dfu->address == UNDEFINED_DOWN_ADDR) {
  65. INFO("Send detach request\n");
  66. dfu->buffer[length++] = 0x01;
  67. }
  68. if (dfu->phase == PHASE_RESET) {
  69. /* error information is added by DFU_ERROR macro */
  70. length += strnlen((char *)&dfu->buffer[GET_PHASE_LEN],
  71. sizeof(dfu->buffer) - GET_PHASE_LEN)
  72. - 1;
  73. }
  74. break;
  75. default:
  76. DFU_ERROR("phase ID :%i, alternate %i for phase %i\n",
  77. dfu->phase, alt, usb_dfu_get_phase(alt));
  78. result = -EIO;
  79. break;
  80. }
  81. if (result == 0) {
  82. *len = length;
  83. *buffer = (uintptr_t)dfu->buffer;
  84. }
  85. return result;
  86. }
  87. static int dfu_callback_download(uint8_t alt, uintptr_t *buffer, uint32_t *len,
  88. void *user_data)
  89. {
  90. struct dfu_state *dfu = (struct dfu_state *)user_data;
  91. if ((dfu->phase != usb_dfu_get_phase(alt)) ||
  92. (dfu->address == UNDEFINED_DOWN_ADDR)) {
  93. DFU_ERROR("phase ID :%i, alternate %i, address %x\n",
  94. dfu->phase, alt, (uint32_t)dfu->address);
  95. return -EIO;
  96. }
  97. VERBOSE("Download %d %lx %x\n", alt, dfu->address, *len);
  98. *buffer = dfu->address;
  99. dfu->address += *len;
  100. if (dfu->address - dfu->base > dfu->len) {
  101. return -EIO;
  102. }
  103. return 0;
  104. }
  105. static int dfu_callback_manifestation(uint8_t alt, void *user_data)
  106. {
  107. struct dfu_state *dfu = (struct dfu_state *)user_data;
  108. if (dfu->phase != usb_dfu_get_phase(alt)) {
  109. ERROR("Manifestation phase ID :%i, alternate %i, address %lx\n",
  110. dfu->phase, alt, dfu->address);
  111. return -EIO;
  112. }
  113. INFO("phase ID :%i, Manifestation %d at %lx\n",
  114. dfu->phase, alt, dfu->address);
  115. switch (dfu->phase) {
  116. case PHASE_SSBL:
  117. if (!is_valid_header((fip_toc_header_t *)dfu->base)) {
  118. DFU_ERROR("FIP Header check failed for phase %d\n", alt);
  119. return -EIO;
  120. }
  121. VERBOSE("FIP header looks OK.\n");
  122. /* Configure End with request detach */
  123. dfu->phase = PHASE_FLASHLAYOUT;
  124. dfu->address = UNDEFINED_DOWN_ADDR;
  125. dfu->len = 0;
  126. break;
  127. default:
  128. DFU_ERROR("Unknown phase\n");
  129. }
  130. return 0;
  131. }
  132. /* Open a connection to the USB device */
  133. static const struct usb_dfu_media usb_dfu_fops = {
  134. .upload = dfu_callback_upload,
  135. .download = dfu_callback_download,
  136. .manifestation = dfu_callback_manifestation,
  137. };
  138. int stm32cubeprog_usb_load(struct usb_handle *usb_core_handle,
  139. uintptr_t base,
  140. size_t len)
  141. {
  142. int ret;
  143. usb_core_handle->user_data = (void *)&dfu_state;
  144. INFO("DFU USB START...\n");
  145. ret = usb_core_start(usb_core_handle);
  146. if (ret != USBD_OK) {
  147. return -EIO;
  148. }
  149. dfu_state.phase = PHASE_SSBL;
  150. dfu_state.address = base;
  151. dfu_state.base = base;
  152. dfu_state.len = len;
  153. ret = usb_dfu_loop(usb_core_handle, &usb_dfu_fops);
  154. if (ret != USBD_OK) {
  155. return -EIO;
  156. }
  157. INFO("DFU USB STOP...\n");
  158. ret = usb_core_stop(usb_core_handle);
  159. if (ret != USBD_OK) {
  160. return -EIO;
  161. }
  162. return 0;
  163. }