b0754637f5595f4fbacee651892397aa08917364
[osmocom-bb.git] / src / host / osmocon / osmoload.c
1 /* control utility for the Calypso bootloader */
2
3 /* (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
4  *
5  * All Rights Reserved
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  */
22
23 #include <errno.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <getopt.h>
30
31 #include <arpa/inet.h>
32
33 #include <sys/stat.h>
34
35 #include <sys/socket.h>
36 #include <sys/un.h>
37
38 #include <osmocore/msgb.h>
39 #include <osmocore/select.h>
40 #include <osmocore/timer.h>
41 #include <osmocore/crc16.h>
42
43 #include <loader/protocol.h>
44
45 #define MSGB_MAX 256
46
47 #define MEM_MSG_MAX (MSGB_MAX - 16)
48
49 #define DEFAULT_SOCKET "/tmp/osmocom_loader"
50
51 static struct bsc_fd connection;
52
53 enum {
54         STATE_INIT,
55         STATE_QUERY_PENDING,
56         STATE_DUMP_IN_PROGRESS,
57         STATE_LOAD_IN_PROGRESS,
58         STATE_FLASHRANGE_GET_INFO,
59         STATE_FLASHRANGE_IN_PROGRESS,
60         STATE_PROGRAM_GET_INFO,
61         STATE_PROGRAM_IN_PROGRESS,
62         STATE_DUMPING,
63 };
64
65 struct flashblock {
66         uint8_t fb_chip;
67         uint32_t fb_offset;
68         uint32_t fb_addr;
69         uint32_t fb_size;
70 };
71
72 static struct {
73         /* debug flags */
74         unsigned char print_requests;
75         unsigned char print_replies;
76
77         /* quit flag for main loop */
78         unsigned char quit;
79
80         /* main state machine */
81         int state;
82
83         /* pending query command */
84         uint8_t command;
85
86         /* general timeout */
87         struct timer_list timeout;
88
89         /* binary i/o for firmware images */
90         FILE *binfile;
91         /* buffer containing binfile data */
92         char *binbuf;
93
94         /* memory operation state */
95         uint8_t  memchip; /* target chip (for flashes) */
96         uint32_t membase; /* target base address of operation */
97         uint32_t memlen;  /* length of entire operation */
98         uint32_t memoff;  /* offset for next request */
99         uint16_t memcrc;  /* crc for current request */
100         uint16_t memreq;  /* length of current request */
101
102         /* array of all flash blocks */
103         uint8_t flashcommand;
104         uint32_t numblocks;
105         struct flashblock blocks[512];
106 } osmoload;
107
108 static int usage(const char *name)
109 {
110         printf("Usage: %s [ -v | -h ] [ -d tr ] [ -m {c123,c155} ] [ -l /tmp/osmocom_loader ] COMMAND ...\n", name);
111
112         puts("\n  Memory commands:");
113         puts("    memget <hex-address> <hex-length>        - Peek at memory");
114         puts("    memput <hex-address> <hex-bytes>         - Poke at memory");
115         puts("    memdump <hex-address> <hex-length> <file>- Dump memory to file");
116         puts("    memload <hex-address> <file>             - Load file into memory");
117
118         puts("\n  Flash commands:");
119         puts("    finfo                             - Information about flash chips");
120         puts("    funlock <address> <length>        - Unlock flash block");
121         puts("    flock <address> <length>          - Lock flash block");
122         puts("    flockdown <address> <length>      - Lock down flash block");
123         puts("    fgetlock <address> <length>       - Get locking state of block");
124         puts("    ferase <address> <length>         - Erase flash range");
125         puts("    fprogram <chip> <address> <file>  - Program file into flash");
126
127         puts("\n  Execution commands:");
128         puts("    jump <hex-address>                 - Jump to address");
129         puts("    jumpflash                          - Jump to flash loader");
130         puts("    jumprom                            - Jump to rom loader");
131
132         puts("\n  Device lifecycle:");
133         puts("    ping                               - Ping the loader");
134         puts("    reset                              - Reset device");
135         puts("    off                                - Power off device");
136
137         puts("\n  Debug:");
138         puts("    dump                               - Dump loader traffic to console");
139
140         exit(2);
141 }
142
143 static int version(const char *name)
144 {
145         //printf("\n%s version %s\n", name, VERSION);
146         exit(2);
147 }
148
149 static void hexdump(const uint8_t *data, unsigned int len)
150 {
151         const uint8_t *bufptr = data;
152         const uint8_t const *endptr = bufptr + len;
153         int n, m, i, hexchr;
154
155         for (n=0; n < len; n+=32, bufptr += 32) {
156                 hexchr = 0;
157                 for(m = 0; m < 32 && bufptr < endptr; m++, bufptr++) {
158                         if((m) && !(m%4)) {
159                                 putchar(' ');
160                                 hexchr++;
161                         }
162                         printf("%02x", *bufptr);
163                         hexchr+=2;
164                 }
165                 bufptr -= m;
166                 int n = 71 - hexchr;
167                 for(i = 0; i < n; i++) {
168                         putchar(' ');
169                 }
170
171                 putchar(' ');
172
173                 for(m = 0; m < 32 && bufptr < endptr; m++, bufptr++) {
174                         if(isgraph(*bufptr)) {
175                                 putchar(*bufptr);
176                         } else {
177                                 putchar('.');
178                         }
179                 }
180                 bufptr -= m;
181
182                 putchar('\n');
183         }
184 }
185
186 static void
187 loader_send_request(struct msgb *msg) {
188         int rc;
189         u_int16_t len = htons(msg->len);
190
191         if(osmoload.print_requests) {
192                 printf("Sending %d bytes:\n", msg->len);
193                 hexdump(msg->data, msg->len);
194         }
195
196         rc = write(connection.fd, &len, sizeof(len));
197         if(rc != sizeof(len)) {
198                 fprintf(stderr, "Error writing.\n");
199                 exit(2);
200         }
201
202         rc = write(connection.fd, msg->data, msg->len);
203         if(rc != msg->len) {
204                 fprintf(stderr, "Error writing.\n");
205                 exit(2);
206         }
207 }
208
209 static void loader_do_memdump(uint16_t crc, void *address, size_t length);
210 static void loader_do_memload();
211 static void loader_do_fprogram();
212 static void loader_do_flashrange(uint8_t cmd, struct msgb *msg, uint8_t chip, uint32_t address, uint32_t status);
213
214 static void memop_timeout(void *dummy) {
215         switch(osmoload.state) {
216         case STATE_LOAD_IN_PROGRESS:
217                 printf("Timeout. Repeating.");
218                 osmoload.memoff -= osmoload.memreq;
219                 loader_do_memload();
220                 break;
221         default:
222                 break;
223         }
224         return;
225 }
226
227 static void
228 loader_parse_flash_info(struct msgb *msg) {
229         uint8_t nchips;
230
231         nchips = msgb_get_u8(msg);
232
233         osmoload.numblocks = 0;
234
235         int chip;
236         for(chip = 0; chip < nchips; chip++) {
237
238                 uint32_t address;
239                 address = msgb_get_u32(msg);
240
241                 uint32_t chipsize;
242                 chipsize = msgb_get_u32(msg);
243
244                 uint8_t nregions;
245                 nregions = msgb_get_u8(msg);
246
247                 printf("    chip %d at 0x%8.8x of %d bytes in %d regions\n", chip, address, chipsize, nregions);
248
249                 uint32_t curoffset = 0;
250                 int region;
251                 for(region = 0; region < nregions; region++) {
252                         uint16_t blockcount = msgb_get_u32(msg);
253                         uint32_t blocksize = msgb_get_u32(msg);
254
255                         printf("      region %d with %d blocks of %d bytes each\n", region, blockcount, blocksize);
256
257                         int block;
258                         for(block = 0; block < blockcount; block++) {
259                                 osmoload.blocks[osmoload.numblocks].fb_chip   = chip;
260                                 osmoload.blocks[osmoload.numblocks].fb_offset = curoffset;
261                                 osmoload.blocks[osmoload.numblocks].fb_addr   = address + curoffset;
262                                 osmoload.blocks[osmoload.numblocks].fb_size   = blocksize;
263
264                                 printf("        block %d with %d bytes at 0x%8.8x on chip %d\n",
265                                            osmoload.numblocks, blocksize, address + curoffset, chip);
266
267                                 curoffset += blocksize;
268
269                                 osmoload.numblocks++;
270                         }
271                 }
272         }
273 }
274
275
276 static void
277 loader_handle_reply(struct msgb *msg) {
278         if(osmoload.print_replies) {
279                 printf("Received %d bytes:\n", msg->len);
280                 hexdump(msg->data, msg->len);
281         }
282
283         uint8_t cmd = msgb_get_u8(msg);
284
285         uint8_t chip;
286         uint8_t length;
287         uint16_t crc;
288         uint32_t address;
289         uint32_t entrypoint;
290         uint32_t status;
291
292         void *data;
293
294         switch(cmd) {
295         case LOADER_INIT:
296                 address = msgb_get_u32(msg);
297                 entrypoint = msgb_get_u32(msg);
298                 printf("Loader at entry %x has been started, requesting load to %x\n", entrypoint, address);
299                 break;
300         case LOADER_PING:
301         case LOADER_RESET:
302         case LOADER_POWEROFF:
303         case LOADER_ENTER_ROM_LOADER:
304         case LOADER_ENTER_FLASH_LOADER:
305                 break;
306         case LOADER_MEM_READ:
307                 length = msgb_get_u8(msg);
308                 crc = msgb_get_u16(msg);
309                 address = msgb_get_u32(msg);
310                 data = msgb_get(msg, length);
311                 break;
312         case LOADER_MEM_WRITE:
313                 length = msgb_get_u8(msg);
314                 crc = msgb_get_u16(msg);
315                 address = msgb_get_u32(msg);
316                 break;
317         case LOADER_JUMP:
318                 address = msgb_get_u32(msg);
319                 break;
320         case LOADER_FLASH_INFO:
321                 break;
322         case LOADER_FLASH_GETLOCK:
323         case LOADER_FLASH_ERASE:
324         case LOADER_FLASH_UNLOCK:
325         case LOADER_FLASH_LOCK:
326         case LOADER_FLASH_LOCKDOWN:
327                 chip = msgb_get_u8(msg);
328                 address = msgb_get_u32(msg);
329                 status = msgb_get_u32(msg);
330                 break;
331         case LOADER_FLASH_PROGRAM:
332                 length = msgb_get_u8(msg);
333                 crc = msgb_get_u16(msg);
334                 msgb_get_u8(msg); // XXX align
335                 chip = msgb_get_u8(msg);
336                 address = msgb_get_u32(msg);
337                 status = msgb_get_u32(msg);
338                 break;
339         default:
340                 printf("Received unknown reply %d:\n", cmd);
341                 hexdump(msg->data, msg->len);
342                 osmoload.quit = 1;
343                 return;
344         }
345
346         switch(osmoload.state) {
347         case STATE_QUERY_PENDING:
348         case STATE_DUMPING:
349                 switch(cmd) {
350                 case LOADER_PING:
351                         printf("Received pong.\n");
352                         break;
353                 case LOADER_RESET:
354                         printf("Reset confirmed.\n");
355                         break;
356                 case LOADER_POWEROFF:
357                         printf("Poweroff confirmed.\n");
358                         break;
359                 case LOADER_ENTER_ROM_LOADER:
360                         printf("Jump to ROM loader confirmed.\n");
361                         break;
362                 case LOADER_ENTER_FLASH_LOADER:
363                         printf("Jump to flash loader confirmed.\n");
364                         break;
365                 case LOADER_MEM_READ:
366                         printf("Received memory dump of %d bytes at 0x%x:\n", length, address);
367                         hexdump(data, length);
368                         break;
369                 case LOADER_MEM_WRITE:
370                         printf("Confirmed memory write of %d bytes at 0x%x.\n", length, address);
371                         break;
372                 case LOADER_JUMP:
373                         printf("Confirmed jump to 0x%x.\n", address);
374                         break;
375                 case LOADER_FLASH_ERASE:
376                         printf("Confirmed flash erase of chip %d address 0x%8.8x, status %s\n",
377                                    chip, address, status ? "FAILED" : "ok");
378                         break;
379                 case LOADER_FLASH_GETLOCK:
380                         printf("Lock state of chip %d address 0x%8.8x is %s\n",
381                                    chip, address, (status == LOADER_FLASH_LOCKED ? "locked"
382                                                                    : (status == LOADER_FLASH_LOCKED_DOWN ? "locked down"
383                                                                           : (status == LOADER_FLASH_UNLOCKED ? "unlocked"
384                                                                                  : "UNKNOWN"))));
385                         break;
386                 case LOADER_FLASH_UNLOCK:
387                         printf("Confirmed flash unlock of chip %d address 0x%8.8x, status %s\n",
388                                    chip, address, status ? "FAILED" : "ok");
389                         break;
390                 case LOADER_FLASH_LOCK:
391                         printf("Confirmed flash lock of chip %d address 0x%8.8x, status %s\n",
392                                    chip, address, status ? "FAILED" : "ok");
393                         break;
394                 case LOADER_FLASH_LOCKDOWN:
395                         printf("Confirmed flash lockdown of chip %d address 0x%8.8x, status %s\n",
396                                    chip, address, status ? "FAILED" : "ok");
397                         break;
398                 case LOADER_FLASH_INFO:
399                         loader_parse_flash_info(msg);
400                         break;
401                 default:
402                         break;
403                 }
404                 if(osmoload.state == STATE_QUERY_PENDING) {
405                         if(osmoload.command == cmd) {
406                                 osmoload.quit = 1;
407                         }
408                 }
409                 break;
410         case STATE_DUMP_IN_PROGRESS:
411                 if(cmd == LOADER_MEM_READ) {
412                         loader_do_memdump(crc, data, length);
413                 }
414                 break;
415         case STATE_LOAD_IN_PROGRESS:
416                 if(cmd == LOADER_MEM_WRITE) {
417                         if(osmoload.memcrc != crc) {
418                                 osmoload.memoff -= osmoload.memreq;
419                                 printf("\nbad crc %4.4x (not %4.4x) at offset 0x%8.8x", crc, osmoload.memcrc, osmoload.memoff);
420                         } else {
421                                 putchar('.');
422                         }
423                         loader_do_memload();
424                 }
425                 break;
426         case STATE_PROGRAM_GET_INFO:
427         case STATE_PROGRAM_IN_PROGRESS:
428                 if(cmd == LOADER_FLASH_PROGRAM) {
429                         if(osmoload.memcrc != crc) {
430                                 osmoload.memoff -= osmoload.memreq;
431                                 printf("\nbad crc %4.4x (not %4.4x) at offset 0x%8.8x", crc, osmoload.memcrc, osmoload.memoff);
432                         } else {
433                                 putchar('.');
434                         }
435                         if(((int)status) != 0) {
436                                 printf("\nstatus %d, aborting\n", status);
437                                 exit(1);
438                         }
439                         loader_do_fprogram();
440                 }
441                 break;
442         case STATE_FLASHRANGE_GET_INFO:
443         case STATE_FLASHRANGE_IN_PROGRESS:
444                 loader_do_flashrange(cmd, msg, chip, address, status);
445                 break;
446         default:
447                 break;
448         }
449
450         fflush(stdout);
451 }
452
453 static int
454 loader_read_cb(struct bsc_fd *fd, unsigned int flags) {
455         struct msgb *msg;
456         u_int16_t len;
457         int rc;
458
459         msg = msgb_alloc(MSGB_MAX, "loader");
460         if (!msg) {
461                 fprintf(stderr, "Failed to allocate msg.\n");
462                 return -1;
463         }
464
465         rc = read(fd->fd, &len, sizeof(len));
466         if (rc < sizeof(len)) {
467                 fprintf(stderr, "Short read. Error.\n");
468                 exit(2);
469         }
470
471         if (ntohs(len) > MSGB_MAX) {
472                 fprintf(stderr, "Length is too big: %u\n", ntohs(len));
473                 msgb_free(msg);
474                 return -1;
475         }
476
477         /* blocking read for the poor... we can starve in here... */
478         msg->l2h = msgb_put(msg, ntohs(len));
479         rc = read(fd->fd, msg->l2h, msgb_l2len(msg));
480         if (rc != msgb_l2len(msg)) {
481                 fprintf(stderr, "Can not read data: rc: %d errno: %d\n", rc, errno);
482                 msgb_free(msg);
483                 return -1;
484         }
485
486         loader_handle_reply(msg);
487
488         msgb_free(msg);
489
490         return 0;
491 }
492
493 static void
494 loader_connect(const char *socket_path) {
495         int rc;
496         struct sockaddr_un local;
497         struct bsc_fd *conn = &connection;
498
499         local.sun_family = AF_UNIX;
500         strncpy(local.sun_path, socket_path, sizeof(local.sun_path));
501         local.sun_path[sizeof(local.sun_path) - 1] = '\0';
502
503         conn->fd = socket(AF_UNIX, SOCK_STREAM, 0);
504         if (conn->fd < 0) {
505                 fprintf(stderr, "Failed to create unix domain socket.\n");
506                 exit(1);
507         }
508
509         rc = connect(conn->fd, (struct sockaddr *) &local,
510                                  sizeof(local.sun_family) + strlen(local.sun_path));
511         if (rc < 0) {
512                 fprintf(stderr, "Failed to connect to '%s'.\n", local.sun_path);
513                 exit(1);
514         }
515
516         conn->when = BSC_FD_READ;
517         conn->cb = loader_read_cb;
518         conn->data = NULL;
519
520         if (bsc_register_fd(conn) != 0) {
521                 fprintf(stderr, "Failed to register fd.\n");
522                 exit(1);
523         }
524 }
525
526 static void
527 loader_send_simple(uint8_t command) {
528         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
529         msgb_put_u8(msg, command);
530         loader_send_request(msg);
531         msgb_free(msg);
532
533         osmoload.command = command;
534 }
535
536 static void
537 loader_start_query(uint8_t command) {
538         loader_send_simple(command);
539         osmoload.state = STATE_QUERY_PENDING;
540 }
541
542 static void
543 loader_send_flash_query(uint8_t command, uint8_t chip, uint32_t address) {
544         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
545         msgb_put_u8(msg, command);
546         msgb_put_u8(msg, chip);
547         msgb_put_u32(msg, address);
548         loader_send_request(msg);
549         msgb_free(msg);
550
551         osmoload.command = command;
552 }
553
554 static void
555 loader_start_flash_query(uint8_t command, uint8_t chip, uint32_t address) {
556         loader_send_flash_query(command, chip, address);
557         osmoload.state = STATE_QUERY_PENDING;
558 }
559
560 static void
561 loader_start_memget(uint8_t length, uint32_t address) {
562         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
563         msgb_put_u8(msg, LOADER_MEM_READ);
564         msgb_put_u8(msg, length);
565         msgb_put_u32(msg, address);
566         loader_send_request(msg);
567         msgb_free(msg);
568
569         osmoload.state = STATE_QUERY_PENDING;
570         osmoload.command = LOADER_MEM_READ;
571 }
572
573 static void
574 loader_start_memput(uint8_t length, uint32_t address, void *data) {
575         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
576         msgb_put_u8(msg, LOADER_MEM_WRITE);
577         msgb_put_u8(msg, length);
578         msgb_put_u16(msg, crc16(0, data, length));
579         msgb_put_u32(msg, address);
580         memcpy(msgb_put(msg, length), data, length);
581         loader_send_request(msg);
582         msgb_free(msg);
583
584         osmoload.state = STATE_QUERY_PENDING;
585         osmoload.command = LOADER_MEM_WRITE;
586 }
587
588 static void
589 loader_start_jump(uint32_t address) {
590         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
591         msgb_put_u8(msg, LOADER_JUMP);
592         msgb_put_u32(msg, address);
593         loader_send_request(msg);
594         msgb_free(msg);
595
596         osmoload.state = STATE_QUERY_PENDING;
597         osmoload.command = LOADER_JUMP;
598 }
599
600
601 static void
602 loader_do_memdump(uint16_t crc, void *data, size_t length) {
603         int rc;
604
605         if(data && length) {
606                 osmoload.memcrc = crc16(0, data, length);
607                 if(osmoload.memcrc != crc) {
608                         osmoload.memoff -= osmoload.memreq;
609                         printf("\nbad crc %4.4x (not %4.4x) at offset 0x%8.8x", crc, osmoload.memcrc, osmoload.memoff);
610                 } else {
611                         putchar('.');
612                 }
613
614                 memcpy(osmoload.binbuf + osmoload.memoff, data, length);
615                 osmoload.memoff += length;
616         }
617
618         uint32_t rembytes = osmoload.memlen - osmoload.memoff;
619
620         if(!rembytes) {
621                 puts("done.");
622                 osmoload.quit = 1;
623
624                 unsigned c = osmoload.memlen;
625                 char *p = osmoload.binbuf;
626                 while(c) {
627                         rc = fwrite(p, 1, c, osmoload.binfile);
628                         if(ferror(osmoload.binfile)) {
629                                 printf("Could not read from file: %s\n", strerror(errno));
630                                 exit(1);
631                         }
632                         c -= rc;
633                         p += rc;
634                 }
635                 fclose(osmoload.binfile);
636                 osmoload.binfile = NULL;
637
638                 free(osmoload.binbuf);
639
640                 return;
641         }
642
643         uint8_t reqbytes = (rembytes < MEM_MSG_MAX) ? rembytes : MEM_MSG_MAX;
644
645         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
646
647         msgb_put_u8(msg, LOADER_MEM_READ);
648         msgb_put_u8(msg, reqbytes);
649         msgb_put_u32(msg, osmoload.membase + osmoload.memoff);
650         loader_send_request(msg);
651         msgb_free(msg);
652 }
653
654 static void
655 loader_do_memload() {
656         uint32_t rembytes = osmoload.memlen - osmoload.memoff;
657
658         if(!rembytes) {
659                 puts("done.");
660                 osmoload.quit = 1;
661                 return;
662         }
663
664         bsc_schedule_timer(&osmoload.timeout, 0, 500000);
665
666         uint8_t reqbytes = (rembytes < MEM_MSG_MAX) ? rembytes : MEM_MSG_MAX;
667
668         osmoload.memcrc = crc16(0, (uint8_t *) osmoload.binbuf + osmoload.memoff, reqbytes);
669         osmoload.memreq = reqbytes;
670
671         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
672
673         msgb_put_u8(msg, LOADER_MEM_WRITE);
674         msgb_put_u8(msg, reqbytes);
675         msgb_put_u16(msg, osmoload.memcrc);
676         msgb_put_u32(msg, osmoload.membase + osmoload.memoff);
677
678         unsigned char *p = msgb_put(msg, reqbytes);
679         memcpy(p, osmoload.binbuf + osmoload.memoff, reqbytes);
680
681 #if 0
682         printf("Sending %u bytes at offset %u to address %x with crc %x\n",
683                    reqbytes, osmoload.memoff, osmoload.membase + osmoload.memoff,
684                    osmoload.memcrc);
685 #endif
686
687         loader_send_request(msg);
688
689         msgb_free(msg);
690
691         osmoload.memoff += reqbytes;
692 }
693
694 static void
695 loader_do_fprogram() {
696         uint32_t rembytes = osmoload.memlen - osmoload.memoff;
697
698         if(!rembytes) {
699                 puts("done.");
700                 osmoload.quit = 1;
701                 return;
702         }
703
704         bsc_schedule_timer(&osmoload.timeout, 0, 10000000);
705
706         uint8_t reqbytes = (rembytes < MEM_MSG_MAX) ? rembytes : MEM_MSG_MAX;
707
708         osmoload.memcrc = crc16(0, (uint8_t *) osmoload.binbuf + osmoload.memoff, reqbytes);
709         osmoload.memreq = reqbytes;
710
711         struct msgb *msg = msgb_alloc(MSGB_MAX, "loader");
712
713         msgb_put_u8(msg, LOADER_FLASH_PROGRAM);
714         msgb_put_u8(msg, reqbytes);
715         msgb_put_u16(msg, osmoload.memcrc);
716         msgb_put_u8(msg, 0); // XXX: align data to 16bit
717         msgb_put_u8(msg, osmoload.memchip);
718         msgb_put_u32(msg, osmoload.membase + osmoload.memoff);
719
720         unsigned char *p = msgb_put(msg, reqbytes);
721         memcpy(p, osmoload.binbuf + osmoload.memoff, reqbytes);
722
723 #if 0
724         printf("Sending %u bytes at offset %u to address %x with crc %x\n",
725                    reqbytes, osmoload.memoff, osmoload.membase + osmoload.memoff,
726                    osmoload.memcrc);
727 #endif
728
729         loader_send_request(msg);
730
731         msgb_free(msg);
732
733         osmoload.memoff += reqbytes;
734 }
735
736 static void
737 loader_start_memdump(uint32_t length, uint32_t address, char *file) {
738         printf("Dumping %u bytes of memory at 0x%x to file %s\n", length, address, file);
739
740         osmoload.binbuf = malloc(length);
741         if(!osmoload.binbuf) {
742                 printf("Could not allocate %u bytes for %s.\n", length, file);
743                 exit(1);
744         }
745
746         osmoload.binfile = fopen(file, "wb");
747         if(!osmoload.binfile) {
748                 printf("Could not open %s: %s\n", file, strerror(errno));
749                 exit(1);
750         }
751
752         osmoload.membase = address;
753         osmoload.memlen = length;
754         osmoload.memoff = 0;
755
756         osmoload.state = STATE_DUMP_IN_PROGRESS;
757         loader_do_memdump(0, NULL, 0);
758 }
759
760 static void
761 loader_start_memload(uint32_t address, char *file) {
762         int rc;
763         struct stat st;
764
765         rc = stat(file, &st);
766         if(rc < 0) {
767                 printf("Could not stat %s: %s\n", file, strerror(errno));
768                 exit(1);
769         }
770
771         uint32_t length = st.st_size;
772
773         printf("Loading %u bytes of memory to address 0x%x from file %s\n", length, address, file);
774
775         osmoload.binbuf = malloc(length);
776         if(!osmoload.binbuf) {
777                 printf("Could not allocate %u bytes for %s.\n", length, file);
778                 exit(1);
779         }
780
781         osmoload.binfile = fopen(file, "rb");
782         if(!osmoload.binfile) {
783                 printf("Could not open %s: %s\n", file, strerror(errno));
784                 exit(1);
785         }
786
787         unsigned c = length;
788         char *p = osmoload.binbuf;
789         while(c) {
790                 rc = fread(p, 1, c, osmoload.binfile);
791                 if(ferror(osmoload.binfile)) {
792                         printf("Could not read from file: %s\n", strerror(errno));
793                         exit(1);
794                 }
795                 c -= rc;
796                 p += rc;
797         }
798         fclose(osmoload.binfile);
799         osmoload.binfile = NULL;
800
801         osmoload.membase = address;
802         osmoload.memlen = length;
803         osmoload.memoff = 0;
804
805         osmoload.state = STATE_LOAD_IN_PROGRESS;
806         loader_do_memload();
807 }
808
809 static void
810 loader_start_flashrange(uint8_t command, uint32_t address, uint32_t length) {
811         switch(command) {
812         case LOADER_FLASH_ERASE:
813                 printf("Erasing %u bytes of flash at 0x%x\n", length, address);
814                 break;
815         case LOADER_FLASH_LOCK:
816                 printf("Locking %u bytes of flash at 0x%x\n", length, address);
817                 break;
818         case LOADER_FLASH_LOCKDOWN:
819                 printf("Locking down %u bytes of flash at 0x%x\n", length, address);
820                 break;
821         case LOADER_FLASH_UNLOCK:
822                 printf("Unlocking %u bytes of flash at 0x%x\n", length, address);
823                 break;
824         case LOADER_FLASH_GETLOCK:
825                 printf("Getlocking %u bytes of flash at 0x%x\n", length, address);
826                 break;
827         default:
828                 puts("Unknown range command");
829                 abort();
830                 break;
831         }
832
833         osmoload.flashcommand = command;
834
835         osmoload.membase = address;
836         osmoload.memlen = length;
837         osmoload.memoff = 0;
838
839         printf("  requesting flash info to determine block layout\n");
840
841         osmoload.state = STATE_FLASHRANGE_GET_INFO;
842
843         loader_send_simple(LOADER_FLASH_INFO);
844 }
845
846 static void
847 loader_do_flashrange(uint8_t cmd, struct msgb *msg, uint8_t chip, uint32_t address, uint32_t status) {
848         switch(osmoload.state) {
849         case STATE_FLASHRANGE_GET_INFO:
850                 if(cmd == LOADER_FLASH_INFO) {
851                         loader_parse_flash_info(msg);
852                         osmoload.state = STATE_FLASHRANGE_IN_PROGRESS;
853                         loader_do_flashrange(0, NULL, 0, 0, 0);
854                 }
855                 break;
856         case STATE_FLASHRANGE_IN_PROGRESS:
857                 {
858                         if(msg) {
859                                 if(cmd == osmoload.flashcommand) {
860                                         if(cmd == LOADER_FLASH_GETLOCK) {
861                                                 printf("  lock state of chip %d address 0x%8.8x is %s\n",
862                                                            chip, address, (status == LOADER_FLASH_LOCKED ? "locked"
863                                                                                            : (status == LOADER_FLASH_LOCKED_DOWN ? "locked down"
864                                                                                                   : (status == LOADER_FLASH_UNLOCKED ? "unlocked"
865                                                                                                          : "UNKNOWN"))));
866                                         } else {
867                                                 printf("  confirmed operation on chip %d address 0x%8.8x, status %s\n",
868                                                            chip, address, status ? "FAILED" : "ok");
869                                         }
870                                 } else {
871                                         break;
872                                 }
873                         }
874
875                         uint32_t addr = osmoload.membase + osmoload.memoff;
876
877                         if(osmoload.memoff >= osmoload.memlen) {
878                                 puts("  operation done");
879                                 osmoload.quit = 1;
880                                 break;
881                         }
882
883                         uint8_t found = 0;
884                         int i;
885                         for(i = 0; i < osmoload.numblocks; i++) {
886                                 struct flashblock *b = &osmoload.blocks[i];
887                                 if(b->fb_addr == addr) {
888                                         loader_send_flash_query(osmoload.flashcommand, b->fb_chip, b->fb_offset);
889                                         osmoload.memoff += b->fb_size;
890                                         found = 1;
891                                         break;
892                                 }
893                         }
894                         if(!found) {
895                                 puts("Oops!? Block not found?"); // XXX message
896                                 abort();
897                         }
898                 }
899                 break;
900         }
901 }
902
903 static void
904 loader_start_fprogram(uint8_t chip, uint32_t address, char *file) {
905         int rc;
906         struct stat st;
907
908         rc = stat(file, &st);
909         if(rc < 0) {
910                 printf("Could not stat %s: %s\n", file, strerror(errno));
911                 exit(1);
912         }
913
914         uint32_t length = st.st_size;
915
916         printf("Loading %u bytes of memory at 0x%x in chip %d from file %s\n", length, address, chip, file);
917
918         osmoload.binbuf = malloc(length);
919         if(!osmoload.binbuf) {
920                 printf("Could not allocate %u bytes for %s.\n", length, file);
921                 exit(1);
922         }
923
924         osmoload.binfile = fopen(file, "rb");
925         if(!osmoload.binfile) {
926                 printf("Could not open %s: %s\n", file, strerror(errno));
927                 exit(1);
928         }
929
930         unsigned c = length;
931         char *p = osmoload.binbuf;
932         while(c) {
933                 rc = fread(p, 1, c, osmoload.binfile);
934                 if(ferror(osmoload.binfile)) {
935                         printf("Could not read from file: %s\n", strerror(errno));
936                         exit(1);
937                 }
938                 c -= rc;
939                 p += rc;
940         }
941         fclose(osmoload.binfile);
942         osmoload.binfile = NULL;
943
944         osmoload.memchip = chip;
945         osmoload.membase = address;
946         osmoload.memlen = length;
947         osmoload.memoff = 0;
948
949         osmoload.state = STATE_PROGRAM_IN_PROGRESS;
950
951         loader_do_fprogram();
952 }
953
954 static void
955 query_timeout(void *dummy) {
956         puts("Query timed out.");
957         exit(2);
958 }
959
960 static void
961 loader_command(char *name, int cmdc, char **cmdv) {
962         if(!cmdc) {
963                 usage(name);
964         }
965
966         char *cmd = cmdv[0];
967
968         char buf[MEM_MSG_MAX];
969         memset(buf, 23, sizeof(buf));
970
971         if(!strcmp(cmd, "dump")) {
972                 osmoload.state = STATE_DUMPING;
973         } else if(!strcmp(cmd, "ping")) {
974                 loader_start_query(LOADER_PING);
975         } else if(!strcmp(cmd, "off")) {
976                 loader_start_query(LOADER_POWEROFF);
977         } else if(!strcmp(cmd, "reset")) {
978                 loader_start_query(LOADER_RESET);
979         } else if(!strcmp(cmd, "jumprom")) {
980                 loader_start_query(LOADER_ENTER_ROM_LOADER);
981         } else if(!strcmp(cmd, "jumpflash")) {
982                 loader_start_query(LOADER_ENTER_FLASH_LOADER);
983         } else if(!strcmp(cmd, "finfo")) {
984                 puts("Requesting flash layout info");
985                 loader_start_query(LOADER_FLASH_INFO);
986         } else if(!strcmp(cmd, "memput")) {
987                 uint32_t address;
988
989                 if(cmdc < 3) {
990                         usage(name);
991                 }
992
993                 address = strtoul(cmdv[1], NULL, 16);
994
995                 unsigned int i;
996                 char *hex = cmdv[2];
997                 if(strlen(hex)&1) {
998                         puts("Invalid hex string.");
999                         exit(2);
1000                 }
1001                 for(i = 0; i <= sizeof(buf) && i < strlen(hex)/2; i++) {
1002                         if(i >= sizeof(buf)) {
1003                                 puts("Value too long for single message");
1004                                 exit(2);
1005                         }
1006                         unsigned int byte;
1007                         int count = sscanf(hex + i * 2, "%02x", &byte);
1008                         if(count != 1) {
1009                                 puts("Invalid hex string.");
1010                                 exit(2);
1011                         }
1012                         buf[i] = byte & 0xFF;
1013                 }
1014
1015                 loader_start_memput(i & 0xFF, address, buf);
1016         } else if(!strcmp(cmd, "memget")) {
1017                 uint32_t address;
1018                 uint8_t length;
1019
1020                 if(cmdc < 3) {
1021                         usage(name);
1022                 }
1023
1024                 address = strtoul(cmdv[1], NULL, 16);
1025                 length = strtoul(cmdv[2], NULL, 16);
1026
1027                 if(length > MEM_MSG_MAX) {
1028                         puts("Too many bytes");
1029                         exit(2);
1030                 }
1031
1032                 loader_start_memget(length, address);
1033         } else if(!strcmp(cmd, "jump")) {
1034                 uint32_t address;
1035
1036                 if(cmdc < 2) {
1037                         usage(name);
1038                 }
1039
1040                 address = strtoul(cmdv[1], NULL, 16);
1041
1042                 loader_start_jump(address);
1043         } else if(!strcmp(cmd, "memdump")) {
1044                 uint32_t address;
1045                 uint32_t length;
1046
1047                 if(cmdc < 4) {
1048                         usage(name);
1049                 }
1050
1051                 address = strtoul(cmdv[1], NULL, 16);
1052                 length = strtoul(cmdv[2], NULL, 16);
1053
1054                 loader_start_memdump(length, address, cmdv[3]);
1055         } else if(!strcmp(cmd, "memload")) {
1056                 uint32_t address;
1057
1058                 if(cmdc < 3) {
1059                         usage(name);
1060                 }
1061
1062                 address = strtoul(cmdv[1], NULL, 16);
1063
1064                 loader_start_memload(address, cmdv[2]);
1065         } else if(!strcmp(cmd, "fprogram")) {
1066                 uint8_t chip;
1067                 uint32_t address;
1068
1069                 if(cmdc < 4) {
1070                         usage(name);
1071                 }
1072
1073                 chip = strtoul(cmdv[1], NULL, 10);
1074                 address = strtoul(cmdv[2], NULL, 16);
1075
1076                 loader_start_fprogram(chip, address, cmdv[3]);
1077         } else if(!strcmp(cmd, "ferase")) {
1078                 uint32_t address;
1079                 uint32_t length;
1080
1081                 if(cmdc < 3) {
1082                         usage(name);
1083                 }
1084
1085                 address = strtoul(cmdv[1], NULL, 16);
1086                 length = strtoul(cmdv[2], NULL, 16);
1087
1088                 loader_start_flashrange(LOADER_FLASH_ERASE, address, length);
1089         } else if(!strcmp(cmd, "flock")) {
1090                 uint32_t address;
1091                 uint32_t length;
1092
1093                 if(cmdc < 3) {
1094                         usage(name);
1095                 }
1096
1097                 address = strtoul(cmdv[1], NULL, 16);
1098                 length = strtoul(cmdv[2], NULL, 16);
1099
1100                 loader_start_flashrange(LOADER_FLASH_LOCK, address, length);
1101         } else if(!strcmp(cmd, "flockdown")) {
1102                 uint32_t address;
1103                 uint32_t length;
1104
1105                 if(cmdc < 3) {
1106                         usage(name);
1107                 }
1108
1109                 address = strtoul(cmdv[1], NULL, 16);
1110                 length = strtoul(cmdv[2], NULL, 16);
1111
1112                 loader_start_flashrange(LOADER_FLASH_LOCKDOWN, address, length);
1113         } else if(!strcmp(cmd, "funlock")) {
1114                 uint32_t address;
1115                 uint32_t length;
1116
1117                 if(cmdc < 3) {
1118                         usage(name);
1119                 }
1120
1121                 address = strtoul(cmdv[1], NULL, 16);
1122                 length = strtoul(cmdv[2], NULL, 16);
1123
1124                 loader_start_flashrange(LOADER_FLASH_UNLOCK, address, length);
1125         } else if(!strcmp(cmd, "fgetlock")) {
1126                 uint32_t address;
1127                 uint32_t length;
1128
1129                 if(cmdc < 3) {
1130                         usage(name);
1131                 }
1132
1133                 address = strtoul(cmdv[1], NULL, 16);
1134                 length = strtoul(cmdv[2], NULL, 16);
1135
1136                 loader_start_flashrange(LOADER_FLASH_GETLOCK, address, length);
1137         } else if(!strcmp(cmd, "help")) {
1138                 usage(name);
1139         } else {
1140                 printf("Unknown command '%s'\n", cmd);
1141                 usage(name);
1142         }
1143
1144         if(osmoload.state == STATE_QUERY_PENDING) {
1145                 osmoload.timeout.cb = &query_timeout;
1146                 bsc_schedule_timer(&osmoload.timeout, 0, 5000000);
1147         }
1148         if(osmoload.state == STATE_LOAD_IN_PROGRESS) {
1149                 osmoload.timeout.cb = &memop_timeout;
1150         }
1151
1152 }
1153
1154 void
1155 setdebug(const char *name, char c) {
1156         switch(c) {
1157         case 't':
1158                 osmoload.print_requests = 1;
1159                 break;
1160         case 'r':
1161                 osmoload.print_replies = 1;
1162                 break;
1163         default:
1164                 usage(name);
1165                 break;
1166         }
1167 }
1168
1169 int
1170 main(int argc, char **argv) {
1171         int opt;
1172         char *loader_un_path = "/tmp/osmocom_loader";
1173         const char *debugopt;
1174
1175         while((opt = getopt(argc, argv, "d:hl:m:v")) != -1) {
1176                 switch(opt) {
1177                 case 'd':
1178                         debugopt = optarg;
1179                         while(*debugopt) {
1180                                 setdebug(argv[0], *debugopt);
1181                                 debugopt++;
1182                         }
1183                         break;
1184                 case 'l':
1185                         loader_un_path = optarg;
1186                         break;
1187                 case 'm':
1188                         puts("model selection not implemented");
1189                         exit(2);
1190                         break;
1191                 case 'v':
1192                         version(argv[0]);
1193                         break;
1194                 case 'h':
1195                 default:
1196                         usage(argv[0]);
1197                         break;
1198                 }
1199         }
1200
1201         osmoload.quit = 0;
1202
1203         loader_connect(loader_un_path);
1204
1205         loader_command(argv[0], argc - optind, argv + optind);
1206
1207         while(!osmoload.quit) {
1208                 bsc_select_main(0);
1209         }
1210
1211         if(osmoload.binfile) {
1212                 fclose(osmoload.binfile);
1213         }
1214
1215         return 0;
1216 }