3 * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
4 * Copyright (C) 2011 Michael Walle
5 * Copyright (C) 2004 MontaVista Software, Inc
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, version 3 of the License.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/types.h>
24 #include <sys/ioctl.h>
39 #include <linux/serial.h>
42 #define DEFAULT_KERNELADR (0x40000000)
43 #define DEFAULT_CMDLINEADR (0x41000000)
44 #define DEFAULT_INITRDADR (0x41002000)
46 #define GDBBUFLEN 1000
48 unsigned int crc16_table
[256] = {
49 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
50 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
51 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
52 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
53 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
54 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
55 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
56 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
57 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
58 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
59 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
60 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
61 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
62 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
63 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
64 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
65 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
66 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
67 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
68 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
69 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
70 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
71 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
72 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
73 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
74 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
75 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
76 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
77 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
78 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
79 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
80 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
85 static unsigned short crc16(const void *_buffer
, int len
)
87 const unsigned char *buffer
= (const unsigned char *)_buffer
;
92 crc
= crc16_table
[((crc
>> 8) ^ (*buffer
++)) & 0xFF] ^ (crc
<< 8);
97 static int write_exact(int fd
, const char *data
, unsigned int length
)
102 r
= write(fd
, data
, length
);
110 /* length, cmd and payload must be filled in */
111 static int send_frame(int serialfd
, struct sfl_frame
*frame
)
113 unsigned short int crc
;
117 crc
= crc16(&frame
->cmd
, frame
->length
+1);
118 frame
->crc
[0] = (crc
& 0xff00) >> 8;
119 frame
->crc
[1] = (crc
& 0x00ff);
123 if(!write_exact(serialfd
, (char *)frame
, frame
->length
+4)) {
124 perror("[FLTERM] Unable to write to serial port.");
127 /* Get the reply from the device */
128 read(serialfd
, &reply
, 1); /* TODO: timeout */
130 case SFL_ACK_SUCCESS
:
133 case SFL_ACK_CRCERROR
:
137 fprintf(stderr
, "[FLTERM] Got unknown reply '%c' from the device, aborting.\n", reply
);
144 static int upload_fd(int serialfd
, const char *name
, int firmwarefd
, unsigned int load_address
)
146 struct sfl_frame frame
;
150 unsigned int current_address
;
155 length
= lseek(firmwarefd
, 0, SEEK_END
);
156 lseek(firmwarefd
, 0, SEEK_SET
);
158 printf("[FLTERM] Uploading %s (%d bytes)...\n", name
, length
);
160 gettimeofday(&t0
, NULL
);
162 current_address
= load_address
;
165 printf("%d%%\r", 100*position
/length
);
168 readbytes
= read(firmwarefd
, &frame
.payload
[4], sizeof(frame
.payload
) - 4);
170 perror("[FLTERM] Unable to read image.");
173 if(readbytes
== 0) break;
175 frame
.length
= readbytes
+4;
176 frame
.cmd
= SFL_CMD_LOAD
;
177 frame
.payload
[0] = (current_address
& 0xff000000) >> 24;
178 frame
.payload
[1] = (current_address
& 0x00ff0000) >> 16;
179 frame
.payload
[2] = (current_address
& 0x0000ff00) >> 8;
180 frame
.payload
[3] = (current_address
& 0x000000ff);
182 if(!send_frame(serialfd
, &frame
)) return -1;
184 current_address
+= readbytes
;
185 position
+= readbytes
;
188 gettimeofday(&t1
, NULL
);
190 millisecs
= (t1
.tv_sec
- t0
.tv_sec
)*1000 + (t1
.tv_usec
- t0
.tv_usec
)/1000;
192 printf("[FLTERM] Upload complete (%.1fKB/s).\n", 1000.0*(double)length
/((double)millisecs
*1024.0));
196 static const char sfl_magic_req
[SFL_MAGIC_LEN
] = SFL_MAGIC_REQ
;
197 static const char sfl_magic_ack
[SFL_MAGIC_LEN
] = SFL_MAGIC_ACK
;
199 static void answer_magic(int serialfd
,
200 const char *kernel_image
, unsigned int kernel_address
,
201 const char *cmdline
, unsigned int cmdline_address
,
202 const char *initrd_image
, unsigned int initrd_address
)
204 int kernelfd
, initrdfd
;
205 struct sfl_frame frame
;
207 printf("[FLTERM] Received firmware download request from the device.\n");
209 kernelfd
= open(kernel_image
, O_RDONLY
);
211 perror("[FLTERM] Unable to open kernel image (request ignored).");
215 if(initrd_image
!= NULL
) {
216 initrdfd
= open(initrd_image
, O_RDONLY
);
218 perror("[FLTERM] Unable to open initrd image (request ignored).");
224 write_exact(serialfd
, sfl_magic_ack
, SFL_MAGIC_LEN
);
226 upload_fd(serialfd
, "kernel", kernelfd
, kernel_address
);
227 if(cmdline
!= NULL
) {
230 printf("[FLTERM] Setting kernel command line: '%s'.\n", cmdline
);
232 len
= strlen(cmdline
)+1;
234 fprintf(stderr
, "[FLTERM] Kernel command line too long, load aborted.\n");
239 frame
.length
= len
+4;
240 frame
.cmd
= SFL_CMD_LOAD
;
241 frame
.payload
[0] = (cmdline_address
& 0xff000000) >> 24;
242 frame
.payload
[1] = (cmdline_address
& 0x00ff0000) >> 16;
243 frame
.payload
[2] = (cmdline_address
& 0x0000ff00) >> 8;
244 frame
.payload
[3] = (cmdline_address
& 0x000000ff);
245 strcpy((char *)&frame
.payload
[4], cmdline
);
246 send_frame(serialfd
, &frame
);
249 frame
.cmd
= SFL_CMD_CMDLINE
;
250 frame
.payload
[0] = (cmdline_address
& 0xff000000) >> 24;
251 frame
.payload
[1] = (cmdline_address
& 0x00ff0000) >> 16;
252 frame
.payload
[2] = (cmdline_address
& 0x0000ff00) >> 8;
253 frame
.payload
[3] = (cmdline_address
& 0x000000ff);
254 send_frame(serialfd
, &frame
);
259 len
= upload_fd(serialfd
, "initrd", initrdfd
, initrd_address
);
263 frame
.cmd
= SFL_CMD_INITRDSTART
;
264 frame
.payload
[0] = (initrd_address
& 0xff000000) >> 24;
265 frame
.payload
[1] = (initrd_address
& 0x00ff0000) >> 16;
266 frame
.payload
[2] = (initrd_address
& 0x0000ff00) >> 8;
267 frame
.payload
[3] = (initrd_address
& 0x000000ff);
268 send_frame(serialfd
, &frame
);
270 initrd_address
+= len
-1;
273 frame
.cmd
= SFL_CMD_INITRDEND
;
274 frame
.payload
[0] = (initrd_address
& 0xff000000) >> 24;
275 frame
.payload
[1] = (initrd_address
& 0x00ff0000) >> 16;
276 frame
.payload
[2] = (initrd_address
& 0x0000ff00) >> 8;
277 frame
.payload
[3] = (initrd_address
& 0x000000ff);
278 send_frame(serialfd
, &frame
);
281 /* Send the jump command */
282 printf("[FLTERM] Booting the device.\n");
284 frame
.cmd
= SFL_CMD_JUMP
;
285 frame
.payload
[0] = (kernel_address
& 0xff000000) >> 24;
286 frame
.payload
[1] = (kernel_address
& 0x00ff0000) >> 16;
287 frame
.payload
[2] = (kernel_address
& 0x0000ff00) >> 8;
288 frame
.payload
[3] = (kernel_address
& 0x000000ff);
289 if(!send_frame(serialfd
, &frame
)) return;
291 printf("[FLTERM] Done.\n");
297 static int hex(unsigned char c
)
299 if(c
>= 'a' && c
<= 'f') {
302 if(c
>= '0' && c
<= '9') {
305 if(c
>= 'A' && c
<= 'F') {
312 * This is taken from kdmx2.
313 * Author: Tom Rini <trini@mvista.com>
315 static void gdb_process_packet(int infd
, int outfd
, int altfd
)
317 /* gdb packet handling */
318 char gdbbuf
[GDBBUFLEN
+ 1];
320 unsigned char runcksum
= 0;
321 unsigned char recvcksum
= 0;
329 memset(gdbbuf
, 0, sizeof(gdbbuf
));
335 if(poll(&fds
, 1, 100) == 0) {
338 write(altfd
, gdbbuf
, pos
);
342 if(pos
== GDBBUFLEN
) {
344 write(altfd
, gdbbuf
, pos
);
352 } else if(seen_hash
== 0) {
354 } else if(seen_hash
== 1) {
355 recvcksum
= hex(c
) << 4;
357 } else if(seen_hash
== 2) {
365 if(recvcksum
== runcksum
) {
367 fprintf(stderr
, "[GDB %s]\n", gdbbuf
);
369 write(outfd
, gdbbuf
, pos
);
372 write(altfd
, gdbbuf
, pos
);
381 static void do_terminal(char *serial_port
,
382 int baud
, int gdb_passthrough
,
383 const char *kernel_image
, unsigned int kernel_address
,
384 const char *cmdline
, unsigned int cmdline_address
,
385 const char *initrd_image
, unsigned int initrd_address
,
391 struct termios my_termios
;
394 struct pollfd fds
[3];
400 /* Open and configure the serial port */
401 if(log_path
!= NULL
) {
402 logfd
= fopen(log_path
, "a+");
404 perror("Unable to open log file");
409 serialfd
= open(serial_port
, O_RDWR
|O_NOCTTY
);
411 perror("Unable to open serial port");
417 case 9600: c_cflag
= B9600
; break;
418 case 19200: c_cflag
= B19200
; break;
419 case 38400: c_cflag
= B38400
; break;
420 case 57600: c_cflag
= B57600
; break;
421 case 115200: c_cflag
= B115200
; break;
422 case 230400: c_cflag
= B230400
; break;
431 struct serial_struct serial_info
;
432 ioctl(serialfd
, TIOCGSERIAL
, &serial_info
);
433 serial_info
.custom_divisor
= serial_info
.baud_base
/ baud
;
434 serial_info
.flags
&= ~ASYNC_SPD_MASK
;
435 serial_info
.flags
|= ASYNC_SPD_CUST
;
436 ioctl(serialfd
, TIOCSSERIAL
, &serial_info
);
440 fprintf(stderr
, "[FLTERM] baudrate not supported\n");
445 /* Thanks to Julien Schmitt (GTKTerm) for figuring out the correct parameters
446 * to put into that weird struct.
448 tcgetattr(serialfd
, &my_termios
);
449 my_termios
.c_cflag
= c_cflag
;
450 my_termios
.c_cflag
|= CS8
;
451 my_termios
.c_cflag
|= CREAD
;
452 my_termios
.c_iflag
= IGNPAR
| IGNBRK
;
453 my_termios
.c_cflag
|= CLOCAL
;
454 my_termios
.c_oflag
= 0;
455 my_termios
.c_lflag
= 0;
456 my_termios
.c_cc
[VTIME
] = 0;
457 my_termios
.c_cc
[VMIN
] = 1;
458 tcsetattr(serialfd
, TCSANOW
, &my_termios
);
459 tcflush(serialfd
, TCOFLUSH
);
460 tcflush(serialfd
, TCIFLUSH
);
462 /* Prepare the fdset for poll() */
464 fds
[0].events
= POLLIN
;
465 fds
[1].fd
= serialfd
;
466 fds
[1].events
= POLLIN
;
469 flags
= fcntl(serialfd
, F_GETFL
, 0);
471 if(gdbfd
== -1 && gdb_passthrough
) {
472 gdbfd
= open("/dev/ptmx", O_RDWR
);
473 if(grantpt(gdbfd
) != 0) {
477 if(unlockpt(gdbfd
) != 0) {
478 perror("unlockpt()");
481 printf("[GDB passthrough] use %s as GDB remote device\n",
484 fds
[2].events
= POLLIN
;
491 /* poll() behaves strangely when the serial port descriptor is in
492 * blocking mode. So work around this.
494 fcntl(serialfd
, F_SETFL
, flags
|O_NONBLOCK
);
495 if(poll(&fds
[0], (gdbfd
== -1) ? 2 : 3, -1) < 0) break;
496 fcntl(serialfd
, F_SETFL
, flags
);
498 if(fds
[0].revents
& POLLIN
) {
499 if(read(0, &c
, 1) <= 0) break;
500 if(write(serialfd
, &c
, 1) <= 0) break;
503 if(fds
[2].revents
& POLLIN
) {
505 if(read(gdbfd
, &c
, 1) <= 0) break;
507 /* convert ETX to breaks */
509 fprintf(stderr
, "[GDB BREAK]\n");
511 tcsendbreak(serialfd
, 0);
512 } else if(c
== '$') {
513 gdb_process_packet(gdbfd
, serialfd
, -1);
514 } else if(c
== '+' || c
== '-') {
515 write(serialfd
, &c
, 1);
517 fprintf(stderr
, "Internal error (line %d)", __LINE__
);
522 if(fds
[2].revents
& POLLHUP
) {
523 /* close and reopen new pair */
529 if(fds
[1].revents
& POLLIN
) {
530 if(read(serialfd
, &c
, 1) <= 0) break;
532 if(logfd
&& c
&& isascii(c
)) {
533 fwrite(&c
, sizeof(c
), 1, logfd
);
534 if(c
== '\n') fflush(logfd
);
537 if(gdbfd
!= -1 && rsp_pending
&& (c
== '+' || c
== '-')) {
540 } else if(gdbfd
!= -1 && c
== '$') {
541 gdb_process_packet(serialfd
, gdbfd
, 0);
543 /* write to terminal */
546 if(kernel_image
!= NULL
) {
547 if(c
== sfl_magic_req
[recognized
]) {
549 if(recognized
== SFL_MAGIC_LEN
) {
550 /* We've got the magic string ! */
552 answer_magic(serialfd
,
553 kernel_image
, kernel_address
,
554 cmdline
, cmdline_address
,
555 initrd_image
, initrd_address
);
558 if(c
== sfl_magic_req
[0]) recognized
= 1; else recognized
= 0;
567 if(gdbfd
!= -1) close(gdbfd
);
568 if(logfd
) fclose(logfd
);
573 OPTION_GDB_PASSTHROUGH
,
585 static const struct option options
[] = {
592 .name
= "gdb-passthrough",
594 .val
= OPTION_GDB_PASSTHROUGH
612 .name
= "kernel-adr",
614 .val
= OPTION_KERNELADR
619 .val
= OPTION_CMDLINE
622 .name
= "cmdline-adr",
624 .val
= OPTION_CMDLINEADR
632 .name
= "initrd-adr",
634 .val
= OPTION_INITRDADR
646 static void print_usage()
648 fprintf(stderr
, "Serial boot program for Milkymist SoC - v. 2.3\n");
649 fprintf(stderr
, "Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq\n");
650 fprintf(stderr
, "Copyright (C) 2011 Michael Walle\n");
651 fprintf(stderr
, "Copyright (C) 2004 MontaVista Software, Inc\n\n");
653 fprintf(stderr
, "This program is free software: you can redistribute it and/or modify\n");
654 fprintf(stderr
, "it under the terms of the GNU General Public License as published by\n");
655 fprintf(stderr
, "the Free Software Foundation, version 3 of the License.\n\n");
657 fprintf(stderr
, "Usage: flterm --port <port>\n");
658 fprintf(stderr
, " [--speed <speed>] [--gdb-passthrough] [--debug]\n");
659 fprintf(stderr
, " [--kernel <kernel_image> [--kernel-adr <address>]]\n");
660 fprintf(stderr
, " [--cmdline <cmdline> [--cmdline-adr <address>]]\n");
661 fprintf(stderr
, " [--initrd <initrd_image> [--initrd-adr <address>]]\n");
662 fprintf(stderr
, " [--log <log_file>]\n\n");
663 fprintf(stderr
, "Default load addresses:\n");
664 fprintf(stderr
, " kernel: 0x%08x\n", DEFAULT_KERNELADR
);
665 fprintf(stderr
, " cmdline: 0x%08x\n", DEFAULT_CMDLINEADR
);
666 fprintf(stderr
, " initrd: 0x%08x\n", DEFAULT_INITRDADR
);
669 int main(int argc
, char *argv
[])
676 unsigned int kernel_address
;
678 unsigned int cmdline_address
;
680 unsigned int initrd_address
;
683 struct termios otty
, ntty
;
685 /* Fetch command line arguments */
690 kernel_address
= DEFAULT_KERNELADR
;
692 cmdline_address
= DEFAULT_CMDLINEADR
;
694 initrd_address
= DEFAULT_INITRDADR
;
696 while((opt
= getopt_long(argc
, argv
, "", options
, NULL
)) != -1) {
704 serial_port
= strdup(optarg
);
707 baud
= strtoul(optarg
, &endptr
, 0);
709 fprintf(stderr
, "[FLTERM] Couldn't parse baudrate\n");
716 case OPTION_GDB_PASSTHROUGH
:
721 kernel_image
= strdup(optarg
);
723 case OPTION_KERNELADR
:
724 kernel_address
= strtoul(optarg
, &endptr
, 0);
726 fprintf(stderr
, "[FLTERM] Couldn't parse kernel address\n");
732 cmdline
= strdup(optarg
);
734 case OPTION_CMDLINEADR
:
735 cmdline_address
= strtoul(optarg
, &endptr
, 0);
737 fprintf(stderr
, "[FLTERM] Couldn't parse cmdline address\n");
743 initrd_image
= strdup(optarg
);
745 case OPTION_INITRDADR
:
746 initrd_address
= strtoul(optarg
, &endptr
, 0);
748 fprintf(stderr
, "[FLTERM] Couldn't parse initrd address\n");
754 log_path
= strdup(optarg
);
759 if(serial_port
== NULL
) {
760 fprintf(stderr
, "[FLTERM] No port given\n");
765 printf("[FLTERM] Starting...\n");
767 /* Set up stdin/out */
770 ntty
.c_lflag
&= ~(ECHO
| ICANON
);
771 tcsetattr(0, TCSANOW
, &ntty
);
773 /* Do the bulk of the work */
774 do_terminal(serial_port
, baud
, gdb_passthrough
,
775 kernel_image
, kernel_address
,
776 cmdline
, cmdline_address
,
777 initrd_image
, initrd_address
,
780 /* Restore stdin/out into their previous state */
781 tcsetattr(0, TCSANOW
, &otty
);