From 48a8ac59e1ba7f98fe5c247f608be3cb3998e9c4 Mon Sep 17 00:00:00 2001 From: Jerry Jacobs Date: Fri, 20 May 2016 20:03:57 +0200 Subject: [PATCH] Move STLINK_DEBUG_* defines into enum, move flash_loader code into seperate header and c file --- CMakeLists.txt | 2 + Makefile.am | 5 +- include/stlink.h | 36 +--- include/stlink/commands.h | 26 +++ include/stlink/flash_loader.h | 27 +++ src/common.c | 333 ++-------------------------------- src/flash_loader.c | 313 ++++++++++++++++++++++++++++++++ 7 files changed, 393 insertions(+), 349 deletions(-) create mode 100644 include/stlink/commands.h create mode 100644 include/stlink/flash_loader.h create mode 100644 src/flash_loader.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 89bd859..dab4829 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) diff --git a/Makefile.am b/Makefile.am index a3114c6..79ce10c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/include/stlink.h b/include/stlink.h index 3941f42..a20f815 100644 --- a/include/stlink.h +++ b/include/stlink.h @@ -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 index 0000000..9ff5a8f --- /dev/null +++ b/include/stlink/commands.h @@ -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 index 0000000..95042f7 --- /dev/null +++ b/include/stlink/flash_loader.h @@ -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 +#include + +#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_ */ diff --git a/src/common.c b/src/common.c index 729c739..7270481 100644 --- a/src/common.c +++ b/src/common.c @@ -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] ; - 0x72, 0xb1, // next: cbz r2, - 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 - 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 - 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 index 0000000..bf4c92f --- /dev/null +++ b/src/flash_loader.c @@ -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] ; + 0x72, 0xb1, // next: cbz r2, + 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 + 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 + 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; +} -- 2.47.2