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