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