bf4c92f1462442dbbaea3f43cea02c25b6d46aba
[fw/stlink] / src / flash_loader.c
1 #include "stlink.h"
2
3 /* from openocd, contrib/loaders/flash/stm32.s */
4 static const uint8_t loader_code_stm32vl[] = {
5         0x08, 0x4c, /* ldr      r4, STM32_FLASH_BASE */
6         0x1c, 0x44, /* add      r4, r3 */
7         /* write_half_word: */
8         0x01, 0x23, /* movs     r3, #0x01 */
9         0x23, 0x61, /* str      r3, [r4, #STM32_FLASH_CR_OFFSET] */
10         0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */
11         0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */
12         /* busy: */
13         0xe3, 0x68, /* ldr      r3, [r4, #STM32_FLASH_SR_OFFSET] */
14         0x13, 0xf0, 0x01, 0x0f, /* tst  r3, #0x01 */
15         0xfb, 0xd0, /* beq      busy */
16         0x13, 0xf0, 0x14, 0x0f, /* tst  r3, #0x14 */
17         0x01, 0xd1, /* bne      exit */
18         0x01, 0x3a, /* subs     r2, r2, #0x01 */
19         0xf0, 0xd1, /* bne      write_half_word */
20         /* exit: */
21         0x00, 0xbe, /* bkpt     #0x00 */
22         0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
23     };
24
25     /* flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored */
26     static const uint8_t loader_code_stm32f0[] = {
27 #if 1
28         /*
29          * These two NOPs here are a safety precaution, added by Pekka Nikander
30          * while debugging the STM32F05x support.  They may not be needed, but
31          * there were strange problems with simpler programs, like a program
32          * that had just a breakpoint or a program that first moved zero to register r2
33          * and then had a breakpoint.  So, it appears safest to have these two nops.
34          *
35          * Feel free to remove them, if you dare, but then please do test the result
36          * rigorously.  Also, if you remove these, it may be a good idea first to
37          * #if 0 them out, with a comment when these were taken out, and to remove
38          * these only a few months later...  But YMMV.
39          */
40         0x00, 0x30, //     nop     /* add r0,#0 */
41         0x00, 0x30, //     nop     /* add r0,#0 */
42 #endif
43         0x0A, 0x4C, //     ldr     r4, STM32_FLASH_BASE
44         0x01, 0x25, //     mov     r5, #1            /*  FLASH_CR_PG, FLASH_SR_BUSY */
45         0x04, 0x26, //     mov     r6, #4            /*  PGERR  */
46         // write_half_word:
47         0x23, 0x69, //     ldr     r3, [r4, #16]     /*  FLASH->CR   */
48         0x2B, 0x43, //     orr     r3, r5
49         0x23, 0x61, //     str     r3, [r4, #16]     /*  FLASH->CR |= FLASH_CR_PG */
50         0x03, 0x88, //     ldrh    r3, [r0]          /*  r3 = *sram */
51         0x0B, 0x80, //     strh    r3, [r1]          /*  *flash = r3 */
52         // busy:
53         0xE3, 0x68, //     ldr     r3, [r4, #12]     /*  FLASH->SR  */
54         0x2B, 0x42, //     tst     r3, r5            /*  FLASH_SR_BUSY  */
55         0xFC, 0xD0, //     beq     busy
56
57         0x33, 0x42, //     tst     r3, r6            /*  PGERR  */
58         0x04, 0xD1, //     bne     exit
59
60         0x02, 0x30, //     add     r0, r0, #2        /*  sram += 2  */
61         0x02, 0x31, //     add     r1, r1, #2        /*  flash += 2  */
62         0x01, 0x3A, //     sub     r2, r2, #0x01     /*  count--  */
63         0x00, 0x2A, //     cmp     r2, #0
64         0xF0, 0xD1, //     bne     write_half_word
65         // exit:
66         0x23, 0x69, //     ldr     r3, [r4, #16]     /*  FLASH->CR  */
67         0xAB, 0x43, //     bic     r3, r5
68         0x23, 0x61, //     str     r3, [r4, #16]     /*  FLASH->CR &= ~FLASH_CR_PG  */
69         0x00, 0xBE, //     bkpt #0x00
70         0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
71     };
72
73     static const uint8_t loader_code_stm32l[] = {
74         // flashloaders/stm32lx.s
75
76         0x04, 0xe0, //     b test_done          ; Go to compare
77         // write_word:
78         0x04, 0x68, //     ldr      r4, [r0]    ; Load one word from address in r0
79         0x0c, 0x60, //     str      r4, [r1]    ; Store the word to address in r1
80         0x04, 0x30, //     adds     r0, #4      ; Increment r0
81         0x04, 0x31, //     adds     r1, #4      ; Increment r1
82         0x01, 0x3a, //     subs     r2, #1      ; Decrement r2
83         // test_done:
84         0x00, 0x2a, //     cmp      r2, #0      ; Compare r2 to 0
85         0xf8, 0xd8, //     bhi      write_word  ; Loop if above 0
86         0x00, 0xbe, //     bkpt     #0x00       ; Set breakpoint to exit
87         0x00, 0x00
88     };
89
90     static const uint8_t loader_code_stm32f4[] = {
91         // flashloaders/stm32f4.s
92
93         0x07, 0x4b,
94
95         0x62, 0xb1,
96         0x04, 0x68,
97         0x0c, 0x60,
98
99         0xdc, 0x89,
100         0x14, 0xf0, 0x01, 0x0f,
101         0xfb, 0xd1,
102         0x00, 0xf1, 0x04, 0x00,
103         0x01, 0xf1, 0x04, 0x01,
104         0xa2, 0xf1, 0x01, 0x02,
105         0xf1, 0xe7,
106
107         0x00, 0xbe,
108
109         0x00, 0x3c, 0x02, 0x40,
110     };
111
112     static const uint8_t loader_code_stm32f4_lv[] = {
113         // flashloaders/stm32f4lv.s
114         0x92, 0x00,
115
116         0x08, 0x4b,
117         0x62, 0xb1,
118         0x04, 0x78,
119         0x0c, 0x70,
120
121         0xdc, 0x89,
122         0x14, 0xf0, 0x01, 0x0f,
123         0xfb, 0xd1,
124         0x00, 0xf1, 0x01, 0x00,
125         0x01, 0xf1, 0x01, 0x01,
126         0xa2, 0xf1, 0x01, 0x02,
127         0xf1, 0xe7,
128
129         0x00, 0xbe,
130         0x00, 0xbf,
131
132         0x00, 0x3c, 0x02, 0x40,
133     };
134
135     static const uint8_t loader_code_stm32l4[] = {
136         // flashloaders/stm32l4.s
137         0x08, 0x4b,             // start: ldr   r3, [pc, #32] ; <flash_base>
138         0x72, 0xb1,             // next:  cbz   r2, <done>
139         0x04, 0x68,             //        ldr   r4, [r0, #0]
140         0x45, 0x68,             //        ldr   r5, [r0, #4]
141         0x0c, 0x60,             //        str   r4, [r1, #0]
142         0x4d, 0x60,             //        str   r5, [r1, #4]
143         0x5c, 0x8a,             // wait:  ldrh  r4, [r3, #18]
144         0x14, 0xf0, 0x01, 0x0f, //        tst.w r4, #1
145         0xfb, 0xd1,             //        bne.n <wait>
146         0x00, 0xf1, 0x08, 0x00, //        add.w r0, r0, #8
147         0x01, 0xf1, 0x08, 0x01, //        add.w r1, r1, #8
148         0xa2, 0xf1, 0x01, 0x02, //        sub.w r2, r2, #1
149         0xef, 0xe7,             //        b.n   <next>
150         0x00, 0xbe,             // done:  bkpt  0x0000
151         0x00, 0x20, 0x02, 0x40  // flash_base:  .word 0x40022000
152     };
153
154         static const uint8_t loader_code_stm32f7[] = {
155         0x08, 0x4b,
156         0x72, 0xb1,
157         0x04, 0x68,
158         0x0c, 0x60,
159         0xbf, 0xf3, 0x4f, 0x8f,        // DSB Memory barrier for in order flash write
160         0xdc, 0x89,
161         0x14, 0xf0, 0x01, 0x0f,
162         0xfb, 0xd1,
163         0x00, 0xf1, 0x04, 0x00,
164         0x01, 0xf1, 0x04, 0x01,
165         0xa2, 0xf1, 0x01, 0x02,
166         0xef, 0xe7,
167         0x00, 0xbe,                   //     bkpt       #0x00
168         0x00, 0x3c, 0x02, 0x40,
169     };
170
171
172
173 int stlink_flash_loader_init(stlink_t *sl, flash_loader_t *fl)
174 {
175         size_t size;
176
177         /* allocate the loader in sram */
178         if (stlink_flash_loader_write_to_sram(sl, &fl->loader_addr, &size) == -1) {
179                 WLOG("Failed to write flash loader to sram!\n");
180                 return -1;
181         }
182
183         /* allocate a one page buffer in sram right after loader */
184         fl->buf_addr = fl->loader_addr + size;
185         ILOG("Successfully loaded flash loader in sram\n");
186
187         return 0;
188 }
189
190 int stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size)
191 {
192     const uint8_t* loader_code;
193     size_t loader_size;
194
195     if (sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM || sl->chip_id == STLINK_CHIPID_STM32_L1_CAT2
196             || sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM_PLUS || sl->chip_id == STLINK_CHIPID_STM32_L1_HIGH
197             || sl->chip_id == STLINK_CHIPID_STM32_L152_RE
198             || sl->chip_id == STLINK_CHIPID_STM32_L0 || sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 || sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2) { /* stm32l */
199         loader_code = loader_code_stm32l;
200         loader_size = sizeof(loader_code_stm32l);
201     } else if (sl->core_id == STM32VL_CORE_ID 
202             || sl->chip_id == STLINK_CHIPID_STM32_F3
203             || sl->chip_id == STLINK_CHIPID_STM32_F3_SMALL
204             || sl->chip_id == STLINK_CHIPID_STM32_F303_HIGH
205             || sl->chip_id == STLINK_CHIPID_STM32_F37x
206             || sl->chip_id == STLINK_CHIPID_STM32_F334) {
207         loader_code = loader_code_stm32vl;
208         loader_size = sizeof(loader_code_stm32vl);
209     } else if (sl->chip_id == STLINK_CHIPID_STM32_F2      ||
210                 sl->chip_id == STLINK_CHIPID_STM32_F4     ||
211                 sl->chip_id == STLINK_CHIPID_STM32_F4_DE  ||
212                 sl->chip_id == STLINK_CHIPID_STM32_F4_LP  ||
213                 sl->chip_id == STLINK_CHIPID_STM32_F4_HD  ||
214                 sl->chip_id == STLINK_CHIPID_STM32_F4_DSI ||
215                 sl->chip_id == STLINK_CHIPID_STM32_F410   ||
216                 sl->chip_id == STLINK_CHIPID_STM32_F411RE ||
217                 sl->chip_id == STLINK_CHIPID_STM32_F446
218                 ) {
219         int voltage = stlink_target_voltage(sl);
220         if (voltage == -1) {
221             printf("Failed to read Target voltage\n");
222             return voltage;
223         } else if (voltage > 2700) {
224             loader_code = loader_code_stm32f4;
225             loader_size = sizeof(loader_code_stm32f4);
226         } else {
227             loader_code = loader_code_stm32f4_lv;
228             loader_size = sizeof(loader_code_stm32f4_lv);
229         }
230     } else if (sl->chip_id == STLINK_CHIPID_STM32_F7){
231         loader_code = loader_code_stm32f7;
232         loader_size = sizeof(loader_code_stm32f7);
233     } 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) {
234         loader_code = loader_code_stm32f0;
235         loader_size = sizeof(loader_code_stm32f0);
236     } else if (sl->chip_id == STLINK_CHIPID_STM32_L4) {
237         loader_code = loader_code_stm32l4;
238         loader_size = sizeof(loader_code_stm32l4);
239     } else {
240         ELOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id);
241         return -1;
242     }
243
244     memcpy(sl->q_buf, loader_code, loader_size);
245     stlink_write_mem32(sl, sl->sram_base, loader_size);
246
247     *addr = sl->sram_base;
248     *size = loader_size;
249
250     /* success */
251     return 0;
252 }
253
254 int stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size)
255 {
256     reg rr;
257     int i = 0;
258     size_t count = 0;
259
260     DLOG("Running flash loader, write address:%#x, size: %zd\n", target, size);
261     // FIXME This can never return -1
262     if (write_buffer_to_sram(sl, fl, buf, size) == -1) {
263         // IMPOSSIBLE!
264         ELOG("write_buffer_to_sram() == -1\n");
265         return -1;
266     }
267
268     if (sl->flash_type == FLASH_TYPE_F0) {
269         count = size / sizeof(uint16_t);
270         if (size % sizeof(uint16_t))
271             ++count;
272     } else if (sl->flash_type == FLASH_TYPE_F4 || sl->flash_type == FLASH_TYPE_L0) {
273         count = size / sizeof(uint32_t);
274         if (size % sizeof(uint32_t))
275             ++count;
276     } else if (sl->flash_type == FLASH_TYPE_L4) {
277         count = size / sizeof(uint64_t);
278         if (size % sizeof(uint64_t))
279             ++count;
280     }
281
282     /* setup core */
283     stlink_write_reg(sl, fl->buf_addr, 0); /* source */
284     stlink_write_reg(sl, target, 1); /* target */
285     stlink_write_reg(sl, count, 2); /* count */
286     stlink_write_reg(sl, 0, 3); /* flash bank 0 (input), only used on F0, but armless fopr others */
287     stlink_write_reg(sl, fl->loader_addr, 15); /* pc register */
288
289     /* run loader */
290     stlink_run(sl);
291
292 #define WAIT_ROUNDS 10000
293     /* wait until done (reaches breakpoint) */
294     for (i = 0; i < WAIT_ROUNDS; i++) {
295         usleep(10);
296         if (is_core_halted(sl))
297             break;
298     }
299
300     if (i >= WAIT_ROUNDS) {
301         ELOG("flash loader run error\n");
302         return -1;
303     }
304
305     /* check written byte count */
306     stlink_read_reg(sl, 2, &rr);
307     if (rr.r[2] != 0) {
308         ELOG("write error, count == %u\n", rr.r[2]);
309         return -1;
310     }
311
312     return 0;
313 }