include/stlink/logging.h
include/stlink/mmap.h
include/stlink/chipid.h
+ include/stlink/flash_loader.h
)
set(STLINK_SOURCE
src/usb.c
src/sg.c
src/logging.c
+ src/flash_loader.c
)
include_directories(${LIBUSB_INCLUDE_DIR})
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
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
#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
FLASH_TYPE_L4,
};
-#include "stlink/chipid.h"
-
typedef struct {
uint32_t r[16];
uint32_t s[32];
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;
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,
#include "stlink/sg.h"
#include "stlink/usb.h"
+#include "stlink/commands.h"
+#include "stlink/chipid.h"
+#include "stlink/flash_loader.h"
#ifdef __cplusplus
}
--- /dev/null
+#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_ */
--- /dev/null
+/*
+ * 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_ */
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 */
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 */
} 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);
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;
}
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;
}
} 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;
}
/* 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);
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;
-}
--- /dev/null
+#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;
+}