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