Move STLINK_DEBUG_* defines into enum, move flash_loader code into seperate header...
authorJerry Jacobs <jerry.jacobs@xor-gate.org>
Fri, 20 May 2016 18:03:57 +0000 (20:03 +0200)
committerJerry Jacobs <jerry.jacobs@xor-gate.org>
Fri, 20 May 2016 18:03:57 +0000 (20:03 +0200)
CMakeLists.txt
Makefile.am
include/stlink.h
include/stlink/commands.h [new file with mode: 0644]
include/stlink/flash_loader.h [new file with mode: 0644]
src/common.c
src/flash_loader.c [new file with mode: 0644]

index 89bd8596874fe9f277b942aefd2f89c02d9d2af8..dab482939a8c3fdb10a37de4c379827038ce6255 100644 (file)
@@ -54,6 +54,7 @@ set(STLINK_HEADERS
        include/stlink/logging.h
        include/stlink/mmap.h
        include/stlink/chipid.h
+       include/stlink/flash_loader.h
 )
 
 set(STLINK_SOURCE
@@ -62,6 +63,7 @@ set(STLINK_SOURCE
        src/usb.c
        src/sg.c
        src/logging.c
+       src/flash_loader.c
 )
 
 include_directories(${LIBUSB_INCLUDE_DIR})
index a3114c6e4799e8dcc8c20c4090929272e27fdfe6..79ce10c229043d7d4f8bf919f53761784c87263a 100644 (file)
@@ -22,7 +22,8 @@ CFILES = \
        src/common.c \
        src/usb.c \
        src/sg.c \
-       src/logging.c
+       src/logging.c \
+       src/flash_loader.c
 
 if !MINGW
 CFILES += src/tools/term.c
@@ -32,6 +33,8 @@ HFILES        = \
        include/stlink.h \
        include/stlink/chipid.h \
        include/stlink/usb.h \
+       include/stlink/flash_loader.h \
+       include/stlink/commands.h \
        include/stlink/sg.h \
        include/stlink/logging.h \
        include/stlink/mmap.h
index 3941f4216483b4e5ada27185df051ed70841bf54..a20f815cbd2a9299d8cbdad27c38e0cea90953c7 100644 (file)
@@ -49,27 +49,6 @@ extern "C" {
 #define STLINK_DEV_DEBUG_MODE          0x02
 #define STLINK_DEV_UNKNOWN_MODE        -1
 
-    // jtag mode cmds
-#define STLINK_DEBUG_ENTER             0x20
-#define STLINK_DEBUG_EXIT              0x21
-#define STLINK_DEBUG_READCOREID        0x22
-#define STLINK_DEBUG_GETSTATUS         0x01
-#define STLINK_DEBUG_FORCEDEBUG        0x02
-#define STLINK_DEBUG_RESETSYS          0x03
-#define STLINK_DEBUG_READALLREGS       0x04
-#define STLINK_DEBUG_READREG           0x05
-#define STLINK_DEBUG_WRITEREG          0x06
-#define STLINK_DEBUG_READMEM_32BIT     0x07
-#define STLINK_DEBUG_WRITEMEM_32BIT    0x08
-#define STLINK_DEBUG_RUNCORE           0x09
-#define STLINK_DEBUG_STEPCORE          0x0a
-#define STLINK_DEBUG_SETFP             0x0b
-#define STLINK_DEBUG_WRITEMEM_8BIT     0x0d
-#define STLINK_DEBUG_CLEARFP           0x0e
-#define STLINK_DEBUG_WRITEDEBUGREG     0x0f
-#define STLINK_DEBUG_ENTER_SWD         0xa3
-#define STLINK_DEBUG_ENTER_JTAG        0x00
-
     // TODO - possible poor names...
 #define STLINK_SWD_ENTER 0x30
 #define STLINK_SWD_READCOREID 0x32  // TBD
@@ -116,8 +95,6 @@ extern "C" {
         FLASH_TYPE_L4,
     };
 
-#include "stlink/chipid.h"
-
     typedef struct {
         uint32_t r[16];
         uint32_t s[32];
@@ -135,6 +112,11 @@ extern "C" {
 
     typedef uint32_t stm32_addr_t;
 
+typedef struct flash_loader {
+       stm32_addr_t loader_addr; /* loader sram adddr */
+       stm32_addr_t buf_addr; /* buffer sram address */
+} flash_loader_t;
+
     typedef struct _cortex_m3_cpuid_ {
         uint16_t implementer_id;
         uint16_t variant;
@@ -150,11 +132,6 @@ extern "C" {
         uint32_t stlink_pid;
     } stlink_version_t;
 
-    typedef struct flash_loader {
-        stm32_addr_t loader_addr; /* loader sram adddr */
-        stm32_addr_t buf_addr; /* buffer sram address */
-    } flash_loader_t;
-
     enum transport_type {
         TRANSPORT_TYPE_ZERO = 0,
         TRANSPORT_TYPE_LIBSG,
@@ -298,6 +275,9 @@ extern "C" {
 
 #include "stlink/sg.h"
 #include "stlink/usb.h"
+#include "stlink/commands.h"
+#include "stlink/chipid.h"
+#include "stlink/flash_loader.h"
 
 #ifdef __cplusplus
 }
diff --git a/include/stlink/commands.h b/include/stlink/commands.h
new file mode 100644 (file)
index 0000000..9ff5a8f
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef STLINK_COMMANDS_H_
+#define STLINK_COMMANDS_H_
+
+enum stlink_debug_commands {
+       STLINK_DEBUG_ENTER_JTAG     = 0x00,
+       STLINK_DEBUG_GETSTATUS      = 0x01,
+       STLINK_DEBUG_FORCEDEBUG     = 0x02,
+       STLINK_DEBUG_RESETSYS       = 0x03,
+       STLINK_DEBUG_READALLREGS    = 0x04,
+       STLINK_DEBUG_READREG        = 0x05,
+       STLINK_DEBUG_WRITEREG       = 0x06,
+       STLINK_DEBUG_READMEM_32BIT  = 0x07,
+       STLINK_DEBUG_WRITEMEM_32BIT = 0x08,
+       STLINK_DEBUG_RUNCORE        = 0x09,
+       STLINK_DEBUG_STEPCORE       = 0x0a,
+       STLINK_DEBUG_SETFP          = 0x0b,
+       STLINK_DEBUG_WRITEMEM_8BIT  = 0x0d,
+       STLINK_DEBUG_CLEARFP        = 0x0e,
+       STLINK_DEBUG_WRITEDEBUGREG  = 0x0f,
+       STLINK_DEBUG_ENTER          = 0x20,
+       STLINK_DEBUG_EXIT           = 0x21,
+       STLINK_DEBUG_READCOREID     = 0x22,
+       STLINK_DEBUG_ENTER_SWD      = 0xa3
+};
+
+#endif /* STLINK_COMMANDS_H_ */
diff --git a/include/stlink/flash_loader.h b/include/stlink/flash_loader.h
new file mode 100644 (file)
index 0000000..95042f7
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * File:   stlink.h
+ *
+ * This should contain all the common top level stlink interfaces, regardless
+ * of how the backend does the work....
+ */
+#ifndef STLINK_FLASH_LOADER_H_
+#define STLINK_FLASH_LOADER_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "stlink.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int stlink_flash_loader_init(stlink_t *sl, flash_loader_t* fl);
+int stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size);
+int stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STLINK_FLASH_LOADER_H_ */
index 729c739da2ecef9c730ef477098bafb6128bccee..72704812570622decbe73a50dff7ee9982584000 100644 (file)
@@ -1416,252 +1416,6 @@ int stlink_erase_flash_mass(stlink_t *sl) {
     return 0;
 }
 
-int init_flash_loader(stlink_t *sl, flash_loader_t* fl) {
-    size_t size;
-
-    /* allocate the loader in sram */
-    if (write_loader_to_sram(sl, &fl->loader_addr, &size) == -1) {
-        WLOG("Failed to write flash loader to sram!\n");
-        return -1;
-    }
-
-    /* allocate a one page buffer in sram right after loader */
-    fl->buf_addr = fl->loader_addr + size;
-    ILOG("Successfully loaded flash loader in sram\n");
-    return 0;
-}
-
-int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size) {
-    /* from openocd, contrib/loaders/flash/stm32.s */
-    static const uint8_t loader_code_stm32vl[] = {
-        0x08, 0x4c, /* ldr     r4, STM32_FLASH_BASE */
-        0x1c, 0x44, /* add     r4, r3 */
-        /* write_half_word: */
-        0x01, 0x23, /* movs    r3, #0x01 */
-        0x23, 0x61, /* str     r3, [r4, #STM32_FLASH_CR_OFFSET] */
-        0x30, 0xf8, 0x02, 0x3b, /* ldrh        r3, [r0], #0x02 */
-        0x21, 0xf8, 0x02, 0x3b, /* strh        r3, [r1], #0x02 */
-        /* busy: */
-        0xe3, 0x68, /* ldr     r3, [r4, #STM32_FLASH_SR_OFFSET] */
-        0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */
-        0xfb, 0xd0, /* beq     busy */
-        0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */
-        0x01, 0xd1, /* bne     exit */
-        0x01, 0x3a, /* subs    r2, r2, #0x01 */
-        0xf0, 0xd1, /* bne     write_half_word */
-        /* exit: */
-        0x00, 0xbe, /* bkpt    #0x00 */
-        0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
-    };
-
-    /* flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored */
-    static const uint8_t loader_code_stm32f0[] = {
-#if 1
-        /*
-         * These two NOPs here are a safety precaution, added by Pekka Nikander
-         * while debugging the STM32F05x support.  They may not be needed, but
-         * there were strange problems with simpler programs, like a program
-         * that had just a breakpoint or a program that first moved zero to register r2
-         * and then had a breakpoint.  So, it appears safest to have these two nops.
-         *
-         * Feel free to remove them, if you dare, but then please do test the result
-         * rigorously.  Also, if you remove these, it may be a good idea first to
-         * #if 0 them out, with a comment when these were taken out, and to remove
-         * these only a few months later...  But YMMV.
-         */
-        0x00, 0x30, //     nop     /* add r0,#0 */
-        0x00, 0x30, //     nop     /* add r0,#0 */
-#endif
-        0x0A, 0x4C, //     ldr     r4, STM32_FLASH_BASE
-        0x01, 0x25, //     mov     r5, #1            /*  FLASH_CR_PG, FLASH_SR_BUSY */
-        0x04, 0x26, //     mov     r6, #4            /*  PGERR  */
-        // write_half_word:
-        0x23, 0x69, //     ldr     r3, [r4, #16]     /*  FLASH->CR   */
-        0x2B, 0x43, //     orr     r3, r5
-        0x23, 0x61, //     str     r3, [r4, #16]     /*  FLASH->CR |= FLASH_CR_PG */
-        0x03, 0x88, //     ldrh    r3, [r0]          /*  r3 = *sram */
-        0x0B, 0x80, //     strh    r3, [r1]          /*  *flash = r3 */
-        // busy:
-        0xE3, 0x68, //     ldr    r3, [r4, #12]     /*  FLASH->SR  */
-        0x2B, 0x42, //     tst    r3, r5            /*  FLASH_SR_BUSY  */
-        0xFC, 0xD0, //     beq    busy
-
-        0x33, 0x42, //     tst    r3, r6            /*  PGERR  */
-        0x04, 0xD1, //     bne    exit
-
-        0x02, 0x30, //     add     r0, r0, #2        /*  sram += 2  */
-        0x02, 0x31, //     add     r1, r1, #2        /*  flash += 2  */
-        0x01, 0x3A, //     sub     r2, r2, #0x01     /*  count--  */
-        0x00, 0x2A, //     cmp     r2, #0
-        0xF0, 0xD1, //     bne    write_half_word
-        // exit:
-        0x23, 0x69, //     ldr     r3, [r4, #16]     /*  FLASH->CR  */
-        0xAB, 0x43, //     bic     r3, r5
-        0x23, 0x61, //     str     r3, [r4, #16]     /*  FLASH->CR &= ~FLASH_CR_PG  */
-        0x00, 0xBE, //     bkpt        #0x00
-        0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
-    };
-
-    static const uint8_t loader_code_stm32l[] = {
-        // flashloaders/stm32lx.s
-
-        0x04, 0xe0, //     b test_done          ; Go to compare
-        // write_word:
-        0x04, 0x68, //     ldr      r4, [r0]    ; Load one word from address in r0
-        0x0c, 0x60, //     str      r4, [r1]    ; Store the word to address in r1
-        0x04, 0x30, //     adds     r0, #4      ; Increment r0
-        0x04, 0x31, //     adds     r1, #4      ; Increment r1
-        0x01, 0x3a, //     subs     r2, #1      ; Decrement r2
-        // test_done:
-        0x00, 0x2a, //     cmp      r2, #0      ; Compare r2 to 0
-        0xf8, 0xd8, //     bhi      write_word  ; Loop if above 0
-        0x00, 0xbe, //     bkpt     #0x00       ; Set breakpoint to exit
-        0x00, 0x00
-    };
-
-    static const uint8_t loader_code_stm32f4[] = {
-        // flashloaders/stm32f4.s
-
-        0x07, 0x4b,
-
-        0x62, 0xb1,
-        0x04, 0x68,
-        0x0c, 0x60,
-
-        0xdc, 0x89,
-        0x14, 0xf0, 0x01, 0x0f,
-        0xfb, 0xd1,
-        0x00, 0xf1, 0x04, 0x00,
-        0x01, 0xf1, 0x04, 0x01,
-        0xa2, 0xf1, 0x01, 0x02,
-        0xf1, 0xe7,
-
-        0x00, 0xbe,
-
-        0x00, 0x3c, 0x02, 0x40,
-    };
-
-    static const uint8_t loader_code_stm32f4_lv[] = {
-        // flashloaders/stm32f4lv.s
-        0x92, 0x00,
-
-        0x08, 0x4b,
-        0x62, 0xb1,
-        0x04, 0x78,
-        0x0c, 0x70,
-
-        0xdc, 0x89,
-        0x14, 0xf0, 0x01, 0x0f,
-        0xfb, 0xd1,
-        0x00, 0xf1, 0x01, 0x00,
-        0x01, 0xf1, 0x01, 0x01,
-        0xa2, 0xf1, 0x01, 0x02,
-        0xf1, 0xe7,
-
-        0x00, 0xbe,
-        0x00, 0xbf,
-
-        0x00, 0x3c, 0x02, 0x40,
-    };
-
-    static const uint8_t loader_code_stm32l4[] = {
-        // flashloaders/stm32l4.s
-        0x08, 0x4b,             // start: ldr   r3, [pc, #32] ; <flash_base>
-        0x72, 0xb1,             // next:  cbz   r2, <done>
-        0x04, 0x68,             //        ldr   r4, [r0, #0]
-        0x45, 0x68,             //        ldr   r5, [r0, #4]
-        0x0c, 0x60,             //        str   r4, [r1, #0]
-        0x4d, 0x60,             //        str   r5, [r1, #4]
-        0x5c, 0x8a,             // wait:  ldrh  r4, [r3, #18]
-        0x14, 0xf0, 0x01, 0x0f, //        tst.w r4, #1
-        0xfb, 0xd1,             //        bne.n <wait>
-        0x00, 0xf1, 0x08, 0x00, //        add.w r0, r0, #8
-        0x01, 0xf1, 0x08, 0x01, //        add.w r1, r1, #8
-        0xa2, 0xf1, 0x01, 0x02, //        sub.w r2, r2, #1
-        0xef, 0xe7,             //        b.n   <next>
-        0x00, 0xbe,             // done:  bkpt  0x0000
-        0x00, 0x20, 0x02, 0x40  // flash_base:  .word 0x40022000
-    };
-
-       static const uint8_t loader_code_stm32f7[] = {
-        0x08, 0x4b,
-        0x72, 0xb1,
-        0x04, 0x68,
-        0x0c, 0x60,
-        0xbf, 0xf3, 0x4f, 0x8f,        // DSB Memory barrier for in order flash write
-        0xdc, 0x89,
-        0x14, 0xf0, 0x01, 0x0f,
-        0xfb, 0xd1,
-        0x00, 0xf1, 0x04, 0x00,
-        0x01, 0xf1, 0x04, 0x01,
-        0xa2, 0xf1, 0x01, 0x02,
-        0xef, 0xe7,
-        0x00, 0xbe,                   //     bkpt      #0x00
-        0x00, 0x3c, 0x02, 0x40,
-    };
-
-    const uint8_t* loader_code;
-    size_t loader_size;
-
-    if (sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM || sl->chip_id == STLINK_CHIPID_STM32_L1_CAT2
-            || sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM_PLUS || sl->chip_id == STLINK_CHIPID_STM32_L1_HIGH
-            || sl->chip_id == STLINK_CHIPID_STM32_L152_RE
-            || sl->chip_id == STLINK_CHIPID_STM32_L0 || sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 || sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2) { /* stm32l */
-        loader_code = loader_code_stm32l;
-        loader_size = sizeof(loader_code_stm32l);
-    } else if (sl->core_id == STM32VL_CORE_ID 
-            || sl->chip_id == STLINK_CHIPID_STM32_F3
-            || sl->chip_id == STLINK_CHIPID_STM32_F3_SMALL
-            || sl->chip_id == STLINK_CHIPID_STM32_F303_HIGH
-            || sl->chip_id == STLINK_CHIPID_STM32_F37x
-            || sl->chip_id == STLINK_CHIPID_STM32_F334) {
-        loader_code = loader_code_stm32vl;
-        loader_size = sizeof(loader_code_stm32vl);
-    } else if (sl->chip_id == STLINK_CHIPID_STM32_F2      ||
-               sl->chip_id == STLINK_CHIPID_STM32_F4     ||
-               sl->chip_id == STLINK_CHIPID_STM32_F4_DE  ||
-               sl->chip_id == STLINK_CHIPID_STM32_F4_LP  ||
-               sl->chip_id == STLINK_CHIPID_STM32_F4_HD  ||
-               sl->chip_id == STLINK_CHIPID_STM32_F4_DSI ||
-               sl->chip_id == STLINK_CHIPID_STM32_F410   ||
-               sl->chip_id == STLINK_CHIPID_STM32_F411RE ||
-               sl->chip_id == STLINK_CHIPID_STM32_F446
-               ) {
-        int voltage = stlink_target_voltage(sl);
-        if (voltage == -1) {
-            printf("Failed to read Target voltage\n");
-            return voltage;
-        } else if (voltage > 2700) {
-            loader_code = loader_code_stm32f4;
-            loader_size = sizeof(loader_code_stm32f4);
-        } else {
-            loader_code = loader_code_stm32f4_lv;
-            loader_size = sizeof(loader_code_stm32f4_lv);
-        }
-    } else if (sl->chip_id == STLINK_CHIPID_STM32_F7){
-        loader_code = loader_code_stm32f7;
-        loader_size = sizeof(loader_code_stm32f7);
-    } else if (sl->chip_id == STLINK_CHIPID_STM32_F0 || sl->chip_id == STLINK_CHIPID_STM32_F04 || sl->chip_id == STLINK_CHIPID_STM32_F0_CAN || sl->chip_id == STLINK_CHIPID_STM32_F0_SMALL || sl->chip_id == STLINK_CHIPID_STM32_F09X) {
-        loader_code = loader_code_stm32f0;
-        loader_size = sizeof(loader_code_stm32f0);
-    } else if (sl->chip_id == STLINK_CHIPID_STM32_L4) {
-        loader_code = loader_code_stm32l4;
-        loader_size = sizeof(loader_code_stm32l4);
-    } else {
-        ELOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id);
-        return -1;
-    }
-
-    memcpy(sl->q_buf, loader_code, loader_size);
-    stlink_write_mem32(sl, sl->sram_base, loader_size);
-
-    *addr = sl->sram_base;
-    *size = loader_size;
-
-    /* success */
-    return 0;
-}
-
 int stlink_fcheck_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
     /* check the contents of path are at addr */
 
@@ -1729,8 +1483,8 @@ int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uin
 
     ILOG("Starting Half page flash write for STM32L core id\n");
     /* flash loader initialization */
-    if (init_flash_loader(sl, &fl) == -1) {
-        WLOG("init_flash_loader() == -1\n");
+    if (stlink_flash_loader_init(sl, &fl) == -1) {
+        WLOG("stlink_flash_loader_init() == -1\n");
         return -1;
     }
     /* Unlock already done */
@@ -1745,8 +1499,8 @@ int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uin
     } while ((val & (1 << 0)) != 0);
 
     for (count = 0; count  < num_half_pages; count ++) {
-        if (run_flash_loader(sl, &fl, addr + count * pagesize, base + count * pagesize, pagesize) == -1) {
-            WLOG("l1_run_flash_loader(%#zx) failed! == -1\n", addr + count * pagesize);
+        if (stlink_flash_loader_run(sl, &fl, addr + count * pagesize, base + count * pagesize, pagesize) == -1) {
+            WLOG("l1_stlink_flash_loader_run(%#zx) failed! == -1\n", addr + count * pagesize);
             stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
             val &= ~((1 << FLASH_L1_FPRG) |(1 << FLASH_L1_PROG));
             stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
@@ -1827,8 +1581,8 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t
 
         ILOG("Starting Flash write for F2/F4/L4\n");
         /* flash loader initialization */
-        if (init_flash_loader(sl, &fl) == -1) {
-            ELOG("init_flash_loader() == -1\n");
+        if (stlink_flash_loader_init(sl, &fl) == -1) {
+            ELOG("stlink_flash_loader_init() == -1\n");
             return -1;
         }
 
@@ -1869,8 +1623,8 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t
 
             printf("size: %zu\n", size);
 
-            if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
-                ELOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
+            if (stlink_flash_loader_run(sl, &fl, addr + off, base + off, size) == -1) {
+                ELOG("stlink_flash_loader_run(%#zx) failed! == -1\n", addr + off);
                 return -1;
             }
 
@@ -1960,8 +1714,8 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t
     } else if (sl->flash_type == FLASH_TYPE_F0) {
         ILOG("Starting Flash write for VL/F0/F3 core id\n");
         /* flash loader initialization */
-        if (init_flash_loader(sl, &fl) == -1) {
-            ELOG("init_flash_loader() == -1\n");
+        if (stlink_flash_loader_init(sl, &fl) == -1) {
+            ELOG("stlink_flash_loader_init() == -1\n");
             return -1;
         }
 
@@ -1974,9 +1728,9 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t
             /* unlock and set programming mode */
             unlock_flash_if(sl);
             set_flash_cr_pg(sl);
-            //DLOG("Finished setting flash cr pg, running loader!\n");
-            if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
-                ELOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
+            DLOG("Finished setting flash cr pg, running loader!\n");
+            if (stlink_flash_loader_run(sl, &fl, addr + off, base + off, size) == -1) {
+                ELOG("stlink_flash_loader_run(%#zx) failed! == -1\n", addr + off);
                 return -1;
             }
             lock_flash(sl);
@@ -2042,64 +1796,3 @@ int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
     unmap_file(&mf);
     return err;
 }
-
-int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size) {
-
-    reg rr;
-    int i = 0;
-    size_t count = 0;
-
-    DLOG("Running flash loader, write address:%#x, size: %zd\n", target, size);
-    // FIXME This can never return -1
-    if (write_buffer_to_sram(sl, fl, buf, size) == -1) {
-        // IMPOSSIBLE!
-        ELOG("write_buffer_to_sram() == -1\n");
-        return -1;
-    }
-
-    if (sl->flash_type == FLASH_TYPE_F0) {
-        count = size / sizeof(uint16_t);
-        if (size % sizeof(uint16_t))
-            ++count;
-    } else if (sl->flash_type == FLASH_TYPE_F4 || sl->flash_type == FLASH_TYPE_L0) {
-        count = size / sizeof(uint32_t);
-        if (size % sizeof(uint32_t))
-            ++count;
-    } else if (sl->flash_type == FLASH_TYPE_L4) {
-        count = size / sizeof(uint64_t);
-        if (size % sizeof(uint64_t))
-            ++count;
-    }
-
-    /* setup core */
-    stlink_write_reg(sl, fl->buf_addr, 0); /* source */
-    stlink_write_reg(sl, target, 1); /* target */
-    stlink_write_reg(sl, count, 2); /* count */
-    stlink_write_reg(sl, 0, 3); /* flash bank 0 (input), only used on F0, but armless fopr others */
-    stlink_write_reg(sl, fl->loader_addr, 15); /* pc register */
-
-    /* run loader */
-    stlink_run(sl);
-
-#define WAIT_ROUNDS 10000
-    /* wait until done (reaches breakpoint) */
-    for (i = 0; i < WAIT_ROUNDS; i++) {
-        usleep(10);
-        if (is_core_halted(sl))
-            break;
-    }
-
-    if (i >= WAIT_ROUNDS) {
-        ELOG("flash loader run error\n");
-        return -1;
-    }
-
-    /* check written byte count */
-    stlink_read_reg(sl, 2, &rr);
-    if (rr.r[2] != 0) {
-        fprintf(stderr, "write error, count == %u\n", rr.r[2]);
-        return -1;
-    }
-
-    return 0;
-}
diff --git a/src/flash_loader.c b/src/flash_loader.c
new file mode 100644 (file)
index 0000000..bf4c92f
--- /dev/null
@@ -0,0 +1,313 @@
+#include "stlink.h"
+
+/* from openocd, contrib/loaders/flash/stm32.s */
+static const uint8_t loader_code_stm32vl[] = {
+        0x08, 0x4c, /* ldr     r4, STM32_FLASH_BASE */
+        0x1c, 0x44, /* add     r4, r3 */
+        /* write_half_word: */
+        0x01, 0x23, /* movs    r3, #0x01 */
+        0x23, 0x61, /* str     r3, [r4, #STM32_FLASH_CR_OFFSET] */
+        0x30, 0xf8, 0x02, 0x3b, /* ldrh        r3, [r0], #0x02 */
+        0x21, 0xf8, 0x02, 0x3b, /* strh        r3, [r1], #0x02 */
+        /* busy: */
+        0xe3, 0x68, /* ldr     r3, [r4, #STM32_FLASH_SR_OFFSET] */
+        0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */
+        0xfb, 0xd0, /* beq     busy */
+        0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */
+        0x01, 0xd1, /* bne     exit */
+        0x01, 0x3a, /* subs    r2, r2, #0x01 */
+        0xf0, 0xd1, /* bne     write_half_word */
+        /* exit: */
+        0x00, 0xbe, /* bkpt    #0x00 */
+        0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
+    };
+
+    /* flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored */
+    static const uint8_t loader_code_stm32f0[] = {
+#if 1
+        /*
+         * These two NOPs here are a safety precaution, added by Pekka Nikander
+         * while debugging the STM32F05x support.  They may not be needed, but
+         * there were strange problems with simpler programs, like a program
+         * that had just a breakpoint or a program that first moved zero to register r2
+         * and then had a breakpoint.  So, it appears safest to have these two nops.
+         *
+         * Feel free to remove them, if you dare, but then please do test the result
+         * rigorously.  Also, if you remove these, it may be a good idea first to
+         * #if 0 them out, with a comment when these were taken out, and to remove
+         * these only a few months later...  But YMMV.
+         */
+        0x00, 0x30, //     nop     /* add r0,#0 */
+        0x00, 0x30, //     nop     /* add r0,#0 */
+#endif
+        0x0A, 0x4C, //     ldr     r4, STM32_FLASH_BASE
+        0x01, 0x25, //     mov     r5, #1            /*  FLASH_CR_PG, FLASH_SR_BUSY */
+        0x04, 0x26, //     mov     r6, #4            /*  PGERR  */
+        // write_half_word:
+        0x23, 0x69, //     ldr     r3, [r4, #16]     /*  FLASH->CR   */
+        0x2B, 0x43, //     orr     r3, r5
+        0x23, 0x61, //     str     r3, [r4, #16]     /*  FLASH->CR |= FLASH_CR_PG */
+        0x03, 0x88, //     ldrh    r3, [r0]          /*  r3 = *sram */
+        0x0B, 0x80, //     strh    r3, [r1]          /*  *flash = r3 */
+        // busy:
+        0xE3, 0x68, //     ldr    r3, [r4, #12]     /*  FLASH->SR  */
+        0x2B, 0x42, //     tst    r3, r5            /*  FLASH_SR_BUSY  */
+        0xFC, 0xD0, //     beq    busy
+
+        0x33, 0x42, //     tst    r3, r6            /*  PGERR  */
+        0x04, 0xD1, //     bne    exit
+
+        0x02, 0x30, //     add     r0, r0, #2        /*  sram += 2  */
+        0x02, 0x31, //     add     r1, r1, #2        /*  flash += 2  */
+        0x01, 0x3A, //     sub     r2, r2, #0x01     /*  count--  */
+        0x00, 0x2A, //     cmp     r2, #0
+        0xF0, 0xD1, //     bne    write_half_word
+        // exit:
+        0x23, 0x69, //     ldr     r3, [r4, #16]     /*  FLASH->CR  */
+        0xAB, 0x43, //     bic     r3, r5
+        0x23, 0x61, //     str     r3, [r4, #16]     /*  FLASH->CR &= ~FLASH_CR_PG  */
+        0x00, 0xBE, //     bkpt        #0x00
+        0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
+    };
+
+    static const uint8_t loader_code_stm32l[] = {
+        // flashloaders/stm32lx.s
+
+        0x04, 0xe0, //     b test_done          ; Go to compare
+        // write_word:
+        0x04, 0x68, //     ldr      r4, [r0]    ; Load one word from address in r0
+        0x0c, 0x60, //     str      r4, [r1]    ; Store the word to address in r1
+        0x04, 0x30, //     adds     r0, #4      ; Increment r0
+        0x04, 0x31, //     adds     r1, #4      ; Increment r1
+        0x01, 0x3a, //     subs     r2, #1      ; Decrement r2
+        // test_done:
+        0x00, 0x2a, //     cmp      r2, #0      ; Compare r2 to 0
+        0xf8, 0xd8, //     bhi      write_word  ; Loop if above 0
+        0x00, 0xbe, //     bkpt     #0x00       ; Set breakpoint to exit
+        0x00, 0x00
+    };
+
+    static const uint8_t loader_code_stm32f4[] = {
+        // flashloaders/stm32f4.s
+
+        0x07, 0x4b,
+
+        0x62, 0xb1,
+        0x04, 0x68,
+        0x0c, 0x60,
+
+        0xdc, 0x89,
+        0x14, 0xf0, 0x01, 0x0f,
+        0xfb, 0xd1,
+        0x00, 0xf1, 0x04, 0x00,
+        0x01, 0xf1, 0x04, 0x01,
+        0xa2, 0xf1, 0x01, 0x02,
+        0xf1, 0xe7,
+
+        0x00, 0xbe,
+
+        0x00, 0x3c, 0x02, 0x40,
+    };
+
+    static const uint8_t loader_code_stm32f4_lv[] = {
+        // flashloaders/stm32f4lv.s
+        0x92, 0x00,
+
+        0x08, 0x4b,
+        0x62, 0xb1,
+        0x04, 0x78,
+        0x0c, 0x70,
+
+        0xdc, 0x89,
+        0x14, 0xf0, 0x01, 0x0f,
+        0xfb, 0xd1,
+        0x00, 0xf1, 0x01, 0x00,
+        0x01, 0xf1, 0x01, 0x01,
+        0xa2, 0xf1, 0x01, 0x02,
+        0xf1, 0xe7,
+
+        0x00, 0xbe,
+        0x00, 0xbf,
+
+        0x00, 0x3c, 0x02, 0x40,
+    };
+
+    static const uint8_t loader_code_stm32l4[] = {
+        // flashloaders/stm32l4.s
+        0x08, 0x4b,             // start: ldr   r3, [pc, #32] ; <flash_base>
+        0x72, 0xb1,             // next:  cbz   r2, <done>
+        0x04, 0x68,             //        ldr   r4, [r0, #0]
+        0x45, 0x68,             //        ldr   r5, [r0, #4]
+        0x0c, 0x60,             //        str   r4, [r1, #0]
+        0x4d, 0x60,             //        str   r5, [r1, #4]
+        0x5c, 0x8a,             // wait:  ldrh  r4, [r3, #18]
+        0x14, 0xf0, 0x01, 0x0f, //        tst.w r4, #1
+        0xfb, 0xd1,             //        bne.n <wait>
+        0x00, 0xf1, 0x08, 0x00, //        add.w r0, r0, #8
+        0x01, 0xf1, 0x08, 0x01, //        add.w r1, r1, #8
+        0xa2, 0xf1, 0x01, 0x02, //        sub.w r2, r2, #1
+        0xef, 0xe7,             //        b.n   <next>
+        0x00, 0xbe,             // done:  bkpt  0x0000
+        0x00, 0x20, 0x02, 0x40  // flash_base:  .word 0x40022000
+    };
+
+       static const uint8_t loader_code_stm32f7[] = {
+        0x08, 0x4b,
+        0x72, 0xb1,
+        0x04, 0x68,
+        0x0c, 0x60,
+        0xbf, 0xf3, 0x4f, 0x8f,        // DSB Memory barrier for in order flash write
+        0xdc, 0x89,
+        0x14, 0xf0, 0x01, 0x0f,
+        0xfb, 0xd1,
+        0x00, 0xf1, 0x04, 0x00,
+        0x01, 0xf1, 0x04, 0x01,
+        0xa2, 0xf1, 0x01, 0x02,
+        0xef, 0xe7,
+        0x00, 0xbe,                   //     bkpt      #0x00
+        0x00, 0x3c, 0x02, 0x40,
+    };
+
+
+
+int stlink_flash_loader_init(stlink_t *sl, flash_loader_t *fl)
+{
+       size_t size;
+
+       /* allocate the loader in sram */
+       if (stlink_flash_loader_write_to_sram(sl, &fl->loader_addr, &size) == -1) {
+               WLOG("Failed to write flash loader to sram!\n");
+               return -1;
+       }
+
+       /* allocate a one page buffer in sram right after loader */
+       fl->buf_addr = fl->loader_addr + size;
+       ILOG("Successfully loaded flash loader in sram\n");
+
+       return 0;
+}
+
+int stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size)
+{
+    const uint8_t* loader_code;
+    size_t loader_size;
+
+    if (sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM || sl->chip_id == STLINK_CHIPID_STM32_L1_CAT2
+            || sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM_PLUS || sl->chip_id == STLINK_CHIPID_STM32_L1_HIGH
+            || sl->chip_id == STLINK_CHIPID_STM32_L152_RE
+            || sl->chip_id == STLINK_CHIPID_STM32_L0 || sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 || sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2) { /* stm32l */
+        loader_code = loader_code_stm32l;
+        loader_size = sizeof(loader_code_stm32l);
+    } else if (sl->core_id == STM32VL_CORE_ID 
+            || sl->chip_id == STLINK_CHIPID_STM32_F3
+            || sl->chip_id == STLINK_CHIPID_STM32_F3_SMALL
+            || sl->chip_id == STLINK_CHIPID_STM32_F303_HIGH
+            || sl->chip_id == STLINK_CHIPID_STM32_F37x
+            || sl->chip_id == STLINK_CHIPID_STM32_F334) {
+        loader_code = loader_code_stm32vl;
+        loader_size = sizeof(loader_code_stm32vl);
+    } else if (sl->chip_id == STLINK_CHIPID_STM32_F2      ||
+               sl->chip_id == STLINK_CHIPID_STM32_F4     ||
+               sl->chip_id == STLINK_CHIPID_STM32_F4_DE  ||
+               sl->chip_id == STLINK_CHIPID_STM32_F4_LP  ||
+               sl->chip_id == STLINK_CHIPID_STM32_F4_HD  ||
+               sl->chip_id == STLINK_CHIPID_STM32_F4_DSI ||
+               sl->chip_id == STLINK_CHIPID_STM32_F410   ||
+               sl->chip_id == STLINK_CHIPID_STM32_F411RE ||
+               sl->chip_id == STLINK_CHIPID_STM32_F446
+               ) {
+        int voltage = stlink_target_voltage(sl);
+        if (voltage == -1) {
+            printf("Failed to read Target voltage\n");
+            return voltage;
+        } else if (voltage > 2700) {
+            loader_code = loader_code_stm32f4;
+            loader_size = sizeof(loader_code_stm32f4);
+        } else {
+            loader_code = loader_code_stm32f4_lv;
+            loader_size = sizeof(loader_code_stm32f4_lv);
+        }
+    } else if (sl->chip_id == STLINK_CHIPID_STM32_F7){
+        loader_code = loader_code_stm32f7;
+        loader_size = sizeof(loader_code_stm32f7);
+    } else if (sl->chip_id == STLINK_CHIPID_STM32_F0 || sl->chip_id == STLINK_CHIPID_STM32_F04 || sl->chip_id == STLINK_CHIPID_STM32_F0_CAN || sl->chip_id == STLINK_CHIPID_STM32_F0_SMALL || sl->chip_id == STLINK_CHIPID_STM32_F09X) {
+        loader_code = loader_code_stm32f0;
+        loader_size = sizeof(loader_code_stm32f0);
+    } else if (sl->chip_id == STLINK_CHIPID_STM32_L4) {
+        loader_code = loader_code_stm32l4;
+        loader_size = sizeof(loader_code_stm32l4);
+    } else {
+        ELOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id);
+        return -1;
+    }
+
+    memcpy(sl->q_buf, loader_code, loader_size);
+    stlink_write_mem32(sl, sl->sram_base, loader_size);
+
+    *addr = sl->sram_base;
+    *size = loader_size;
+
+    /* success */
+    return 0;
+}
+
+int stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size)
+{
+    reg rr;
+    int i = 0;
+    size_t count = 0;
+
+    DLOG("Running flash loader, write address:%#x, size: %zd\n", target, size);
+    // FIXME This can never return -1
+    if (write_buffer_to_sram(sl, fl, buf, size) == -1) {
+        // IMPOSSIBLE!
+        ELOG("write_buffer_to_sram() == -1\n");
+        return -1;
+    }
+
+    if (sl->flash_type == FLASH_TYPE_F0) {
+        count = size / sizeof(uint16_t);
+        if (size % sizeof(uint16_t))
+            ++count;
+    } else if (sl->flash_type == FLASH_TYPE_F4 || sl->flash_type == FLASH_TYPE_L0) {
+        count = size / sizeof(uint32_t);
+        if (size % sizeof(uint32_t))
+            ++count;
+    } else if (sl->flash_type == FLASH_TYPE_L4) {
+        count = size / sizeof(uint64_t);
+        if (size % sizeof(uint64_t))
+            ++count;
+    }
+
+    /* setup core */
+    stlink_write_reg(sl, fl->buf_addr, 0); /* source */
+    stlink_write_reg(sl, target, 1); /* target */
+    stlink_write_reg(sl, count, 2); /* count */
+    stlink_write_reg(sl, 0, 3); /* flash bank 0 (input), only used on F0, but armless fopr others */
+    stlink_write_reg(sl, fl->loader_addr, 15); /* pc register */
+
+    /* run loader */
+    stlink_run(sl);
+
+#define WAIT_ROUNDS 10000
+    /* wait until done (reaches breakpoint) */
+    for (i = 0; i < WAIT_ROUNDS; i++) {
+        usleep(10);
+        if (is_core_halted(sl))
+            break;
+    }
+
+    if (i >= WAIT_ROUNDS) {
+        ELOG("flash loader run error\n");
+        return -1;
+    }
+
+    /* check written byte count */
+    stlink_read_reg(sl, 2, &rr);
+    if (rr.r[2] != 0) {
+        ELOG("write error, count == %u\n", rr.r[2]);
+        return -1;
+    }
+
+    return 0;
+}