1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 
5 #include <helper.h>
6 
7 #include "flash.h"
8 
starts_with(const char * str,const char * prefix)9 static bool starts_with(const char * str, const char * prefix) {
10     size_t n = strlen(prefix);
11 
12     if (strlen(str) < n) { return(false); }
13 
14     return (0 == strncmp(str, prefix, n));
15 }
16 
17 // support positive integer from 0 to UINT64_MAX
18 // support decimal, hexadecimal, octal, binary format like 0xff 12 1k 1M, 0b1001
19 // negative numbers are not supported
20 // return 0 if success else return -1
get_long_integer_from_char_array(const char * const str,uint64_t * read_value)21 static int get_long_integer_from_char_array (const char *const str, uint64_t *read_value) {
22     uint64_t value;
23     char *tail;
24 
25     if (starts_with (str, "0x") || starts_with (str, "0X")) {          // hexadecimal
26         value = strtoul (str + 2, &tail, 16);
27     } else if (starts_with (str, "0b") || starts_with (str, "0B")) {   // binary
28         value = strtoul (str + 2, &tail, 2);
29     } else if (starts_with (str, "0")) {                               // octal
30         value = strtoul (str + 1, &tail, 8);
31     } else {                                                           // decimal
32         value = strtoul (str, &tail, 10);
33     }
34 
35     if (((tail[0] == 'k') || (tail[0] == 'K')) && (tail[1] == '\0')) {
36         value = value * 1024;
37     } else if (((tail[0] == 'm') || (tail[0] == 'M')) && (tail[1] == '\0')) {
38         value = value * 1024 * 1024;
39     } else if (tail[0] == '\0') {
40         /* value not changed */
41     } else {
42         return(-1);
43     }
44 
45     *read_value = value;
46     return(0);
47 }
48 
49 // support positive integer from 0 to UINT32_MAX
50 // support decimal, hexadecimal, octal, binary format like 0xff 12 1k 1M, 0b1001
51 // negative numbers are not supported
52 // return 0 if success else return -1
get_integer_from_char_array(const char * const str,uint32_t * read_value)53 static int get_integer_from_char_array (const char *const str, uint32_t *read_value) {
54     uint64_t value;
55     int result = get_long_integer_from_char_array (str, &value);
56 
57     if (result != 0) {
58         return(result);
59     } else if (value > UINT32_MAX) {
60         fprintf (stderr, "*** Error: Integer greater than UINT32_MAX, cannot convert to int32_t\n");
61         return(-1);
62     } else {
63         *read_value = (uint32_t)value;
64         return(0);
65     }
66 }
67 
invalid_args(const char * expected)68 static int invalid_args(const char *expected) {
69     fprintf(stderr, "*** Error: Expected args for this command: %s\n", expected);
70     return(-1);
71 }
72 
bad_arg(const char * arg)73 static int bad_arg(const char *arg) {
74     fprintf(stderr, "*** Error: Invalid value for %s\n", arg);
75     return(-1);
76 }
77 
flash_get_opts(struct flash_opts * o,int ac,char ** av)78 int flash_get_opts(struct flash_opts* o, int ac, char** av) {
79 
80     // defaults
81     memset(o, 0, sizeof(*o));
82     o->log_level = STND_LOG_LEVEL;
83 
84     // options
85     int result;
86 
87     while (ac >= 1) {
88         if (strcmp(av[0], "--version") == 0) {
89             printf("v%s\n", STLINK_VERSION);
90             exit(EXIT_SUCCESS);
91         } else if (strcmp(av[0], "--debug") == 0) {
92             o->log_level = DEBUG_LOG_LEVEL;
93         } else if (strcmp(av[0], "--opt") == 0) {
94             o->opt = ENABLE_OPT;
95         } else if (strcmp(av[0], "--reset") == 0) {
96             o->reset = 1;
97         } else if (strcmp(av[0], "--serial") == 0 || starts_with(av[0], "--serial=")) {
98             const char * serial;
99 
100             if (strcmp(av[0], "--serial") == 0) {
101                 ac--;
102                 av++;
103 
104                 if (ac < 1) { return(-1); }
105 
106                 serial = av[0];
107             } else {
108                 serial = av[0] + strlen("--serial=");
109             }
110 
111             memcpy(o->serial, serial, STLINK_SERIAL_BUFFER_SIZE);
112 
113         } else if (strcmp(av[0], "--area") == 0 || starts_with(av[0], "--area=")) {
114             const char * area;
115 
116             if (strcmp(av[0], "--area") == 0) {
117                 ac--;
118                 av++;
119 
120                 if (ac < 1) { return(-1); }
121 
122                 area = av[0];
123             } else {
124                 area = av[0] + strlen("--area=");
125             }
126 
127             if (strcmp(area, "main") == 0) {
128                 o->area = FLASH_MAIN_MEMORY;
129             } else if (strcmp(area, "system") == 0) {
130                 o->area = FLASH_SYSTEM_MEMORY;
131             } else if (strcmp(area, "otp") == 0) {
132                 o->area = FLASH_OTP;
133             } else if (strcmp(area, "option") == 0) {
134                 o->area = FLASH_OPTION_BYTES;
135             } else if (strcmp(area, "option_boot_add") == 0) {
136                 o->area = FLASH_OPTION_BYTES_BOOT_ADD;
137             } else if (strcmp(area, "optcr") == 0) {
138                 o->area = FLASH_OPTCR;
139             } else if (strcmp(area, "optcr1") == 0) {
140                 o->area = FLASH_OPTCR1;
141             } else {
142                 return(-1);
143             }
144 
145         } else if (strcmp(av[0], "--freq") == 0) {
146             ac--;
147             av++;
148 
149             if (ac < 1) {
150                 return(-1);
151             }
152 
153             o->freq = arg_parse_freq(av[0]);
154             if (o->freq < 0) {
155                 return(-1);
156             }
157         } else if (starts_with(av[0], "--freq=")) {
158             o->freq = arg_parse_freq(av[0] + strlen("--freq="));
159             if (o->freq < 0) {
160                 return(-1);
161             }
162         } else if (strcmp(av[0], "--format") == 0 || starts_with(av[0], "--format=")) {
163             const char * format;
164 
165             if (strcmp(av[0], "--format") == 0) {
166                 ac--;
167                 av++;
168 
169                 if (ac < 1) { return(-1); }
170 
171                 format = av[0];
172             } else {
173                 format = av[0] + strlen("--format=");
174             }
175 
176             if (strcmp(format, "binary") == 0) {
177                 o->format = FLASH_FORMAT_BINARY;
178             } else if (strcmp(format, "ihex") == 0) {
179                 o->format = FLASH_FORMAT_IHEX;
180             } else {
181                 return(bad_arg("format"));
182             }
183         } else if ( starts_with(av[0], "--flash=")) {
184             const char *arg = av[0] + strlen("--flash=");
185 
186             uint32_t flash_size;
187             result = get_integer_from_char_array(arg, &flash_size);
188 
189             if (result != 0) {
190                 return(bad_arg ("--flash"));
191             } else {
192                 o->flash_size = (size_t)flash_size;
193             }
194         } else if (strcmp(av[0], "--connect-under-reset") == 0) {
195             o->connect = CONNECT_UNDER_RESET;
196         } else if (strcmp(av[0], "--hot-plug") == 0) {
197             o->connect = CONNECT_HOT_PLUG;
198         } else {
199             break; // non-option found
200 
201         }
202 
203         ac--;
204         av++;
205     }
206 
207     // command and (optional) device name
208     while (ac >= 1) {
209         if (strcmp(av[0], "erase") == 0) {
210             if (o->cmd != FLASH_CMD_NONE) { return(-1); }
211             o->cmd = FLASH_CMD_ERASE;
212         } else if (strcmp(av[0], "read") == 0) {
213             if (o->cmd != FLASH_CMD_NONE) { return(-1); }
214 
215             o->cmd = FLASH_CMD_READ;
216         } else if (strcmp(av[0], "write") == 0) {
217             if (o->cmd != FLASH_CMD_NONE) { return(-1); }
218 
219             o->cmd = FLASH_CMD_WRITE;
220         } else if (strcmp(av[0], "reset") == 0) {
221             if (o->cmd != FLASH_CMD_NONE) { return(-1); }
222 
223             o->cmd = CMD_RESET;
224         } else {
225             break;
226         }
227 
228         ac--;
229         av++;
230     }
231 
232     switch (o->cmd) {
233     case FLASH_CMD_NONE:     // no command found
234         return(-1);
235 
236     case FLASH_CMD_ERASE:    // no more arguments expected
237         if (ac != 0) { return(-1); }
238 
239         break;
240 
241     case FLASH_CMD_READ:     // expect filename, addr and size
242         if ((o->area == FLASH_MAIN_MEMORY) || (o->area == FLASH_SYSTEM_MEMORY)) {
243             if (ac != 3) { return invalid_args("read <path> <addr> <size>"); }
244 
245             o->filename = av[0];
246             uint32_t address;
247             result = get_integer_from_char_array(av[1], &address);
248             if (result != 0) {
249                 return bad_arg ("addr");
250             } else {
251                 o->addr = (stm32_addr_t) address;
252             }
253 
254             uint32_t size;
255             result = get_integer_from_char_array(av[2], &size);
256             if (result != 0) {
257                 return bad_arg ("size");
258             } else {
259                 o->size = (size_t) size;
260             }
261 
262             break;
263         } else if (o->area == FLASH_OTP) {
264             return bad_arg("TODO: otp not implemented yet");
265             if (ac > 1) { return invalid_args("otp read: [path]"); }
266             if (ac > 0) { o->filename = av[0]; }
267             break;
268         } else if (o->area == FLASH_OPTION_BYTES) {
269             if (ac > 2) { return invalid_args("option bytes read: [path] [size]"); }
270             if (ac > 0) { o->filename = av[0]; }
271             if (ac > 1) {
272                 uint32_t size;
273                 result = get_integer_from_char_array(av[1], &size);
274                 if (result != 0) {
275                     return bad_arg("option bytes read: invalid size");
276                 } else {
277                     o->size = (size_t) size;
278                 }
279             }
280             break;
281         } else if (o->area == FLASH_OPTION_BYTES_BOOT_ADD) {
282             if (ac > 0) { return invalid_args("option bytes boot_add read"); }
283             break;
284         } else if (o->area == FLASH_OPTCR) {
285             if (ac > 0) { return invalid_args("option control register read"); }
286             break;
287         } else if (o->area == FLASH_OPTCR1) {
288             if (ac > 0) { return invalid_args("option control register 1 read"); }
289             break;
290         }
291 
292         break;
293 
294     case FLASH_CMD_WRITE:
295         // TODO: should be boot add 0 and boot add 1 uint32
296         if (o->area == FLASH_OPTION_BYTES) { // expect option byte value
297             if (ac != 1) { return invalid_args("option byte write <value>"); }
298             uint32_t val;
299             result = get_integer_from_char_array(av[0], &val);
300             if (result != 0) {
301                 return bad_arg ("val");
302             } else {
303                 o->val = (uint32_t) val;
304             }
305         } else if (o->area == FLASH_OPTION_BYTES_BOOT_ADD) { // expect option bytes boot address
306             if (ac != 1) { return invalid_args("option bytes boot_add write <value>"); }
307 
308             uint32_t val;
309             result = get_integer_from_char_array(av[0], &val);
310 
311             if (result != 0) {
312                 return(bad_arg ("val"));
313             } else {
314                 o->val = (uint32_t)val;
315             }
316         } else if (o->area == FLASH_OPTCR) { // expect option control register value
317             if (ac != 1) { return invalid_args("option control register write <value>"); }
318 
319             uint32_t val;
320             result = get_integer_from_char_array(av[0], &val);
321 
322             if (result != 0) {
323                 return bad_arg ("val");
324             } else {
325                 o->val = (uint32_t) val;
326             }
327         } else if (o->area == FLASH_OPTCR1) { // expect option control register 1 value
328             if (ac != 1) { return invalid_args("option control register 1 write <value>"); }
329 
330             uint32_t val;
331             result = get_integer_from_char_array(av[0], &val);
332             if (result != 0) {
333                 return bad_arg ("val");
334             } else {
335                 o->val = (uint32_t) val;
336             }
337         } else if (o->format == FLASH_FORMAT_BINARY) {    // expect filename and addr
338             if (ac != 2) { return invalid_args("write <path> <addr>"); }
339 
340             o->filename = av[0];
341             uint32_t addr;
342             result = get_integer_from_char_array(av[1], &addr);
343 
344             if (result != 0) {
345                 return(bad_arg ("addr"));
346             } else {
347                 o->addr = (stm32_addr_t)addr;
348             }
349         } else if (o->format == FLASH_FORMAT_IHEX) { // expect filename
350             if (ac != 1) { return(invalid_args("write <path>")); }
351 
352             o->filename = av[0];
353         } else {
354             return(-1); // should have been caught during format parsing
355         }
356 
357         break;
358 
359     default: break;
360     }
361 
362     return(0);
363 }
364