bootloader: Reimplement flash::run_command() in C.
authorTilman Sauerbeck <tilman@code-monkey.de>
Sun, 10 Nov 2019 17:58:44 +0000 (18:58 +0100)
committerTilman Sauerbeck <tilman@code-monkey.de>
Sun, 5 Jan 2020 19:38:11 +0000 (20:38 +0100)
While running a flash command that operates on a given flash block,
executing code from that same flash block will cause read-while-write
errors that lock up the core.

Thus we need to ensure that no interrupt handler will execute
during that time, and we also need to relocate the respective
flash code to RAM.

SConscript.libcommon
src/bootloader/flash.rs
src/common/flash.c [new file with mode: 0644]

index a8534c83b43faf8f021e207582e311a3ed68760a..3e229c23dd65585b900a3bba845f8e7a2c176b2c 100644 (file)
@@ -18,6 +18,7 @@ source_files_c = [
     'src/common/startup.c',
     'src/common/systick.c',
     'src/common/ringbuf.c',
+    'src/common/flash.c',
     'src/common/usb_device_ch9.c',
     'src/common/usb_device_dci.c',
     'src/common/usb_device_descriptor.c',
index f6c00d956622a9068216d87a128c89b858e0c78f..7d0d294f0d92b62c4d2c256873481366f173cf85 100644 (file)
@@ -41,7 +41,6 @@ const FTFA_FSTAT_MGSTAT0 : u8 = 1 << 0;
 const FTFA_FSTAT_FPVIOL  : u8 = 1 << 4;
 const FTFA_FSTAT_ACCERR  : u8 = 1 << 5;
 const FTFA_FSTAT_RDCOLERR: u8 = 1 << 6;
-const FTFA_FSTAT_CCIF    : u8 = 1 << 7;
 
 const FCMD_RD1SEC : u8 = 0x01;
 const FCMD_PGM4   : u8 = 0x06;
@@ -49,6 +48,10 @@ const FCMD_ERSSCR : u8 = 0x09;
 
 pub const SECTOR_SIZE : usize = 1024;
 
+extern {
+    fn flash_run_command() -> u8;
+}
+
 // The hardware refuses to run another command (or even take the new command's
 // parameters) until the errors reported by a previous command have been
 // acknowledged (see KL26P121M48SF4RM.pdf p. 445).
@@ -59,19 +62,7 @@ fn prepare_command() {
 }
 
 fn run_command() -> u8 {
-    let mut fstat = Reg8::new(FTFA_FSTAT);
-
-    // Start command.
-    fstat.write(FTFA_FSTAT_CCIF);
-
-    // Wait for it to finish.
-    loop {
-        let v = fstat.read();
-
-        if (v & FTFA_FSTAT_CCIF) != 0 {
-            return v;
-        }
-    }
+    unsafe { flash_run_command() }
 }
 
 fn erase_check(sector: u32) -> bool {
diff --git a/src/common/flash.c b/src/common/flash.c
new file mode 100644 (file)
index 0000000..3dff454
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 Tilman Sauerbeck (tilman at code-monkey de)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+static const uint32_t FTFA_FSTAT = 0x40020000;
+
+static const uint8_t FTFA_FSTAT_CCIF = 1 << 7;
+
+__attribute__((section(".data")))
+static uint8_t
+run_command(void)
+{
+    volatile uint8_t *fstat = (uint8_t *) FTFA_FSTAT;
+
+    /* Start command. */
+    *fstat = FTFA_FSTAT_CCIF;
+
+    /* Wait for it to finish. */
+    for (;;) {
+        uint8_t v = *fstat;
+
+        if ((v & FTFA_FSTAT_CCIF) != 0) {
+            return v;
+        }
+    }
+}
+
+uint8_t
+flash_run_command(void)
+{
+    asm volatile ("cpsid i");
+
+    uint8_t status = run_command();
+
+    asm volatile ("cpsie i");
+
+    return status;
+}