ao-tools/ao-stmload: application base moved to 0x08001000
[fw/altos] / ao-tools / ao-stmload / ao-stmload.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <err.h>
19 #include <fcntl.h>
20 #include <gelf.h>
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <sysexits.h>
25 #include <unistd.h>
26 #include <getopt.h>
27 #include <string.h>
28 #include "stlink-common.h"
29 #include "ao-elf.h"
30 #include "ccdbg.h"
31 #include "cc-usb.h"
32 #include "cc.h"
33 #include "ao-stmload.h"
34
35 #define AO_USB_DESC_STRING              3
36
37 struct sym ao_symbols[] = {
38
39         { 0, AO_BOOT_APPLICATION_BASE + 0x100,  "ao_romconfig_version", 1 },
40 #define AO_ROMCONFIG_VERSION    (ao_symbols[0].addr)
41
42         { 0, AO_BOOT_APPLICATION_BASE + 0x102,  "ao_romconfig_check",   1 },
43 #define AO_ROMCONFIG_CHECK      (ao_symbols[1].addr)
44
45         { 0, AO_BOOT_APPLICATION_BASE + 0x104,  "ao_serial_number", 1 },
46 #define AO_SERIAL_NUMBER        (ao_symbols[2].addr)
47
48         { 0, AO_BOOT_APPLICATION_BASE + 0x108,  "ao_radio_cal", 0 },
49 #define AO_RADIO_CAL            (ao_symbols[3].addr)
50
51         { 0, AO_BOOT_APPLICATION_BASE + 0x10c,  "ao_usb_descriptors", 0 },
52 #define AO_USB_DESCRIPTORS      (ao_symbols[4].addr)
53 };
54
55 #define NUM_SYMBOLS             5
56 #define NUM_REQUIRED_SYMBOLS    3
57
58 int ao_num_symbols = NUM_SYMBOLS;
59 int ao_num_required_symbols = NUM_REQUIRED_SYMBOLS;
60
61 /*
62  * Edit the to-be-written memory block
63  */
64 static int
65 rewrite(struct hex_image *load, unsigned address, uint8_t *data, int length)
66 {
67         int             i;
68
69         if (address < load->address || load->address + load->length < address + length)
70                 return 0;
71
72         printf("rewrite %04x:", address);
73         for (i = 0; i < length; i++)
74                 printf (" %02x", load->data[address - load->address + i]);
75         printf(" ->");
76         for (i = 0; i < length; i++)
77                 printf (" %02x", data[i]);
78         printf("\n");
79         memcpy(load->data + address - load->address, data, length);
80 }
81
82 /*
83  * Read a 16-bit value from the USB target
84  */
85
86 static uint16_t
87 get_uint16_cc(struct cc_usb *cc, uint32_t addr)
88 {
89         struct hex_image        *hex = ao_self_read(cc, addr, 2);
90         uint16_t                v;
91         uint8_t                 *data;
92
93         if (!hex)
94                 return 0;
95         data = hex->data + addr - hex->address;
96         v = data[0] | (data[1] << 8);
97         free(hex);
98         return v;
99 }
100
101 static uint32_t
102 get_uint32_cc(struct cc_usb *cc, uint32_t addr)
103 {
104         struct hex_image        *hex = ao_self_read(cc, addr, 4);
105         uint32_t                v;
106         uint8_t                 *data;
107
108         if (!hex)
109                 return 0;
110         data = hex->data + addr - hex->address;
111         v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
112         free(hex);
113         return v;
114 }
115
116 /*
117  * Read a 16-bit value from the target device with arbitrary
118  * alignment
119  */
120 static uint16_t
121 get_uint16_sl(stlink_t *sl, uint32_t addr)
122 {
123         const           uint8_t *data = sl->q_buf;
124         uint32_t        actual_addr;
125         int             off;
126         uint16_t        result;
127
128         sl->q_len = 0;
129
130
131         actual_addr = addr & ~3;
132         
133         stlink_read_mem32(sl, actual_addr, 8);
134
135         if (sl->q_len != 8)
136                 abort();
137
138         off = addr & 3;
139         result = data[off] | (data[off + 1] << 8);
140         return result;
141 }
142
143 static uint16_t
144 get_uint16(stlink_t *sl, struct cc_usb *cc, uint32_t addr)
145 {
146         uint16_t        result;
147         if (cc)
148                 result = get_uint16_cc(cc, addr);
149         else
150                 result = get_uint16_sl(sl, addr);
151         printf ("read 0x%08x = 0x%04x\n", addr, result);
152         return result;
153 }
154
155 /*
156  * Read a 32-bit value from the target device with arbitrary
157  * alignment
158  */
159 static uint32_t
160 get_uint32_sl(stlink_t *sl, uint32_t addr)
161 {
162         const           uint8_t *data = sl->q_buf;
163         uint32_t        actual_addr;
164         int             off;
165         uint32_t        result;
166
167         sl->q_len = 0;
168
169         printf ("read 0x%x\n", addr);
170
171         actual_addr = addr & ~3;
172         
173         stlink_read_mem32(sl, actual_addr, 8);
174
175         if (sl->q_len != 8)
176                 abort();
177
178         off = addr & 3;
179         result = data[off] | (data[off + 1] << 8) | (data[off+2] << 16) | (data[off+3] << 24);
180         return result;
181 }
182
183 /*
184  * Read a 32-bit value from the target device with arbitrary
185  * alignment
186  */
187 static uint32_t
188 get_uint32(stlink_t *sl, struct cc_usb *cc, uint32_t addr)
189 {
190         uint32_t        result;
191
192         if (cc)
193                 result = get_uint32_cc(cc, addr);
194         else
195                 result = get_uint32_sl(sl, addr);
196         printf ("read 0x%08x = 0x%08x\n", addr, result);
197         return result;
198 }
199
200 /*
201  * Check to see if the target device has been
202  * flashed with a similar firmware image before
203  *
204  * This is done by looking for the same romconfig version,
205  * which should be at the same location as the linker script
206  * places this at 0x100 from the start of the rom section
207  */
208 static int
209 check_flashed(stlink_t *sl, struct cc_usb *cc)
210 {
211         uint16_t        romconfig_version = get_uint16(sl, cc, AO_ROMCONFIG_VERSION);
212         uint16_t        romconfig_check = get_uint16(sl, cc, AO_ROMCONFIG_CHECK);
213
214         if (romconfig_version != (uint16_t) ~romconfig_check) {
215                 fprintf (stderr, "Device has not been flashed before\n");
216                 return 0;
217         }
218         return 1;
219 }
220
221 static const struct option options[] = {
222         { .name = "stlink", .has_arg = 0, .val = 'S' },
223         { .name = "tty", .has_arg = 1, .val = 'T' },
224         { .name = "device", .has_arg = 1, .val = 'D' },
225         { .name = "cal", .has_arg = 1, .val = 'c' },
226         { .name = "serial", .has_arg = 1, .val = 's' },
227         { 0, 0, 0, 0},
228 };
229
230 static void usage(char *program)
231 {
232         fprintf(stderr, "usage: %s [--stlink] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
233         exit(1);
234 }
235
236 void
237 done(stlink_t *sl, struct cc_usb *cc, int code)
238 {
239         if (cc) {
240 /*              cc_usb_printf(cc, "a\n"); */
241                 cc_usb_close(cc);
242         }
243         if (sl) {
244                 stlink_reset(sl);
245                 stlink_run(sl);
246                 stlink_exit_debug_mode(sl);
247                 stlink_close(sl);
248         }
249         exit (code);
250 }
251
252 static int
253 ends_with(char *whole, char *suffix)
254 {
255         int whole_len = strlen(whole);
256         int suffix_len = strlen(suffix);
257
258         if (suffix_len > whole_len)
259                 return 0;
260         return strcmp(whole + whole_len - suffix_len, suffix) == 0;
261 }
262
263 int
264 main (int argc, char **argv)
265 {
266         char                    *device = NULL;
267         char                    *filename;
268         Elf                     *e;
269         char                    *serial_end;
270         unsigned int            serial = 0;
271         char                    *serial_ucs2;
272         int                     serial_ucs2_len;
273         char                    serial_int[2];
274         unsigned int            s;
275         int                     i;
276         int                     string_num;
277         uint32_t                cal = 0;
278         char                    cal_int[4];
279         char                    *cal_end;
280         int                     c;
281         stlink_t                *sl = NULL;
282         int                     was_flashed = 0;
283         struct hex_image        *load;
284         int                     tries;
285         struct cc_usb           *cc = NULL;
286         int                     use_stlink = 0;
287         char                    *tty = NULL;
288         int                     success;
289
290         while ((c = getopt_long(argc, argv, "T:D:c:s:S", options, NULL)) != -1) {
291                 switch (c) {
292                 case 'T':
293                         tty = optarg;
294                         break;
295                 case 'D':
296                         device = optarg;
297                         break;
298                 case 'c':
299                         cal = strtoul(optarg, &cal_end, 10);
300                         if (cal_end == optarg || *cal_end != '\0')
301                                 usage(argv[0]);
302                         break;
303                 case 's':
304                         serial = strtoul(optarg, &serial_end, 10);
305                         if (serial_end == optarg || *serial_end != '\0')
306                                 usage(argv[0]);
307                         break;
308                 case 'S':
309                         use_stlink = 1;
310                         break;
311                 default:
312                         usage(argv[0]);
313                         break;
314                 }
315         }
316
317         filename = argv[optind];
318         if (filename == NULL)
319                 usage(argv[0]);
320
321         if (ends_with (filename, ".elf")) {
322                 load = ao_load_elf(filename);
323         } else if (ends_with (filename, ".ihx")) {
324                 int     i;
325                 load = ccdbg_hex_load(filename);
326                 for (i = 0; i < ao_num_symbols; i++)
327                         ao_symbols[i].addr = ao_symbols[i].default_addr;
328         } else
329                 usage(argv[0]);
330
331         if (use_stlink) {
332                 /* Connect to the programming dongle
333                  */
334         
335                 for (tries = 0; tries < 3; tries++) {
336                         if (device) {
337                                 sl = stlink_v1_open(50);
338                         } else {
339                                 sl = stlink_open_usb(50);
340                 
341                         }
342                         if (!sl) {
343                                 fprintf (stderr, "No STLink devices present\n");
344                                 done (sl, NULL, 1);
345                         }
346
347                         if (sl->chip_id != 0)
348                                 break;
349                         stlink_reset(sl);
350                         stlink_close(sl);
351                         sl = NULL;
352                 }
353                 if (!sl) {
354                         fprintf (stderr, "Debugger connection failed\n");
355                         exit(1);
356                 }
357
358                 /* Verify that the loaded image fits entirely within device flash
359                  */
360                 if (load->address < sl->flash_base ||
361                     sl->flash_base + sl->flash_size < load->address + load->length) {
362                         fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename,
363                                  load->address, load->address + load->length);
364                         done(sl, NULL, 1);
365                 }
366
367                 /* Enter debugging mode
368                  */
369                 if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
370                         stlink_exit_dfu_mode(sl);
371
372                 if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
373                         stlink_enter_swd_mode(sl);
374         } else {
375                 int     is_loader;
376                 int     tries;
377
378                 for (tries = 0; tries < 3; tries++) {
379                         char    *this_tty = tty;
380                         if (!this_tty)
381                                 this_tty = cc_usbdevs_find_by_arg(device, "AltosFlash");
382                         if (!this_tty)
383                                 this_tty = cc_usbdevs_find_by_arg(device, "MegaMetrum");
384                         if (!this_tty)
385                                 this_tty = getenv("ALTOS_TTY");
386                         if (!this_tty)
387                                 this_tty="/dev/ttyACM0";
388
389                         cc = cc_usb_open(this_tty);
390
391                         if (!cc)
392                                 exit(1);
393                         cc_usb_printf(cc, "v\n");
394                         is_loader = 0;
395                         for (;;) {
396                                 char    line[256];
397                                 cc_usb_getline(cc, line, sizeof(line));
398                                 if (!strncmp(line, "altos-loader", 12))
399                                         is_loader = 1;
400                                 if (!strncmp(line, "software-version", 16))
401                                         break;
402                         }
403                         if (is_loader)
404                                 break;
405                         printf ("rebooting to loader\n");
406                         cc_usb_printf(cc, "X\n");
407                         cc_usb_close(cc);
408                         sleep(1);
409                         cc = NULL;
410                 }
411                 if (!is_loader) {
412                         fprintf(stderr, "Cannot switch to boot loader\n");
413                         exit(1);
414                 }
415                 {
416                         uint8_t check[256];
417                         int     i = 0;
418
419                         ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, check);
420                         for (;;) {
421                                 uint8_t block[256];
422                                 putchar ('.');
423                                 if (++i == 40) {
424                                         putchar('\n');
425                                         i = 0;
426                                 }
427                                 fflush(stdout);
428                                 ao_self_block_write(cc, AO_BOOT_APPLICATION_BASE, block);
429                                 ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, block);
430                                 if (memcmp(block, check, 256) != 0) {
431                                         fprintf (stderr, "read differed\n");
432                                         exit(1);
433                                 }
434                         }
435                 }
436         }
437
438         /* Go fetch existing config values
439          * if available
440          */
441         was_flashed = check_flashed(sl, cc);
442
443         if (!serial) {
444                 if (!was_flashed) {
445                         fprintf (stderr, "Must provide serial number\n");
446                         done(sl, cc, 1);
447                 }
448                 serial = get_uint16(sl, cc, AO_SERIAL_NUMBER);
449                 if (!serial || serial == 0xffff) {
450                         fprintf (stderr, "Invalid existing serial %d\n", serial);
451                         done(sl, cc, 1);
452                 }
453         }
454
455         if (!cal && AO_RADIO_CAL && was_flashed) {
456                 cal = get_uint32(sl, cc, AO_RADIO_CAL);
457                 if (!cal || cal == 0xffffffff) {
458                         fprintf (stderr, "Invalid existing rf cal %d\n", cal);
459                         done(sl, cc, 1);
460                 }
461         }
462
463         /* Write the config values into the flash image
464          */
465
466         serial_int[0] = serial & 0xff;
467         serial_int[1] = (serial >> 8) & 0xff;
468
469         if (!rewrite(load, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {
470                 fprintf(stderr, "Cannot rewrite serial integer at %08x\n",
471                         AO_SERIAL_NUMBER);
472                 done(sl, cc, 1);
473         }
474
475         if (AO_USB_DESCRIPTORS) {
476                 uint32_t        usb_descriptors = AO_USB_DESCRIPTORS - load->address;
477                 string_num = 0;
478
479                 while (load->data[usb_descriptors] != 0 && usb_descriptors < load->length) {
480                         if (load->data[usb_descriptors+1] == AO_USB_DESC_STRING) {
481                                 ++string_num;
482                                 if (string_num == 4)
483                                         break;
484                         }
485                         usb_descriptors += load->data[usb_descriptors];
486                 }
487                 if (usb_descriptors >= load->length || load->data[usb_descriptors] == 0 ) {
488                         fprintf(stderr, "Cannot rewrite serial string at %08x\n", AO_USB_DESCRIPTORS);
489                         done(sl, cc, 1);
490                 }
491
492                 serial_ucs2_len = load->data[usb_descriptors] - 2;
493                 serial_ucs2 = malloc(serial_ucs2_len);
494                 if (!serial_ucs2) {
495                         fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len);
496                         done(sl, cc, 1);
497                 }
498                 s = serial;
499                 for (i = serial_ucs2_len / 2; i; i--) {
500                         serial_ucs2[i * 2 - 1] = 0;
501                         serial_ucs2[i * 2 - 2] = (s % 10) + '0';
502                         s /= 10;
503                 }
504                 if (!rewrite(load, usb_descriptors + 2 + load->address, serial_ucs2, serial_ucs2_len)) {
505                         fprintf (stderr, "Cannot rewrite USB descriptor at %08x\n", AO_USB_DESCRIPTORS);
506                         done(sl, cc, 1);
507                 }
508         }
509
510         if (cal && AO_RADIO_CAL) {
511                 cal_int[0] = cal & 0xff;
512                 cal_int[1] = (cal >> 8) & 0xff;
513                 cal_int[2] = (cal >> 16) & 0xff;
514                 cal_int[3] = (cal >> 24) & 0xff;
515
516                 if (!rewrite(load, AO_RADIO_CAL, cal_int, sizeof (cal_int))) {
517                         fprintf(stderr, "Cannot rewrite radio calibration at %08x\n", AO_RADIO_CAL);
518                         exit(1);
519                 }
520         }
521
522         /* And flash the resulting image to the device
523          */
524         if (cc)
525                 success = ao_self_write(cc, load);
526         else
527                 success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0);
528                 
529         if (!success) {
530                 fprintf (stderr, "\"%s\": Write failed\n", filename);
531                 done(sl, cc, 1);
532         }
533
534         done(sl, cc, 0);
535 }