]> git.zerfleddert.de Git - proxmark3-svn/blame - client/flasher.c
moar svn ignore crap
[proxmark3-svn] / client / flasher.c
CommitLineData
6658905f 1#include <usb.h>
2#include <stdio.h>
3#include <unistd.h>
4#include <stdlib.h>
a146075d 5#include <stdint.h>
6#include <stdbool.h>
6658905f 7#include <strings.h>
8#include <string.h>
9#include <errno.h>
10#include <ctype.h>
11
cd00aa30 12#include "prox.h"
6658905f 13#include "proxmark3.h"
14
a146075d 15static uint32_t ExpectedAddr;
16static uint8_t QueuedToSend[256];
17static bool AllWritten;
a5b1ba20 18#define PHYSICAL_FLASH_START 0x100000
9b255608 19unsigned int current_command = CMD_UNKNOWN;
20
21void WaitForAck(void) {
22 UsbCommand ack;
23 ReceiveCommand(&ack);
24 if(ack.cmd != CMD_ACK) {
25 printf("bad ACK\n");
26 exit(-1);
27 }
28}
a5b1ba20 29
30struct partition {
31 int start;
32 int end;
33 int precious;
34 const char *name;
35};
36struct 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 */
45static void FlushPrevious(int translate)
6658905f 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);
3a8464f0 56 c.arg[0] = (i/4);
9b255608 57 SendCommand(&c);
58 WaitForAck();
6658905f 59 }
60
61 c.cmd = CMD_FINISH_WRITE;
3a8464f0 62 c.arg[0] = (ExpectedAddr-1) & (~255);
a5b1ba20 63 if(translate) {
3a8464f0 64 c.arg[0] -= PHYSICAL_FLASH_START;
a5b1ba20 65 }
3a8464f0 66 printf("c.arg[0] = %08x\r", c.arg[0]);
6658905f 67 memcpy(c.d.asBytes, QueuedToSend+240, 16);
9b255608 68 SendCommand(&c);
69 WaitForAck();
6658905f 70
a146075d 71 AllWritten = true;
6658905f 72}
73
a5b1ba20 74/* Where must be between start_addr (inclusive) and end_addr (exclusive).
75 */
a146075d 76static void GotByte(uint32_t where, uint8_t which, int start_addr, int end_addr, int translate)
6658905f 77{
a146075d 78 AllWritten = false;
a5b1ba20 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 }
6658905f 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
a5b1ba20 94 FlushPrevious(translate);
6658905f 95 }
96}
97
98static 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
a146075d 111static uint8_t HexByte(char *s)
6658905f 112{
113 return (HexVal(s[0]) << 4) | HexVal(s[1]);
114}
115
a5b1ba20 116static void LoadFlashFromSRecords(const char *file, int start_addr, int end_addr, int translate)
6658905f 117{
a5b1ba20 118 ExpectedAddr = start_addr;
119
6658905f 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';
a146075d 136 uint32_t addr;
6658905f 137 sscanf(addrStr, "%x", &addr);
138 s += 8;
a5b1ba20 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;
6658905f 143
144 int i;
145 for(i = 0; i < len; i++) {
146 while((addr+i) > ExpectedAddr) {
a5b1ba20 147 GotByte(ExpectedAddr, 0xff, start_addr, end_addr, translate);
6658905f 148 }
a5b1ba20 149 GotByte(addr+i, HexByte(s), start_addr, end_addr, translate);
6658905f 150 s += 2;
151 }
152 }
153 }
154
a5b1ba20 155 if(!AllWritten) FlushPrevious(translate);
6658905f 156
157 fclose(f);
158 printf("\ndone.\n");
159}
160
a5b1ba20 161static 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;
3a8464f0 167 c.arg[0] = p->start;
168 c.arg[1] = p->end;
a5b1ba20 169
170 /* Only send magic when flashing bootrom */
171 if(p->precious) {
3a8464f0 172 c.arg[2] = START_FLASH_MAGIC;
a5b1ba20 173 } else {
3a8464f0 174 c.arg[2] = 0;
a5b1ba20 175 }
9b255608 176 SendCommand(&c);
177 WaitForAck();
a5b1ba20 178 translate = 0;
6658905f 179 } else {
a5b1ba20 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;
6658905f 183 }
a5b1ba20 184
185 LoadFlashFromSRecords(filename, p->start, p->end, translate);
186 return 1;
187}
6658905f 188
a5b1ba20 189static unsigned int GetProxmarkState(void)
190{
191 unsigned int state = 0;
192
193 UsbCommand c;
194 c.cmd = CMD_DEVICE_INFO;
9b255608 195 SendCommand(&c);
a5b1ba20 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:
3a8464f0 213 state = resp.arg[0];
a5b1ba20 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;
431ae7e0 219 }
a5b1ba20 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}
431ae7e0 230
a5b1ba20 231static 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) {
431ae7e0 241 fprintf(stderr,"Entering flash-mode...\n");
a5b1ba20 242 UsbCommand c;
431ae7e0 243 bzero(&c, sizeof(c));
a5b1ba20 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;
9b255608 250 SendCommand(&c);
a5b1ba20 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;
9b255608 256 SendCommand(&c);
a5b1ba20 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
431ae7e0 261 CloseProxmark();
262 sleep(1);
263
431ae7e0 264 while(!(devh=OpenProxmark(0))) { sleep(1); }
a5b1ba20 265 fprintf(stderr,"Found.\n");
266
267 return GetProxmarkState();
268 }
269
270 return 0;
271}
272
273static 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);
431ae7e0 281 }
a5b1ba20 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}
6658905f 286
a5b1ba20 287/* On first call, have *offset = -1, *length = 0; */
288static 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);
431ae7e0 299 }
a5b1ba20 300 return 1;
301}
6658905f 302
a5b1ba20 303int 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;
6658905f 360 bzero(&c, sizeof(c));
361 c.cmd = CMD_HARDWARE_RESET;
9b255608 362 SendCommand(&c);
6658905f 363
364 CloseProxmark();
365
366 fprintf(stderr,"Have a nice day!\n");
367
368 return 0;
369}
Impressum, Datenschutz