]>
git.ipfire.org Git - people/ms/u-boot.git/blob - tools/kwboot.c
2 * Boot a Marvell Kirkwood SoC, with Xmodem over UART0.
4 * (c) 2012 Daniel Stodden <daniel.stodden@gmail.com>
6 * References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281
7 * Integrated Controller: Functional Specifications" December 2,
8 * 2008. Chapter 24.2 "BootROM Firmware".
27 #define PACKED __attribute((packed))
33 * Marvell BootROM UART Sensing
36 static unsigned char kwboot_msg_boot
[] = {
37 0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
40 #define KWBOOT_MSG_REQ_DELAY 10 /* ms */
41 #define KWBOOT_MSG_RSP_TIMEO 50 /* ms */
47 #define SOH 1 /* sender start of block header */
48 #define EOT 4 /* sender end of block transfer */
49 #define ACK 6 /* target block ack */
50 #define NAK 21 /* target block negative ack */
51 #define CAN 24 /* target/sender transfer cancellation */
61 #define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */
63 static int kwboot_verbose
;
66 kwboot_printv(const char *fmt
, ...)
81 const char seq
[] = { '-', '\\', '|', '/' };
85 if (state
% div
== 0) {
87 fputc(seq
[state
/ div
% sizeof(seq
)], stdout
);
103 __progress(int pct
, char c
)
105 const int width
= 70;
106 static const char *nl
= "";
109 if (pos
% width
== 0)
110 printf("%s%3d %% [", nl
, pct
);
118 while (pos
++ < width
)
128 kwboot_progress(int _pct
, char c
)
140 kwboot_tty_recv(int fd
, void *buf
, size_t len
, int timeo
)
153 tv
.tv_usec
= timeo
* 1000;
154 if (tv
.tv_usec
> 1000000) {
155 tv
.tv_sec
+= tv
.tv_usec
/ 1000000;
156 tv
.tv_usec
%= 1000000;
160 nfds
= select(fd
+ 1, &rfds
, NULL
, NULL
, &tv
);
168 n
= read(fd
, buf
, len
);
172 buf
= (char *)buf
+ n
;
182 kwboot_tty_send(int fd
, const void *buf
, size_t len
)
190 n
= write(fd
, buf
, len
);
194 buf
= (char *)buf
+ n
;
204 kwboot_tty_send_char(int fd
, unsigned char c
)
206 return kwboot_tty_send(fd
, &c
, 1);
210 kwboot_tty_speed(int baudrate
)
229 kwboot_open_tty(const char *path
, speed_t speed
)
236 fd
= open(path
, O_RDWR
|O_NOCTTY
|O_NDELAY
);
240 memset(&tio
, 0, sizeof(tio
));
243 tio
.c_cflag
= CREAD
|CLOCAL
|CS8
;
246 tio
.c_cc
[VTIME
] = 10;
248 cfsetospeed(&tio
, speed
);
249 cfsetispeed(&tio
, speed
);
251 rc
= tcsetattr(fd
, TCSANOW
, &tio
);
266 kwboot_bootmsg(int tty
, void *msg
)
271 kwboot_printv("Sending boot message. Please reboot the target...");
274 rc
= tcflush(tty
, TCIOFLUSH
);
278 rc
= kwboot_tty_send(tty
, msg
, 8);
280 usleep(KWBOOT_MSG_REQ_DELAY
* 1000);
284 rc
= kwboot_tty_recv(tty
, &c
, 1, KWBOOT_MSG_RSP_TIMEO
);
288 } while (rc
|| c
!= NAK
);
296 kwboot_xm_makeblock(struct kwboot_block
*block
, const void *data
,
297 size_t size
, int pnum
)
299 const size_t blksz
= sizeof(block
->data
);
304 block
->_pnum
= ~block
->pnum
;
306 n
= size
< blksz
? size
: blksz
;
307 memcpy(&block
->data
[0], data
, n
);
308 memset(&block
->data
[n
], 0, blksz
- n
);
311 for (i
= 0; i
< n
; i
++)
312 block
->csum
+= block
->data
[i
];
318 kwboot_xm_sendblock(int fd
, struct kwboot_block
*block
)
325 rc
= kwboot_tty_send(fd
, block
, sizeof(*block
));
329 rc
= kwboot_tty_recv(fd
, &c
, 1, KWBOOT_BLK_RSP_TIMEO
);
334 kwboot_progress(-1, '+');
336 } while (c
== NAK
&& retries
-- > 0);
359 kwboot_xmodem(int tty
, const void *_data
, size_t size
)
361 const uint8_t *data
= _data
;
362 int rc
, pnum
, N
, err
;
367 kwboot_printv("Sending boot image...\n");
370 struct kwboot_block block
;
373 n
= kwboot_xm_makeblock(&block
,
382 rc
= kwboot_xm_sendblock(tty
, &block
);
387 kwboot_progress(N
* 100 / size
, '.');
390 rc
= kwboot_tty_send_char(tty
, EOT
);
397 kwboot_tty_send_char(tty
, CAN
);
403 kwboot_term_pipe(int in
, int out
, char *quit
, int *s
)
406 char _buf
[128], *buf
= _buf
;
408 nin
= read(in
, buf
, sizeof(buf
));
415 for (i
= 0; i
< nin
; i
++) {
416 if (*buf
== quit
[*s
]) {
424 nout
= write(out
, quit
, *s
);
433 nout
= write(out
, buf
, nin
);
443 kwboot_terminal(int tty
)
447 struct termios otio
, tio
;
453 rc
= tcgetattr(in
, &otio
);
457 rc
= tcsetattr(in
, TCSANOW
, &tio
);
464 kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n",
465 quit
[0]|0100, quit
[1]);
477 nfds
= nfds
< tty
? tty
: nfds
;
481 nfds
= nfds
< in
? in
: nfds
;
484 nfds
= select(nfds
+ 1, &rfds
, NULL
, NULL
, NULL
);
488 if (FD_ISSET(tty
, &rfds
)) {
489 rc
= kwboot_term_pipe(tty
, STDOUT_FILENO
, NULL
, NULL
);
494 if (FD_ISSET(in
, &rfds
)) {
495 rc
= kwboot_term_pipe(in
, tty
, quit
, &s
);
499 } while (quit
[s
] != 0);
501 tcsetattr(in
, TCSANOW
, &otio
);
507 kwboot_mmap_image(const char *path
, size_t *size
, int prot
)
517 fd
= open(path
, O_RDONLY
);
525 flags
= (prot
& PROT_WRITE
) ? MAP_PRIVATE
: MAP_SHARED
;
527 img
= mmap(NULL
, st
.st_size
, prot
, flags
, fd
, 0);
528 if (img
== MAP_FAILED
) {
537 munmap(img
, st
.st_size
);
547 kwboot_img_csum8(void *_data
, size_t size
)
549 uint8_t *data
= _data
, csum
;
551 for (csum
= 0; size
-- > 0; data
++)
558 kwboot_img_patch_hdr(void *img
, size_t size
)
563 const size_t hdrsz
= sizeof(*hdr
);
573 csum
= kwboot_img_csum8(hdr
, hdrsz
) - hdr
->checkSum
;
574 if (csum
!= hdr
->checkSum
) {
579 if (hdr
->blockid
== IBR_HDR_UART_ID
) {
584 hdr
->blockid
= IBR_HDR_UART_ID
;
586 hdr
->nandeccmode
= IBR_HDR_ECC_DISABLED
;
587 hdr
->nandpagesize
= 0;
589 hdr
->srcaddr
= hdr
->ext
590 ? sizeof(struct kwb_header
)
593 hdr
->checkSum
= kwboot_img_csum8(hdr
, hdrsz
) - csum
;
601 kwboot_usage(FILE *stream
, char *progname
)
604 "Usage: %s -b <image> [ -p ] [ -t ] "
605 "[-B <baud> ] <TTY>\n", progname
);
606 fprintf(stream
, "\n");
607 fprintf(stream
, " -b <image>: boot <image>\n");
608 fprintf(stream
, " -p: patch <image> to type 0x69 (uart boot)\n");
609 fprintf(stream
, "\n");
610 fprintf(stream
, " -t: mini terminal\n");
611 fprintf(stream
, "\n");
612 fprintf(stream
, " -B <baud>: set baud rate\n");
613 fprintf(stream
, "\n");
617 main(int argc
, char **argv
)
619 const char *ttypath
, *imgpath
;
620 int rv
, rc
, tty
, term
, prot
, patch
;
636 kwboot_verbose
= isatty(STDOUT_FILENO
);
639 int c
= getopt(argc
, argv
, "hb:ptB:");
645 bootmsg
= kwboot_msg_boot
;
658 speed
= kwboot_tty_speed(atoi(optarg
));
670 if (!bootmsg
&& !term
)
673 if (patch
&& !imgpath
)
676 if (argc
- optind
< 1)
679 ttypath
= argv
[optind
++];
681 tty
= kwboot_open_tty(ttypath
, speed
);
688 prot
= PROT_READ
| (patch
? PROT_WRITE
: 0);
690 img
= kwboot_mmap_image(imgpath
, &size
, prot
);
698 rc
= kwboot_img_patch_hdr(img
, size
);
700 fprintf(stderr
, "%s: Invalid image.\n", imgpath
);
706 rc
= kwboot_bootmsg(tty
, bootmsg
);
714 rc
= kwboot_xmodem(tty
, img
, size
);
722 rc
= kwboot_terminal(tty
);
723 if (rc
&& !(errno
== EINTR
)) {
740 kwboot_usage(rv
? stderr
: stdout
, basename(argv
[0]));