dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bl_xfer.c
Go to the documentation of this file.
1 
12 /*
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful, but
19  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  * for more details.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, see <http://www.gnu.org/licenses/>
25  *
26  * Additional note on redistribution: The copyright and license notices above
27  * must be maintained in each individual source file that is a derivative work
28  * of this source file; otherwise redistribution is prohibited.
29  */
30 
31 #include "pios.h" /* PIOS_COM_TELEM_USB -- FIXME: include is too coarse */
32 
33 #include "string.h" /* memcpy */
34 
35 #include "bl_xfer.h" /* API definition */
36 
37 #include "pios_com_msg.h" /* PIOS_COM_MSG_* */
38 #include "pios_board_info.h" /* struct pios_board_info */
39 
40 #include "pios_flash.h" /* PIOS_FLASH_* */
41 
42 #define MIN(x,y) ((x) < (y) ? (x) : (y))
43 
44 static uint32_t bl_compute_partition_crc(uintptr_t partition_id, uint32_t partition_offset, uint32_t length)
45 {
46  CRC_ResetDR();
47 
48  PIOS_FLASH_start_transaction(partition_id);
49  while (length) {
50  uint8_t buf[128];
51  uint32_t bytes_to_read = MIN(sizeof(buf), length);
52  PIOS_FLASH_read_data(partition_id,
53  partition_offset,
54  buf,
55  bytes_to_read);
56  CRC_CalcBlockCRC((uint32_t *)buf, bytes_to_read >> 2);
57 
58  partition_offset += bytes_to_read;
59  length -= bytes_to_read;
60  }
61  PIOS_FLASH_end_transaction(partition_id);
62 
63  return CRC_GetCRC();
64 }
65 
66 bool bl_xfer_completed_p(const struct xfer_state * xfer)
67 {
68  return (xfer->in_progress && (xfer->bytes_to_xfer == 0));
69 }
70 
71 bool bl_xfer_crc_ok_p(const struct xfer_state * xfer)
72 {
73  if (!xfer->check_crc) {
74  /* No CRC provided for this transfer. Always indicate success. */
75  return true;
76  }
77 
78  uint32_t actual_crc = bl_compute_partition_crc(xfer->partition_id,
80  xfer->partition_size);
81 
82  return (actual_crc == xfer->crc);
83 }
84 
85 bool bl_xfer_read_start(struct xfer_state * xfer, const struct msg_xfer_start *xfer_start)
86 {
87  /* Disable any previous transfer */
88  xfer->in_progress = false;
89 
90  /* Recover a pointer to the bootloader board info blob */
91  const struct pios_board_info * bdinfo = &pios_board_info_blob;
92 
93  /* Set up the transfer */
94  switch (xfer_start->label) {
95  case DFU_PARTITION_FW:
98  xfer->partition_size -= bdinfo->desc_size;
99  xfer->original_partition_offset = 0;
100  break;
101  case DFU_PARTITION_DESC:
104  xfer->original_partition_offset = bdinfo->desc_base - bdinfo->fw_base;
105  break;
106  case DFU_PARTITION_BL:
109  xfer->original_partition_offset = 0;
110  break;
114  xfer->original_partition_offset = 0;
115  break;
119  xfer->original_partition_offset = 0;
120  break;
121  case DFU_PARTITION_LOG:
124  xfer->original_partition_offset = 0;
125  break;
129  xfer->original_partition_offset = 0;
130  break;
131  default:
132  return false;
133  }
134 
135  uint32_t bytes_to_xfer = (BE32_TO_CPU(xfer_start->packets_in_transfer) - 1) * XFER_BYTES_PER_PACKET +
136  xfer_start->words_in_last_packet * sizeof(uint32_t);
137 
138  if (bytes_to_xfer > (xfer->partition_size - xfer->original_partition_offset))
139  bytes_to_xfer = xfer->partition_size - xfer->original_partition_offset;
140 
142  xfer->bytes_to_xfer = bytes_to_xfer;
143  xfer->next_packet_number = 0;
144  xfer->in_progress = true;
145 
146  return true;
147 }
148 
150 {
151  if (!xfer->in_progress) {
152  return false;
153  }
154 
155  struct bl_messages msg = {
157  .v.xfer_cont = {
158  .current_packet_number = CPU_TO_BE32(xfer->next_packet_number),
159  },
160  };
161 
162  uint32_t bytes_this_xfer = MIN(XFER_BYTES_PER_PACKET, xfer->bytes_to_xfer);
163 
164  if (bytes_this_xfer == 0) {
165  /* No more bytes to send. We shouldn't be in this function at all */
166  return false;
167  }
168 
169  /* Read the data from flash */
171 
174  msg.v.xfer_cont.data,
175  bytes_this_xfer);
176 
178 
179  PIOS_COM_MSG_Send(PIOS_COM_TELEM_USB, (uint8_t *)&msg, sizeof(msg));
180 
181  /* Update our transfer state */
182  xfer->bytes_to_xfer -= bytes_this_xfer;
183  xfer->current_partition_offset += bytes_this_xfer;
184  xfer->next_packet_number++;
185 
186  return true;
187 }
188 
189 bool bl_xfer_write_start(struct xfer_state * xfer, const struct msg_xfer_start *xfer_start)
190 {
191  /* Disable any previous transfer */
192  xfer->in_progress = false;
193 
194  /* Recover a pointer to the bootloader board info blob */
195  const struct pios_board_info * bdinfo = &pios_board_info_blob;
196 
197  /* Set up the transfer */
198  bool partition_needs_erase = true;
199 
200  xfer->check_crc = true;
201  xfer->crc = BE32_TO_CPU(xfer_start->expected_crc);
202  xfer->original_partition_offset = 0;
203 
204  switch (xfer_start->label) {
205 #ifdef F1_UPGRADER
206  case DFU_PARTITION_BL:
209  xfer->partition_size -= bdinfo->desc_size; /* don't allow overwriting descriptor */
210  break;
211 #endif
212  case DFU_PARTITION_FW:
215  xfer->partition_size -= bdinfo->desc_size; /* don't allow overwriting descriptor */
216  break;
217  case DFU_PARTITION_DESC:
220  xfer->original_partition_offset = bdinfo->desc_base - bdinfo->fw_base;
221  xfer->check_crc = false;
222  partition_needs_erase = false;
223  break;
227  break;
231  break;
232  case DFU_PARTITION_LOG:
235  break;
239  break;
240  default:
241  return false;
242  }
243 
244  /* How many bytes is the host trying to transfer? */
245  uint32_t bytes_to_xfer = (BE32_TO_CPU(xfer_start->packets_in_transfer) - 1) * XFER_BYTES_PER_PACKET +
246  xfer_start->words_in_last_packet * sizeof(uint32_t);
247 
248  uint32_t max_bytes_in_xfer = (xfer->partition_size - xfer->original_partition_offset);
249  if (bytes_to_xfer > max_bytes_in_xfer) {
250  return false;
251  }
252 
253  /* Figure out if we need to erase the *selected* partition before writing to it */
254  if (partition_needs_erase) {
256  int32_t ret = PIOS_FLASH_erase_partition(xfer->partition_id);
258  if (ret != 0)
259  return false;
260  }
261 
263  xfer->bytes_to_xfer = bytes_to_xfer;
264  xfer->next_packet_number = 0;
265  xfer->in_progress = true;
266 
267  return true;
268 }
269 
270 bool bl_xfer_write_cont(struct xfer_state * xfer, const struct msg_xfer_cont *xfer_cont)
271 {
272  if (!xfer->in_progress) {
273  /* no transfer in progress */
274  return false;
275  }
276 
277  if (BE32_TO_CPU(xfer_cont->current_packet_number) != xfer->next_packet_number) {
278  /* packet is out of sequence */
279  return false;
280  }
281 
282  uint32_t bytes_this_xfer = MIN(XFER_BYTES_PER_PACKET, xfer->bytes_to_xfer);
283 
284  if (bytes_this_xfer == 0) {
285  /* Not expecting any more bytes. We shouldn't be in this function at all */
286  return false;
287  }
288 
289  /* Fix up the endian of the data words */
290  for (uint8_t i = 0; i < bytes_this_xfer / sizeof(uint32_t); i++) {
291  uint32_t *data = &((uint32_t *)xfer_cont->data)[i];
292  *data = BE32_TO_CPU(*data);
293  }
294 
295  /* Write the data to flash */
297 
300  xfer_cont->data,
301  bytes_this_xfer);
302 
304 
305  /* Update accounting for how many bytes we've received */
306  xfer->current_partition_offset += bytes_this_xfer;
307  xfer->bytes_to_xfer -= bytes_this_xfer;
308 
309  xfer->next_packet_number++;
310 
311  return true;
312 }
313 
315 {
316  enum pios_flash_partition_labels flash_label;
317 
318  switch (wipe_partition->label) {
319 #ifdef F1_UPGRADER
320  case DFU_PARTITION_BL:
321  flash_label = FLASH_PARTITION_LABEL_BL;
322  break;
323 #endif
324  case DFU_PARTITION_FW:
325  flash_label = FLASH_PARTITION_LABEL_FW;
326  break;
328  flash_label = FLASH_PARTITION_LABEL_SETTINGS;
329  break;
331  flash_label = FLASH_PARTITION_LABEL_AUTOTUNE;
332  break;
333  case DFU_PARTITION_LOG:
334  flash_label = FLASH_PARTITION_LABEL_LOG;
335  break;
338  break;
339  default:
340  return false;
341  }
342 
343  uintptr_t partition_id;
344  if (PIOS_FLASH_find_partition_id(flash_label, &partition_id) != 0)
345  return false;
346 
347  PIOS_FLASH_start_transaction(partition_id);
348  PIOS_FLASH_erase_partition(partition_id);
349  PIOS_FLASH_end_transaction(partition_id);
350 
351  return true;
352 }
353 
355 {
356  /* Return capabilities of the specific device */
357  const struct pios_board_info * bdinfo = &pios_board_info_blob;
358 
359  /* Compute the firmware partition CRC */
360  uintptr_t fw_partition_id;
362  uint32_t fw_crc = bl_compute_partition_crc(fw_partition_id, 0, bdinfo->fw_size);
363 
364  struct bl_messages msg = {
366  .v.cap_rep_specific = {
367  .fw_size = CPU_TO_BE32(bdinfo->fw_size),
368  .device_number = 1, /* Always 1 for "self" */
369  .bl_version = bdinfo->bl_rev,
370  .desc_size = bdinfo->desc_size,
371  .board_rev = bdinfo->board_rev,
372  .fw_crc = CPU_TO_BE32(fw_crc),
373  .device_id = CPU_TO_BE16(bdinfo->board_type << 8 | bdinfo->board_rev),
374  },
375  };
376 
377 #if defined(BL_INCLUDE_CAP_EXTENSIONS)
378  /* Fill in capabilities extensions */
379  msg.v.cap_rep_specific.cap_extension_magic = BL_CAP_EXTENSION_MAGIC;
380 
381  uintptr_t partition_id;
382  uint32_t partition_size;
383 
384  /* FW + DESC */
385  if (PIOS_FLASH_find_partition_id(FLASH_PARTITION_LABEL_FW, &partition_id) == 0) {
386 
387  PIOS_FLASH_get_partition_size(partition_id, &partition_size);
388  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_FW] = CPU_TO_BE32(partition_size - bdinfo->desc_size);
389  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_DESC] = CPU_TO_BE32(bdinfo->desc_size);
390  } else {
391  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_FW] = 0;
392  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_DESC] = 0;
393  }
394 
395  if (PIOS_FLASH_find_partition_id(FLASH_PARTITION_LABEL_BL, &partition_id) == 0) {
396  PIOS_FLASH_get_partition_size(partition_id, &partition_size);
397  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_BL] = CPU_TO_BE32(partition_size);
398  } else {
399  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_BL] = 0;
400  }
401 
403  PIOS_FLASH_get_partition_size(partition_id, &partition_size);
404  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_SETTINGS] = CPU_TO_BE32(partition_size);
405  } else {
406  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_SETTINGS] = 0;
407  }
408 
410  PIOS_FLASH_get_partition_size(partition_id, &partition_size);
411  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_AUTOTUNE] = CPU_TO_BE32(partition_size);
412  } else {
413  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_AUTOTUNE] = 0;
414  }
415 
416  if (PIOS_FLASH_find_partition_id(FLASH_PARTITION_LABEL_LOG, &partition_id) == 0) {
417  PIOS_FLASH_get_partition_size(partition_id, &partition_size);
418  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_LOG] = CPU_TO_BE32(partition_size);
419  } else {
420  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_LOG] = 0;
421  }
422 
424  PIOS_FLASH_get_partition_size(partition_id, &partition_size);
425  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_LOADABLE_EXTENSION] = CPU_TO_BE32(partition_size);
426  } else {
427  msg.v.cap_rep_specific.partition_sizes[DFU_PARTITION_LOADABLE_EXTENSION] = 0;
428  }
429 #endif /* BL_INCLUDE_CAP_EXTENSIONS */
430 
431  PIOS_COM_MSG_Send(PIOS_COM_TELEM_USB, (uint8_t *)&msg, sizeof(msg));
432 
433  return true;
434 }
435 
bool bl_xfer_completed_p(const struct xfer_state *xfer)
Definition: bl_xfer.c:66
int32_t PIOS_FLASH_find_partition_id(enum pios_flash_partition_labels label, uintptr_t *partition_id)
int32_t PIOS_COM_MSG_Send(uintptr_t com_id, const uint8_t *msg, uint16_t msg_len)
bool in_progress
Definition: bl_xfer.h:35
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:139
int32_t PIOS_FLASH_erase_partition(uintptr_t partition_id)
enum dfu_partition_label label
Definition: bl_messages.h:131
Main PiOS header to include all the compiled in PiOS options.
bool bl_xfer_read_start(struct xfer_state *xfer, const struct msg_xfer_start *xfer_start)
Definition: bl_xfer.c:85
struct msg_wipe_partition wipe_partition
#define CPU_TO_BE16(x)
Definition: pios.h:199
uint32_t original_partition_offset
Definition: bl_xfer.h:40
int32_t PIOS_FLASH_get_partition_size(uintptr_t partition_id, uint32_t *partition_size)
DFU_PARTITION_BL
Definition: bl_messages.h:66
bool bl_xfer_wipe_partition(const struct msg_wipe_partition *wipe_partition)
Definition: bl_xfer.c:314
bool check_crc
Definition: bl_xfer.h:43
uint32_t bytes_to_xfer
Definition: bl_xfer.h:46
bool bl_xfer_send_next_read_packet(struct xfer_state *xfer)
Definition: bl_xfer.c:149
uintptr_t partition_id
Definition: bl_xfer.h:37
static uint32_t bl_compute_partition_crc(uintptr_t partition_id, uint32_t partition_offset, uint32_t length)
Definition: bl_xfer.c:44
uint32_t expected_crc
Definition: bl_messages.h:133
bool bl_xfer_crc_ok_p(const struct xfer_state *xfer)
Definition: bl_xfer.c:71
#define PIOS_COM_TELEM_USB
Definition: pios_board.h:114
#define XFER_BYTES_PER_PACKET
Definition: bl_messages.h:124
#define BE32_TO_CPU(x)
Definition: pios.h:222
const struct pios_board_info pios_board_info_blob
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
bool bl_xfer_write_start(struct xfer_state *xfer, const struct msg_xfer_start *xfer_start)
Definition: bl_xfer.c:189
uint8_t length
int32_t PIOS_FLASH_write_data(uintptr_t partition_id, uint32_t offset, const uint8_t *data, uint16_t len)
#define MIN(x, y)
Definition: bl_xfer.c:42
struct bl_messages::@23::msg_capabilities_rep_specific cap_rep_specific
uint32_t current_partition_offset
Definition: bl_xfer.h:41
DFU_PARTITION_SETTINGS
Definition: bl_messages.h:66
int32_t PIOS_FLASH_end_transaction(uintptr_t partition_id)
DFU_PARTITION_AUTOTUNE
Definition: bl_messages.h:66
bool bl_xfer_write_cont(struct xfer_state *xfer, const struct msg_xfer_cont *xfer_cont)
Definition: bl_xfer.c:270
DFU_PARTITION_LOG
Definition: bl_messages.h:66
DFU_PARTITION_LOADABLE_EXTENSION
Definition: bl_messages.h:66
struct msg_xfer_start xfer_start
uint8_t i
Definition: msp_messages.h:97
COM MSG layer functions header.
uint32_t current_packet_number
Definition: bl_messages.h:138
struct bl_messages::@23::msg_xfer_cont xfer_cont
DFU_PARTITION_FW
Definition: bl_messages.h:66
uint32_t crc
Definition: bl_xfer.h:44
uint32_t fw_crc
Definition: bl_messages.h:86
uint8_t flags_command
Definition: bl_messages.h:78
enum dfu_partition_label label
Definition: bl_messages.h:152
#define CPU_TO_BE32(x)
Definition: pios.h:201
uint8_t words_in_last_packet
Definition: bl_messages.h:132
struct msg_xfer_cont xfer_cont
pios_flash_partition_labels
Definition: pios_flash.h:31
int32_t PIOS_FLASH_read_data(uintptr_t partition_id, uint32_t offset, uint8_t *data, uint16_t len)
int32_t PIOS_FLASH_start_transaction(uintptr_t partition_id)
uint32_t next_packet_number
Definition: bl_xfer.h:42
uint32_t packets_in_transfer
Definition: bl_messages.h:130
DFU_PARTITION_DESC
Definition: bl_messages.h:66
bool bl_xfer_send_capabilities_self(void)
Definition: bl_xfer.c:354
#define BL_CAP_EXTENSION_MAGIC
Definition: bl_messages.h:88
uint32_t partition_size
Definition: bl_xfer.h:39