Parcourir la source

On bootloader update, validate the new *before* erasing the old.

Keir Fraser il y a 4 ans
Parent
commit
efa8ddbd31
1 fichiers modifiés avec 26 ajouts et 19 suppressions
  1. 26 19
      src/floppy.c

+ 26 - 19
src/floppy.c

@@ -1014,7 +1014,6 @@ static void sink_bytes(void)
 
 static struct {
     uint32_t len;
-    uint32_t cur;
 } update;
 
 static void erase_old_bootloader(void)
@@ -1026,11 +1025,7 @@ static void erase_old_bootloader(void)
 
 static void update_prep(uint32_t len)
 {
-    fpec_init();
-    erase_old_bootloader();
-
     floppy_state = ST_update_bootloader;
-    update.cur = 0;
     update.len = len;
 
     printk("Update Bootloader: %u bytes\n", len);
@@ -1038,28 +1033,40 @@ static void update_prep(uint32_t len)
 
 static void update_continue(void)
 {
-    int len;
+    uint16_t crc;
+    int len, retry;
 
+    /* Read entire new bootloader into the u_buf[] ring. */
     if ((len = ep_rx_ready(EP_RX)) >= 0) {
         usb_read(EP_RX, &u_buf[u_prod], len);
         u_prod += len;
     }
 
-    if ((len = u_prod) >= 2) {
-        int nr = len & ~1;
-        fpec_write(u_buf, nr, BL_START + update.cur);
-        update.cur += nr;
-        u_prod -= nr;
-        memcpy(u_buf, &u_buf[nr], u_prod);
-    }
+    /* Keep going until we have the entire bootloader. */
+    if ((u_prod < update.len) || !ep_tx_ready(EP_TX))
+        return;
 
-    if ((update.cur >= update.len) && ep_tx_ready(EP_TX)) {
-        uint16_t crc = crc16_ccitt((void *)BL_START, update.len, 0xffff);
-        printk("Final CRC: %04x (%s)\n", crc, crc ? "FAIL" : "OK");
-        u_buf[0] = !!crc;
-        floppy_state = ST_command_wait;
-        floppy_end_command(u_buf, 1);
+    /* Validate the new bootloader before erasing the existing one! */
+    crc = crc16_ccitt(u_buf, update.len, 0xffff);
+    if (crc != 0)
+        goto done;
+
+    /* We are now committed to overwriting the existing bootloader. 
+     * Try really hard to write the new bootloader (including retries). */
+    fpec_init();
+    for (retry = 0; retry < 3; retry++) {
+        erase_old_bootloader();
+        fpec_write(u_buf, update.len, BL_START);
+        crc = crc16_ccitt((void *)BL_START, update.len, 0xffff);
+        if (crc == 0)
+            goto done;
     }
+
+done:
+    printk("Final CRC: %04x (%s)\n", crc, crc ? "FAIL" : "OK");
+    u_buf[0] = !!crc;
+    floppy_state = ST_command_wait;
+    floppy_end_command(u_buf, 1);
 }