]> git.zerfleddert.de Git - proxmark3-svn/blob - client/flasher.c
lean up event model so that this will work under OS X (and hopefully Linux)
[proxmark3-svn] / client / flasher.c
1 #include <usb.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <stdint.h>
6 #include <stdbool.h>
7 #include <strings.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <ctype.h>
11
12 #include "prox.h"
13 #include "proxmark3.h"
14
15 static uint32_t ExpectedAddr;
16 static uint8_t QueuedToSend[256];
17 static bool AllWritten;
18 #define PHYSICAL_FLASH_START 0x100000
19 unsigned int current_command = CMD_UNKNOWN;
20
21 void WaitForAck(void) {
22 UsbCommand ack;
23 ReceiveCommand(&ack);
24 if(ack.cmd != CMD_ACK) {
25 printf("bad ACK\n");
26 exit(-1);
27 }
28 }
29
30 struct partition {
31 int start;
32 int end;
33 int precious;
34 const char *name;
35 };
36 struct partition partitions[] = {
37 {0x100000, 0x102000, 1, "bootrom"},
38 {0x102000, 0x110000, 0, "fpga"},
39 {0x110000, 0x140000, 0, "os"},
40 };
41
42 /* If translate is set, subtract PHYSICAL_FLASH_START to translate for old
43 * bootroms.
44 */
45 static void FlushPrevious(int translate)
46 {
47 UsbCommand c;
48 memset(&c, 0, sizeof(c));
49
50 printf("expected = %08x flush, ", ExpectedAddr);
51
52 int i;
53 for(i = 0; i < 240; i += 48) {
54 c.cmd = CMD_SETUP_WRITE;
55 memcpy(c.d.asBytes, QueuedToSend+i, 48);
56 c.arg[0] = (i/4);
57 SendCommand(&c);
58 WaitForAck();
59 }
60
61 c.cmd = CMD_FINISH_WRITE;
62 c.arg[0] = (ExpectedAddr-1) & (~255);
63 if(translate) {
64 c.arg[0] -= PHYSICAL_FLASH_START;
65 }
66 printf("c.arg[0] = %08x\r", c.arg[0]);
67 memcpy(c.d.asBytes, QueuedToSend+240, 16);
68 SendCommand(&c);
69 WaitForAck();
70
71 AllWritten = true;
72 }
73
74 /* Where must be between start_addr (inclusive) and end_addr (exclusive).
75 */
76 static void GotByte(uint32_t where, uint8_t which, int start_addr, int end_addr, int translate)
77 {
78 AllWritten = false;
79
80 if(where < start_addr || where >= end_addr) {
81 printf("bad: got byte at %08x, outside of range %08x-%08x\n", where, start_addr, end_addr);
82 exit(-1);
83 }
84
85 if(where != ExpectedAddr) {
86 printf("bad: got at %08x, expected at %08x\n", where, ExpectedAddr);
87 exit(-1);
88 }
89 QueuedToSend[where & 255] = which;
90 ExpectedAddr++;
91
92 if((where & 255) == 255) {
93 // we have completed a full page
94 FlushPrevious(translate);
95 }
96 }
97
98 static int HexVal(int c)
99 {
100 c = tolower(c);
101 if(c >= '0' && c <= '9') {
102 return c - '0';
103 } else if(c >= 'a' && c <= 'f') {
104 return (c - 'a') + 10;
105 } else {
106 printf("bad hex digit '%c'\n", c);
107 exit(-1);
108 }
109 }
110
111 static uint8_t HexByte(char *s)
112 {
113 return (HexVal(s[0]) << 4) | HexVal(s[1]);
114 }
115
116 static void LoadFlashFromSRecords(const char *file, int start_addr, int end_addr, int translate)
117 {
118 ExpectedAddr = start_addr;
119
120 FILE *f = fopen(file, "r");
121 if(!f) {
122 printf("couldn't open file\n");
123 exit(-1);
124 }
125
126 char line[512];
127 while(fgets(line, sizeof(line), f)) {
128 if(memcmp(line, "S3", 2)==0) {
129 char *s = line + 2;
130 int len = HexByte(s) - 5;
131 s += 2;
132
133 char addrStr[9];
134 memcpy(addrStr, s, 8);
135 addrStr[8] = '\0';
136 uint32_t addr;
137 sscanf(addrStr, "%x", &addr);
138 s += 8;
139
140 /* Accept files that are located at PHYSICAL_FLASH_START, and files that are located at 0 */
141 if(addr < PHYSICAL_FLASH_START)
142 addr += PHYSICAL_FLASH_START;
143
144 int i;
145 for(i = 0; i < len; i++) {
146 while((addr+i) > ExpectedAddr) {
147 GotByte(ExpectedAddr, 0xff, start_addr, end_addr, translate);
148 }
149 GotByte(addr+i, HexByte(s), start_addr, end_addr, translate);
150 s += 2;
151 }
152 }
153 }
154
155 if(!AllWritten) FlushPrevious(translate);
156
157 fclose(f);
158 printf("\ndone.\n");
159 }
160
161 static int PrepareFlash(struct partition *p, const char *filename, unsigned int state)
162 {
163 int translate = 0;
164 if(state & DEVICE_INFO_FLAG_UNDERSTANDS_START_FLASH) {
165 UsbCommand c;
166 c.cmd = CMD_START_FLASH;
167 c.arg[0] = p->start;
168 c.arg[1] = p->end;
169
170 /* Only send magic when flashing bootrom */
171 if(p->precious) {
172 c.arg[2] = START_FLASH_MAGIC;
173 } else {
174 c.arg[2] = 0;
175 }
176 SendCommand(&c);
177 WaitForAck();
178 translate = 0;
179 } else {
180 fprintf(stderr, "Warning: Your bootloader does not understand the new START_FLASH command\n");
181 fprintf(stderr, " It is recommended that you update your bootloader\n\n");
182 translate = 1;
183 }
184
185 LoadFlashFromSRecords(filename, p->start, p->end, translate);
186 return 1;
187 }
188
189 static unsigned int GetProxmarkState(void)
190 {
191 unsigned int state = 0;
192
193 UsbCommand c;
194 c.cmd = CMD_DEVICE_INFO;
195 SendCommand(&c);
196
197 UsbCommand resp;
198 ReceiveCommand(&resp);
199 /* Three cases:
200 * 1. The old bootrom code will ignore CMD_DEVICE_INFO, but respond with an ACK
201 * 2. The old os code will respond with CMD_DEBUG_PRINT_STRING and "unknown command"
202 * 3. The new bootrom and os codes will respond with CMD_DEVICE_INFO and flags
203 */
204
205 switch(resp.cmd) {
206 case CMD_ACK:
207 state = DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM;
208 break;
209 case CMD_DEBUG_PRINT_STRING:
210 state = DEVICE_INFO_FLAG_CURRENT_MODE_OS;
211 break;
212 case CMD_DEVICE_INFO:
213 state = resp.arg[0];
214 break;
215 default:
216 fprintf(stderr, "Couldn't get proxmark state, bad response type: 0x%04X\n", resp.cmd);
217 exit(-1);
218 break;
219 }
220
221 #if 0
222 if(state & DEVICE_INFO_FLAG_BOOTROM_PRESENT) printf("New bootrom present\n");
223 if(state & DEVICE_INFO_FLAG_OSIMAGE_PRESENT) printf("New osimage present\n");
224 if(state & DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM) printf("Currently in bootrom\n");
225 if(state & DEVICE_INFO_FLAG_CURRENT_MODE_OS) printf("Currently in OS\n");
226 #endif
227
228 return state;
229 }
230
231 static unsigned int EnterFlashState(void)
232 {
233 unsigned int state = GetProxmarkState();
234
235 if(state & DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM) {
236 /* Already in flash state, we're done. */
237 return state;
238 }
239
240 if(state & DEVICE_INFO_FLAG_CURRENT_MODE_OS) {
241 fprintf(stderr,"Entering flash-mode...\n");
242 UsbCommand c;
243 bzero(&c, sizeof(c));
244
245 if( (state & DEVICE_INFO_FLAG_BOOTROM_PRESENT) && (state & DEVICE_INFO_FLAG_OSIMAGE_PRESENT) ) {
246 /* New style handover: Send CMD_START_FLASH, which will reset the board and
247 * enter the bootrom on the next boot.
248 */
249 c.cmd = CMD_START_FLASH;
250 SendCommand(&c);
251 fprintf(stderr,"(You don't have to do anything. Press and release the button only if you want to abort)\n");
252 fprintf(stderr,"Waiting for Proxmark to reappear on USB... ");
253 } else {
254 /* Old style handover: Ask the user to press the button, then reset the board */
255 c.cmd = CMD_HARDWARE_RESET;
256 SendCommand(&c);
257 fprintf(stderr,"(Press and hold down button NOW if your bootloader requires it)\n");
258 fprintf(stderr,"Waiting for Proxmark to reappear on USB... ");
259 }
260
261 CloseProxmark();
262 sleep(1);
263
264 while(!(devh=OpenProxmark(0))) { sleep(1); }
265 fprintf(stderr,"Found.\n");
266
267 return GetProxmarkState();
268 }
269
270 return 0;
271 }
272
273 static void usage(char **argv)
274 {
275 int i;
276 fprintf(stderr, "Usage: %s areas image [image [image]]\n", argv[0]);
277 fprintf(stderr, " areas is a comma-separated list of areas to flash, with no spaces\n");
278 fprintf(stderr, " Known areas are:");
279 for(i=0; i<(sizeof(partitions)/sizeof(partitions[0])); i++) {
280 fprintf(stderr, " %s", partitions[i].name);
281 }
282 fprintf(stderr, "\n");
283 fprintf(stderr, " image is the path to the corresponding image\n\n");
284 fprintf(stderr, "Example: %s os,fpga path/to/osimage.s19 path/to/fpgaimage.s19\n", argv[0]);
285 }
286
287 /* On first call, have *offset = -1, *length = 0; */
288 static int find_next_area(const char *str, int *offset, int *length)
289 {
290 if(*str == '\0') return 0;
291 if((*offset >= 0) && str[*offset + *length] == '\0') return 0;
292 *offset += 1 + *length;
293
294 char *next_comma = strchr(str + *offset, ',');
295 if(next_comma == NULL) {
296 *length = strlen(str) - *offset;
297 } else {
298 *length = next_comma-(str+*offset);
299 }
300 return 1;
301 }
302
303 int main(int argc, char **argv) {
304 if(argc < 2) {
305 usage(argv);
306 exit(-1);
307 }
308
309 /* Count area arguments */
310 int areas = 0, offset=-1, length=0;
311 while(find_next_area(argv[1], &offset, &length)) areas++;
312
313 if(areas != argc - 2) {
314 usage(argv);
315 exit(-1);
316 }
317
318 usb_init();
319
320 fprintf(stderr,"Waiting for Proxmark to appear on USB... ");
321 while(!(devh=OpenProxmark(0))) { sleep(1); }
322 fprintf(stderr,"Found.\n");
323
324 unsigned int state = EnterFlashState();
325
326 if( !(state & DEVICE_INFO_FLAG_CURRENT_MODE_BOOTROM) ) {
327 fprintf(stderr, "Proxmark would not enter flash state, abort\n");
328 exit(-1);
329 }
330
331 offset=-1; length=0;
332 int current_area = 0;
333 while(find_next_area(argv[1], &offset, &length)) {
334 int i;
335 struct partition *p = NULL;
336 for(i=0; i<sizeof(partitions)/sizeof(partitions[0]); i++) {
337 if(strncmp(partitions[i].name, argv[1] + offset, length) == 0) {
338 /* Check if the name matches the bootrom partition, and if so, require "bootrom" to
339 * be written in full. The other names may be abbreviated.
340 */
341 if(!partitions[i].precious || (strlen(partitions[i].name) == length)) {
342 p = &partitions[i];
343 }
344 break;
345 }
346 }
347
348 if(p == NULL) {
349 fprintf(stderr, "Warning: area name '");
350 fwrite(argv[1]+offset, length, 1, stderr);
351 fprintf(stderr, "' unknown, ignored\n");
352 } else {
353 fprintf(stderr, "Flashing %s from %s\n", p->name, argv[2+current_area]);
354 PrepareFlash(p, argv[2+current_area], state);
355 }
356 current_area++;
357 }
358
359 UsbCommand c;
360 bzero(&c, sizeof(c));
361 c.cmd = CMD_HARDWARE_RESET;
362 SendCommand(&c);
363
364 CloseProxmark();
365
366 fprintf(stderr,"Have a nice day!\n");
367
368 return 0;
369 }
Impressum, Datenschutz