ao-tools: Clean up ao-stmload and ao-usbload options. Add --raw
[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.h"
33 #include "ao-stmload.h"
34 #include "ao-selfload.h"
35 #include "ao-verbose.h"
36 #include "ao-editaltos.h"
37
38
39 /*
40  * Read a 16-bit value from the target device with arbitrary
41  * alignment
42  */
43 static uint16_t
44 get_uint16_sl(stlink_t *sl, uint32_t addr)
45 {
46         const           uint8_t *data = sl->q_buf;
47         uint32_t        actual_addr;
48         int             off;
49         uint16_t        result;
50
51         sl->q_len = 0;
52
53
54         actual_addr = addr & ~3;
55         
56         stlink_read_mem32(sl, actual_addr, 8);
57
58         if (sl->q_len != 8)
59                 abort();
60
61         off = addr & 3;
62         result = data[off] | (data[off + 1] << 8);
63         return result;
64 }
65
66 static uint16_t
67 get_uint16(stlink_t *sl, uint32_t addr)
68 {
69         uint16_t        result;
70         result = get_uint16_sl(sl, addr);
71         printf ("read 0x%08x = 0x%04x\n", addr, result);
72         return result;
73 }
74
75 /*
76  * Read a 32-bit value from the target device with arbitrary
77  * alignment
78  */
79 static uint32_t
80 get_uint32_sl(stlink_t *sl, uint32_t addr)
81 {
82         const           uint8_t *data = sl->q_buf;
83         uint32_t        actual_addr;
84         int             off;
85         uint32_t        result;
86
87         sl->q_len = 0;
88
89         printf ("read 0x%x\n", addr);
90
91         actual_addr = addr & ~3;
92         
93         stlink_read_mem32(sl, actual_addr, 8);
94
95         if (sl->q_len != 8)
96                 abort();
97
98         off = addr & 3;
99         result = data[off] | (data[off + 1] << 8) | (data[off+2] << 16) | (data[off+3] << 24);
100         return result;
101 }
102
103 /*
104  * Read a 32-bit value from the target device with arbitrary
105  * alignment
106  */
107 static uint32_t
108 get_uint32(stlink_t *sl, uint32_t addr)
109 {
110         uint32_t        result;
111
112         result = get_uint32_sl(sl, addr);
113         printf ("read 0x%08x = 0x%08x\n", addr, result);
114         return result;
115 }
116
117 /*
118  * Check to see if the target device has been
119  * flashed with a similar firmware image before
120  *
121  * This is done by looking for the same romconfig version,
122  * which should be at the same location as the linker script
123  * places this at 0x100 from the start of the rom section
124  */
125 static int
126 check_flashed(stlink_t *sl)
127 {
128         uint16_t        romconfig_version = get_uint16(sl, AO_ROMCONFIG_VERSION);
129         uint16_t        romconfig_check = get_uint16(sl, AO_ROMCONFIG_CHECK);
130
131         if (romconfig_version != (uint16_t) ~romconfig_check) {
132                 fprintf (stderr, "Device has not been flashed before\n");
133                 return 0;
134         }
135         return 1;
136 }
137
138 static const struct option options[] = {
139         { .name = "v1", .has_arg = 0, .val = '1' },
140         { .name = "raw", .has_arg = 0, .val = 'r' },
141         { .name = "cal", .has_arg = 1, .val = 'c' },
142         { .name = "serial", .has_arg = 1, .val = 's' },
143         { .name = "verbose", .has_arg = 1, .val = 'v' },
144         { 0, 0, 0, 0},
145 };
146
147 static void usage(char *program)
148 {
149         fprintf(stderr, "usage: %s [--v1] [--raw] [--verbose=<verbose>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);
150         exit(1);
151 }
152
153 void
154 done(stlink_t *sl, int code)
155 {
156         stlink_reset(sl);
157         stlink_run(sl);
158         stlink_exit_debug_mode(sl);
159         stlink_close(sl);
160         exit (code);
161 }
162
163 static int
164 ends_with(char *whole, char *suffix)
165 {
166         int whole_len = strlen(whole);
167         int suffix_len = strlen(suffix);
168
169         if (suffix_len > whole_len)
170                 return 0;
171         return strcmp(whole + whole_len - suffix_len, suffix) == 0;
172 }
173
174 int
175 main (int argc, char **argv)
176 {
177         int                     stlink_v1 = 0;
178         int                     raw = 0;
179         char                    *filename;
180         Elf                     *e;
181         char                    *serial_end;
182         unsigned int            serial = 0;
183         char                    *serial_ucs2;
184         int                     serial_ucs2_len;
185         char                    serial_int[2];
186         unsigned int            s;
187         int                     i;
188         int                     string_num;
189         uint32_t                cal = 0;
190         char                    cal_int[4];
191         char                    *cal_end;
192         int                     c;
193         stlink_t                *sl = NULL;
194         int                     was_flashed = 0;
195         struct ao_hex_image     *load;
196         int                     tries;
197         int                     success;
198         int                     verbose = 0;
199         struct ao_sym           *file_symbols;
200         int                     num_file_symbols;
201
202         while ((c = getopt_long(argc, argv, "1rc:s:v:", options, NULL)) != -1) {
203                 switch (c) {
204                 case '1':
205                         stlink_v1 = 1;
206                         break;
207                 case 'r':
208                         raw = 1;
209                         break;
210                 case 'c':
211                         cal = strtoul(optarg, &cal_end, 10);
212                         if (cal_end == optarg || *cal_end != '\0')
213                                 usage(argv[0]);
214                         break;
215                 case 's':
216                         serial = strtoul(optarg, &serial_end, 10);
217                         if (serial_end == optarg || *serial_end != '\0')
218                                 usage(argv[0]);
219                         break;
220                 case 'v':
221                         verbose++;
222                         break;
223                 default:
224                         usage(argv[0]);
225                         break;
226                 }
227         }
228
229         ao_verbose = verbose;
230
231         if (verbose > 1)
232                 ccdbg_add_debug(CC_DEBUG_BITBANG);
233
234         filename = argv[optind];
235         if (filename == NULL)
236                 usage(argv[0]);
237
238         if (ends_with (filename, ".elf")) {
239                 load = ao_load_elf(filename, &file_symbols, &num_file_symbols);
240         } else if (ends_with (filename, ".ihx")) {
241                 load = ao_hex_load(filename, &file_symbols, &num_file_symbols);
242         } else
243                 usage(argv[0]);
244
245         if (!raw) {
246                 if (!ao_editaltos_find_symbols(file_symbols, num_file_symbols, ao_symbols, ao_num_symbols)) {
247                         fprintf(stderr, "Cannot find required symbols\n");
248                         usage(argv[0]);
249                 }
250         }
251
252         /* Connect to the programming dongle
253          */
254         
255         for (tries = 0; tries < 3; tries++) {
256                 if (stlink_v1) {
257                         sl = stlink_v1_open(50);
258                 } else {
259                         sl = stlink_open_usb(50);
260                 
261                 }
262                 if (!sl) {
263                         fprintf (stderr, "No STLink devices present\n");
264                         done (sl, 1);
265                 }
266
267                 if (sl->chip_id != 0)
268                         break;
269                 stlink_reset(sl);
270                 stlink_close(sl);
271                 sl = NULL;
272         }
273         if (!sl) {
274                 fprintf (stderr, "Debugger connection failed\n");
275                 exit(1);
276         }
277
278         /* Verify that the loaded image fits entirely within device flash
279          */
280         if (load->address < sl->flash_base ||
281             sl->flash_base + sl->flash_size < load->address + load->length) {
282                 fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename,
283                          load->address, load->address + load->length);
284                 done(sl, 1);
285         }
286
287         /* Enter debugging mode
288          */
289         if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
290                 stlink_exit_dfu_mode(sl);
291
292         if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
293                 stlink_enter_swd_mode(sl);
294
295
296         if (!raw) {
297                 /* Go fetch existing config values
298                  * if available
299                  */
300                 was_flashed = check_flashed(sl);
301
302                 if (!serial) {
303                         if (!was_flashed) {
304                                 fprintf (stderr, "Must provide serial number\n");
305                                 done(sl, 1);
306                         }
307                         serial = get_uint16(sl, AO_SERIAL_NUMBER);
308                         if (!serial || serial == 0xffff) {
309                                 fprintf (stderr, "Invalid existing serial %d\n", serial);
310                                 done(sl, 1);
311                         }
312                 }
313
314                 if (!cal && AO_RADIO_CAL && was_flashed) {
315                         cal = get_uint32(sl, AO_RADIO_CAL);
316                         if (!cal || cal == 0xffffffff) {
317                                 fprintf (stderr, "Invalid existing rf cal %d\n", cal);
318                                 done(sl, 1);
319                         }
320                 }
321
322                 if (!ao_editaltos(load, serial, cal))
323                         done(sl, 1);
324         }
325
326         /* And flash the resulting image to the device
327          */
328
329         success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0);
330                 
331         if (!success) {
332                 fprintf (stderr, "\"%s\": Write failed\n", filename);
333                 done(sl, 1);
334         }
335
336         done(sl, 0);
337 }