1*d131ad68SLuka Perkov /* 2*d131ad68SLuka Perkov * Boot a Marvell Kirkwood SoC, with Xmodem over UART0. 3*d131ad68SLuka Perkov * 4*d131ad68SLuka Perkov * (c) 2012 Daniel Stodden <daniel.stodden@gmail.com> 5*d131ad68SLuka Perkov * 6*d131ad68SLuka Perkov * References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281 7*d131ad68SLuka Perkov * Integrated Controller: Functional Specifications" December 2, 8*d131ad68SLuka Perkov * 2008. Chapter 24.2 "BootROM Firmware". 9*d131ad68SLuka Perkov */ 10*d131ad68SLuka Perkov 11*d131ad68SLuka Perkov #include <stdlib.h> 12*d131ad68SLuka Perkov #include <stdio.h> 13*d131ad68SLuka Perkov #include <string.h> 14*d131ad68SLuka Perkov #include <stdarg.h> 15*d131ad68SLuka Perkov #include <libgen.h> 16*d131ad68SLuka Perkov #include <fcntl.h> 17*d131ad68SLuka Perkov #include <errno.h> 18*d131ad68SLuka Perkov #include <unistd.h> 19*d131ad68SLuka Perkov #include <stdint.h> 20*d131ad68SLuka Perkov #include <termios.h> 21*d131ad68SLuka Perkov #include <sys/mman.h> 22*d131ad68SLuka Perkov #include <sys/stat.h> 23*d131ad68SLuka Perkov 24*d131ad68SLuka Perkov #include "kwbimage.h" 25*d131ad68SLuka Perkov 26*d131ad68SLuka Perkov #ifdef __GNUC__ 27*d131ad68SLuka Perkov #define PACKED __attribute((packed)) 28*d131ad68SLuka Perkov #else 29*d131ad68SLuka Perkov #define PACKED 30*d131ad68SLuka Perkov #endif 31*d131ad68SLuka Perkov 32*d131ad68SLuka Perkov /* 33*d131ad68SLuka Perkov * Marvell BootROM UART Sensing 34*d131ad68SLuka Perkov */ 35*d131ad68SLuka Perkov 36*d131ad68SLuka Perkov static unsigned char kwboot_msg_boot[] = { 37*d131ad68SLuka Perkov 0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 38*d131ad68SLuka Perkov }; 39*d131ad68SLuka Perkov 40*d131ad68SLuka Perkov #define KWBOOT_MSG_REQ_DELAY 10 /* ms */ 41*d131ad68SLuka Perkov #define KWBOOT_MSG_RSP_TIMEO 50 /* ms */ 42*d131ad68SLuka Perkov 43*d131ad68SLuka Perkov /* 44*d131ad68SLuka Perkov * Xmodem Transfers 45*d131ad68SLuka Perkov */ 46*d131ad68SLuka Perkov 47*d131ad68SLuka Perkov #define SOH 1 /* sender start of block header */ 48*d131ad68SLuka Perkov #define EOT 4 /* sender end of block transfer */ 49*d131ad68SLuka Perkov #define ACK 6 /* target block ack */ 50*d131ad68SLuka Perkov #define NAK 21 /* target block negative ack */ 51*d131ad68SLuka Perkov #define CAN 24 /* target/sender transfer cancellation */ 52*d131ad68SLuka Perkov 53*d131ad68SLuka Perkov struct kwboot_block { 54*d131ad68SLuka Perkov uint8_t soh; 55*d131ad68SLuka Perkov uint8_t pnum; 56*d131ad68SLuka Perkov uint8_t _pnum; 57*d131ad68SLuka Perkov uint8_t data[128]; 58*d131ad68SLuka Perkov uint8_t csum; 59*d131ad68SLuka Perkov } PACKED; 60*d131ad68SLuka Perkov 61*d131ad68SLuka Perkov #define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */ 62*d131ad68SLuka Perkov 63*d131ad68SLuka Perkov static int kwboot_verbose; 64*d131ad68SLuka Perkov 65*d131ad68SLuka Perkov static void 66*d131ad68SLuka Perkov kwboot_printv(const char *fmt, ...) 67*d131ad68SLuka Perkov { 68*d131ad68SLuka Perkov va_list ap; 69*d131ad68SLuka Perkov 70*d131ad68SLuka Perkov if (kwboot_verbose) { 71*d131ad68SLuka Perkov va_start(ap, fmt); 72*d131ad68SLuka Perkov vprintf(fmt, ap); 73*d131ad68SLuka Perkov va_end(ap); 74*d131ad68SLuka Perkov fflush(stdout); 75*d131ad68SLuka Perkov } 76*d131ad68SLuka Perkov } 77*d131ad68SLuka Perkov 78*d131ad68SLuka Perkov static void 79*d131ad68SLuka Perkov __spinner(void) 80*d131ad68SLuka Perkov { 81*d131ad68SLuka Perkov const char seq[] = { '-', '\\', '|', '/' }; 82*d131ad68SLuka Perkov const int div = 8; 83*d131ad68SLuka Perkov static int state, bs; 84*d131ad68SLuka Perkov 85*d131ad68SLuka Perkov if (state % div == 0) { 86*d131ad68SLuka Perkov fputc(bs, stdout); 87*d131ad68SLuka Perkov fputc(seq[state / div % sizeof(seq)], stdout); 88*d131ad68SLuka Perkov fflush(stdout); 89*d131ad68SLuka Perkov } 90*d131ad68SLuka Perkov 91*d131ad68SLuka Perkov bs = '\b'; 92*d131ad68SLuka Perkov state++; 93*d131ad68SLuka Perkov } 94*d131ad68SLuka Perkov 95*d131ad68SLuka Perkov static void 96*d131ad68SLuka Perkov kwboot_spinner(void) 97*d131ad68SLuka Perkov { 98*d131ad68SLuka Perkov if (kwboot_verbose) 99*d131ad68SLuka Perkov __spinner(); 100*d131ad68SLuka Perkov } 101*d131ad68SLuka Perkov 102*d131ad68SLuka Perkov static void 103*d131ad68SLuka Perkov __progress(int pct, char c) 104*d131ad68SLuka Perkov { 105*d131ad68SLuka Perkov const int width = 70; 106*d131ad68SLuka Perkov static const char *nl = ""; 107*d131ad68SLuka Perkov static int pos; 108*d131ad68SLuka Perkov 109*d131ad68SLuka Perkov if (pos % width == 0) 110*d131ad68SLuka Perkov printf("%s%3d %% [", nl, pct); 111*d131ad68SLuka Perkov 112*d131ad68SLuka Perkov fputc(c, stdout); 113*d131ad68SLuka Perkov 114*d131ad68SLuka Perkov nl = "]\n"; 115*d131ad68SLuka Perkov pos++; 116*d131ad68SLuka Perkov 117*d131ad68SLuka Perkov if (pct == 100) { 118*d131ad68SLuka Perkov while (pos++ < width) 119*d131ad68SLuka Perkov fputc(' ', stdout); 120*d131ad68SLuka Perkov fputs(nl, stdout); 121*d131ad68SLuka Perkov } 122*d131ad68SLuka Perkov 123*d131ad68SLuka Perkov fflush(stdout); 124*d131ad68SLuka Perkov 125*d131ad68SLuka Perkov } 126*d131ad68SLuka Perkov 127*d131ad68SLuka Perkov static void 128*d131ad68SLuka Perkov kwboot_progress(int _pct, char c) 129*d131ad68SLuka Perkov { 130*d131ad68SLuka Perkov static int pct; 131*d131ad68SLuka Perkov 132*d131ad68SLuka Perkov if (_pct != -1) 133*d131ad68SLuka Perkov pct = _pct; 134*d131ad68SLuka Perkov 135*d131ad68SLuka Perkov if (kwboot_verbose) 136*d131ad68SLuka Perkov __progress(pct, c); 137*d131ad68SLuka Perkov } 138*d131ad68SLuka Perkov 139*d131ad68SLuka Perkov static int 140*d131ad68SLuka Perkov kwboot_tty_recv(int fd, void *buf, size_t len, int timeo) 141*d131ad68SLuka Perkov { 142*d131ad68SLuka Perkov int rc, nfds; 143*d131ad68SLuka Perkov fd_set rfds; 144*d131ad68SLuka Perkov struct timeval tv; 145*d131ad68SLuka Perkov ssize_t n; 146*d131ad68SLuka Perkov 147*d131ad68SLuka Perkov rc = -1; 148*d131ad68SLuka Perkov 149*d131ad68SLuka Perkov FD_ZERO(&rfds); 150*d131ad68SLuka Perkov FD_SET(fd, &rfds); 151*d131ad68SLuka Perkov 152*d131ad68SLuka Perkov tv.tv_sec = 0; 153*d131ad68SLuka Perkov tv.tv_usec = timeo * 1000; 154*d131ad68SLuka Perkov if (tv.tv_usec > 1000000) { 155*d131ad68SLuka Perkov tv.tv_sec += tv.tv_usec / 1000000; 156*d131ad68SLuka Perkov tv.tv_usec %= 1000000; 157*d131ad68SLuka Perkov } 158*d131ad68SLuka Perkov 159*d131ad68SLuka Perkov do { 160*d131ad68SLuka Perkov nfds = select(fd + 1, &rfds, NULL, NULL, &tv); 161*d131ad68SLuka Perkov if (nfds < 0) 162*d131ad68SLuka Perkov goto out; 163*d131ad68SLuka Perkov if (!nfds) { 164*d131ad68SLuka Perkov errno = ETIMEDOUT; 165*d131ad68SLuka Perkov goto out; 166*d131ad68SLuka Perkov } 167*d131ad68SLuka Perkov 168*d131ad68SLuka Perkov n = read(fd, buf, len); 169*d131ad68SLuka Perkov if (n < 0) 170*d131ad68SLuka Perkov goto out; 171*d131ad68SLuka Perkov 172*d131ad68SLuka Perkov buf = (char *)buf + n; 173*d131ad68SLuka Perkov len -= n; 174*d131ad68SLuka Perkov } while (len > 0); 175*d131ad68SLuka Perkov 176*d131ad68SLuka Perkov rc = 0; 177*d131ad68SLuka Perkov out: 178*d131ad68SLuka Perkov return rc; 179*d131ad68SLuka Perkov } 180*d131ad68SLuka Perkov 181*d131ad68SLuka Perkov static int 182*d131ad68SLuka Perkov kwboot_tty_send(int fd, const void *buf, size_t len) 183*d131ad68SLuka Perkov { 184*d131ad68SLuka Perkov int rc; 185*d131ad68SLuka Perkov ssize_t n; 186*d131ad68SLuka Perkov 187*d131ad68SLuka Perkov rc = -1; 188*d131ad68SLuka Perkov 189*d131ad68SLuka Perkov do { 190*d131ad68SLuka Perkov n = write(fd, buf, len); 191*d131ad68SLuka Perkov if (n < 0) 192*d131ad68SLuka Perkov goto out; 193*d131ad68SLuka Perkov 194*d131ad68SLuka Perkov buf = (char *)buf + n; 195*d131ad68SLuka Perkov len -= n; 196*d131ad68SLuka Perkov } while (len > 0); 197*d131ad68SLuka Perkov 198*d131ad68SLuka Perkov rc = tcdrain(fd); 199*d131ad68SLuka Perkov out: 200*d131ad68SLuka Perkov return rc; 201*d131ad68SLuka Perkov } 202*d131ad68SLuka Perkov 203*d131ad68SLuka Perkov static int 204*d131ad68SLuka Perkov kwboot_tty_send_char(int fd, unsigned char c) 205*d131ad68SLuka Perkov { 206*d131ad68SLuka Perkov return kwboot_tty_send(fd, &c, 1); 207*d131ad68SLuka Perkov } 208*d131ad68SLuka Perkov 209*d131ad68SLuka Perkov static speed_t 210*d131ad68SLuka Perkov kwboot_tty_speed(int baudrate) 211*d131ad68SLuka Perkov { 212*d131ad68SLuka Perkov switch (baudrate) { 213*d131ad68SLuka Perkov case 115200: 214*d131ad68SLuka Perkov return B115200; 215*d131ad68SLuka Perkov case 57600: 216*d131ad68SLuka Perkov return B57600; 217*d131ad68SLuka Perkov case 38400: 218*d131ad68SLuka Perkov return B38400; 219*d131ad68SLuka Perkov case 19200: 220*d131ad68SLuka Perkov return B19200; 221*d131ad68SLuka Perkov case 9600: 222*d131ad68SLuka Perkov return B9600; 223*d131ad68SLuka Perkov } 224*d131ad68SLuka Perkov 225*d131ad68SLuka Perkov return -1; 226*d131ad68SLuka Perkov } 227*d131ad68SLuka Perkov 228*d131ad68SLuka Perkov static int 229*d131ad68SLuka Perkov kwboot_open_tty(const char *path, speed_t speed) 230*d131ad68SLuka Perkov { 231*d131ad68SLuka Perkov int rc, fd; 232*d131ad68SLuka Perkov struct termios tio; 233*d131ad68SLuka Perkov 234*d131ad68SLuka Perkov rc = -1; 235*d131ad68SLuka Perkov 236*d131ad68SLuka Perkov fd = open(path, O_RDWR|O_NOCTTY|O_NDELAY); 237*d131ad68SLuka Perkov if (fd < 0) 238*d131ad68SLuka Perkov goto out; 239*d131ad68SLuka Perkov 240*d131ad68SLuka Perkov memset(&tio, 0, sizeof(tio)); 241*d131ad68SLuka Perkov 242*d131ad68SLuka Perkov tio.c_iflag = 0; 243*d131ad68SLuka Perkov tio.c_cflag = CREAD|CLOCAL|CS8; 244*d131ad68SLuka Perkov 245*d131ad68SLuka Perkov tio.c_cc[VMIN] = 1; 246*d131ad68SLuka Perkov tio.c_cc[VTIME] = 10; 247*d131ad68SLuka Perkov 248*d131ad68SLuka Perkov cfsetospeed(&tio, speed); 249*d131ad68SLuka Perkov cfsetispeed(&tio, speed); 250*d131ad68SLuka Perkov 251*d131ad68SLuka Perkov rc = tcsetattr(fd, TCSANOW, &tio); 252*d131ad68SLuka Perkov if (rc) 253*d131ad68SLuka Perkov goto out; 254*d131ad68SLuka Perkov 255*d131ad68SLuka Perkov rc = fd; 256*d131ad68SLuka Perkov out: 257*d131ad68SLuka Perkov if (rc < 0) { 258*d131ad68SLuka Perkov if (fd >= 0) 259*d131ad68SLuka Perkov close(fd); 260*d131ad68SLuka Perkov } 261*d131ad68SLuka Perkov 262*d131ad68SLuka Perkov return rc; 263*d131ad68SLuka Perkov } 264*d131ad68SLuka Perkov 265*d131ad68SLuka Perkov static int 266*d131ad68SLuka Perkov kwboot_bootmsg(int tty, void *msg) 267*d131ad68SLuka Perkov { 268*d131ad68SLuka Perkov int rc; 269*d131ad68SLuka Perkov char c; 270*d131ad68SLuka Perkov 271*d131ad68SLuka Perkov kwboot_printv("Sending boot message. Please reboot the target..."); 272*d131ad68SLuka Perkov 273*d131ad68SLuka Perkov do { 274*d131ad68SLuka Perkov rc = tcflush(tty, TCIOFLUSH); 275*d131ad68SLuka Perkov if (rc) 276*d131ad68SLuka Perkov break; 277*d131ad68SLuka Perkov 278*d131ad68SLuka Perkov rc = kwboot_tty_send(tty, msg, 8); 279*d131ad68SLuka Perkov if (rc) { 280*d131ad68SLuka Perkov usleep(KWBOOT_MSG_REQ_DELAY * 1000); 281*d131ad68SLuka Perkov continue; 282*d131ad68SLuka Perkov } 283*d131ad68SLuka Perkov 284*d131ad68SLuka Perkov rc = kwboot_tty_recv(tty, &c, 1, KWBOOT_MSG_RSP_TIMEO); 285*d131ad68SLuka Perkov 286*d131ad68SLuka Perkov kwboot_spinner(); 287*d131ad68SLuka Perkov 288*d131ad68SLuka Perkov } while (rc || c != NAK); 289*d131ad68SLuka Perkov 290*d131ad68SLuka Perkov kwboot_printv("\n"); 291*d131ad68SLuka Perkov 292*d131ad68SLuka Perkov return rc; 293*d131ad68SLuka Perkov } 294*d131ad68SLuka Perkov 295*d131ad68SLuka Perkov static int 296*d131ad68SLuka Perkov kwboot_xm_makeblock(struct kwboot_block *block, const void *data, 297*d131ad68SLuka Perkov size_t size, int pnum) 298*d131ad68SLuka Perkov { 299*d131ad68SLuka Perkov const size_t blksz = sizeof(block->data); 300*d131ad68SLuka Perkov size_t n; 301*d131ad68SLuka Perkov int i; 302*d131ad68SLuka Perkov 303*d131ad68SLuka Perkov block->pnum = pnum; 304*d131ad68SLuka Perkov block->_pnum = ~block->pnum; 305*d131ad68SLuka Perkov 306*d131ad68SLuka Perkov n = size < blksz ? size : blksz; 307*d131ad68SLuka Perkov memcpy(&block->data[0], data, n); 308*d131ad68SLuka Perkov memset(&block->data[n], 0, blksz - n); 309*d131ad68SLuka Perkov 310*d131ad68SLuka Perkov block->csum = 0; 311*d131ad68SLuka Perkov for (i = 0; i < n; i++) 312*d131ad68SLuka Perkov block->csum += block->data[i]; 313*d131ad68SLuka Perkov 314*d131ad68SLuka Perkov return n; 315*d131ad68SLuka Perkov } 316*d131ad68SLuka Perkov 317*d131ad68SLuka Perkov static int 318*d131ad68SLuka Perkov kwboot_xm_sendblock(int fd, struct kwboot_block *block) 319*d131ad68SLuka Perkov { 320*d131ad68SLuka Perkov int rc, retries; 321*d131ad68SLuka Perkov char c; 322*d131ad68SLuka Perkov 323*d131ad68SLuka Perkov retries = 16; 324*d131ad68SLuka Perkov do { 325*d131ad68SLuka Perkov rc = kwboot_tty_send(fd, block, sizeof(*block)); 326*d131ad68SLuka Perkov if (rc) 327*d131ad68SLuka Perkov break; 328*d131ad68SLuka Perkov 329*d131ad68SLuka Perkov rc = kwboot_tty_recv(fd, &c, 1, KWBOOT_BLK_RSP_TIMEO); 330*d131ad68SLuka Perkov if (rc) 331*d131ad68SLuka Perkov break; 332*d131ad68SLuka Perkov 333*d131ad68SLuka Perkov if (c != ACK) 334*d131ad68SLuka Perkov kwboot_progress(-1, '+'); 335*d131ad68SLuka Perkov 336*d131ad68SLuka Perkov } while (c == NAK && retries-- > 0); 337*d131ad68SLuka Perkov 338*d131ad68SLuka Perkov rc = -1; 339*d131ad68SLuka Perkov 340*d131ad68SLuka Perkov switch (c) { 341*d131ad68SLuka Perkov case ACK: 342*d131ad68SLuka Perkov rc = 0; 343*d131ad68SLuka Perkov break; 344*d131ad68SLuka Perkov case NAK: 345*d131ad68SLuka Perkov errno = EBADMSG; 346*d131ad68SLuka Perkov break; 347*d131ad68SLuka Perkov case CAN: 348*d131ad68SLuka Perkov errno = ECANCELED; 349*d131ad68SLuka Perkov break; 350*d131ad68SLuka Perkov default: 351*d131ad68SLuka Perkov errno = EPROTO; 352*d131ad68SLuka Perkov break; 353*d131ad68SLuka Perkov } 354*d131ad68SLuka Perkov 355*d131ad68SLuka Perkov return rc; 356*d131ad68SLuka Perkov } 357*d131ad68SLuka Perkov 358*d131ad68SLuka Perkov static int 359*d131ad68SLuka Perkov kwboot_xmodem(int tty, const void *_data, size_t size) 360*d131ad68SLuka Perkov { 361*d131ad68SLuka Perkov const uint8_t *data = _data; 362*d131ad68SLuka Perkov int rc, pnum, N, err; 363*d131ad68SLuka Perkov 364*d131ad68SLuka Perkov pnum = 1; 365*d131ad68SLuka Perkov N = 0; 366*d131ad68SLuka Perkov 367*d131ad68SLuka Perkov kwboot_printv("Sending boot image...\n"); 368*d131ad68SLuka Perkov 369*d131ad68SLuka Perkov do { 370*d131ad68SLuka Perkov struct kwboot_block block; 371*d131ad68SLuka Perkov int n; 372*d131ad68SLuka Perkov 373*d131ad68SLuka Perkov n = kwboot_xm_makeblock(&block, 374*d131ad68SLuka Perkov data + N, size - N, 375*d131ad68SLuka Perkov pnum++); 376*d131ad68SLuka Perkov if (n < 0) 377*d131ad68SLuka Perkov goto can; 378*d131ad68SLuka Perkov 379*d131ad68SLuka Perkov if (!n) 380*d131ad68SLuka Perkov break; 381*d131ad68SLuka Perkov 382*d131ad68SLuka Perkov rc = kwboot_xm_sendblock(tty, &block); 383*d131ad68SLuka Perkov if (rc) 384*d131ad68SLuka Perkov goto out; 385*d131ad68SLuka Perkov 386*d131ad68SLuka Perkov N += n; 387*d131ad68SLuka Perkov kwboot_progress(N * 100 / size, '.'); 388*d131ad68SLuka Perkov } while (1); 389*d131ad68SLuka Perkov 390*d131ad68SLuka Perkov rc = kwboot_tty_send_char(tty, EOT); 391*d131ad68SLuka Perkov 392*d131ad68SLuka Perkov out: 393*d131ad68SLuka Perkov return rc; 394*d131ad68SLuka Perkov 395*d131ad68SLuka Perkov can: 396*d131ad68SLuka Perkov err = errno; 397*d131ad68SLuka Perkov kwboot_tty_send_char(tty, CAN); 398*d131ad68SLuka Perkov errno = err; 399*d131ad68SLuka Perkov goto out; 400*d131ad68SLuka Perkov } 401*d131ad68SLuka Perkov 402*d131ad68SLuka Perkov static int 403*d131ad68SLuka Perkov kwboot_term_pipe(int in, int out, char *quit, int *s) 404*d131ad68SLuka Perkov { 405*d131ad68SLuka Perkov ssize_t nin, nout; 406*d131ad68SLuka Perkov char _buf[128], *buf = _buf; 407*d131ad68SLuka Perkov 408*d131ad68SLuka Perkov nin = read(in, buf, sizeof(buf)); 409*d131ad68SLuka Perkov if (nin < 0) 410*d131ad68SLuka Perkov return -1; 411*d131ad68SLuka Perkov 412*d131ad68SLuka Perkov if (quit) { 413*d131ad68SLuka Perkov int i; 414*d131ad68SLuka Perkov 415*d131ad68SLuka Perkov for (i = 0; i < nin; i++) { 416*d131ad68SLuka Perkov if (*buf == quit[*s]) { 417*d131ad68SLuka Perkov (*s)++; 418*d131ad68SLuka Perkov if (!quit[*s]) 419*d131ad68SLuka Perkov return 0; 420*d131ad68SLuka Perkov buf++; 421*d131ad68SLuka Perkov nin--; 422*d131ad68SLuka Perkov } else 423*d131ad68SLuka Perkov while (*s > 0) { 424*d131ad68SLuka Perkov nout = write(out, quit, *s); 425*d131ad68SLuka Perkov if (nout <= 0) 426*d131ad68SLuka Perkov return -1; 427*d131ad68SLuka Perkov (*s) -= nout; 428*d131ad68SLuka Perkov } 429*d131ad68SLuka Perkov } 430*d131ad68SLuka Perkov } 431*d131ad68SLuka Perkov 432*d131ad68SLuka Perkov while (nin > 0) { 433*d131ad68SLuka Perkov nout = write(out, buf, nin); 434*d131ad68SLuka Perkov if (nout <= 0) 435*d131ad68SLuka Perkov return -1; 436*d131ad68SLuka Perkov nin -= nout; 437*d131ad68SLuka Perkov } 438*d131ad68SLuka Perkov 439*d131ad68SLuka Perkov return 0; 440*d131ad68SLuka Perkov } 441*d131ad68SLuka Perkov 442*d131ad68SLuka Perkov static int 443*d131ad68SLuka Perkov kwboot_terminal(int tty) 444*d131ad68SLuka Perkov { 445*d131ad68SLuka Perkov int rc, in, s; 446*d131ad68SLuka Perkov char *quit = "\34c"; 447*d131ad68SLuka Perkov struct termios otio, tio; 448*d131ad68SLuka Perkov 449*d131ad68SLuka Perkov rc = -1; 450*d131ad68SLuka Perkov 451*d131ad68SLuka Perkov in = STDIN_FILENO; 452*d131ad68SLuka Perkov if (isatty(in)) { 453*d131ad68SLuka Perkov rc = tcgetattr(in, &otio); 454*d131ad68SLuka Perkov if (!rc) { 455*d131ad68SLuka Perkov tio = otio; 456*d131ad68SLuka Perkov cfmakeraw(&tio); 457*d131ad68SLuka Perkov rc = tcsetattr(in, TCSANOW, &tio); 458*d131ad68SLuka Perkov } 459*d131ad68SLuka Perkov if (rc) { 460*d131ad68SLuka Perkov perror("tcsetattr"); 461*d131ad68SLuka Perkov goto out; 462*d131ad68SLuka Perkov } 463*d131ad68SLuka Perkov 464*d131ad68SLuka Perkov kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n", 465*d131ad68SLuka Perkov quit[0]|0100, quit[1]); 466*d131ad68SLuka Perkov } else 467*d131ad68SLuka Perkov in = -1; 468*d131ad68SLuka Perkov 469*d131ad68SLuka Perkov rc = 0; 470*d131ad68SLuka Perkov s = 0; 471*d131ad68SLuka Perkov 472*d131ad68SLuka Perkov do { 473*d131ad68SLuka Perkov fd_set rfds; 474*d131ad68SLuka Perkov int nfds = 0; 475*d131ad68SLuka Perkov 476*d131ad68SLuka Perkov FD_SET(tty, &rfds); 477*d131ad68SLuka Perkov nfds = nfds < tty ? tty : nfds; 478*d131ad68SLuka Perkov 479*d131ad68SLuka Perkov if (in >= 0) { 480*d131ad68SLuka Perkov FD_SET(in, &rfds); 481*d131ad68SLuka Perkov nfds = nfds < in ? in : nfds; 482*d131ad68SLuka Perkov } 483*d131ad68SLuka Perkov 484*d131ad68SLuka Perkov nfds = select(nfds + 1, &rfds, NULL, NULL, NULL); 485*d131ad68SLuka Perkov if (nfds < 0) 486*d131ad68SLuka Perkov break; 487*d131ad68SLuka Perkov 488*d131ad68SLuka Perkov if (FD_ISSET(tty, &rfds)) { 489*d131ad68SLuka Perkov rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL); 490*d131ad68SLuka Perkov if (rc) 491*d131ad68SLuka Perkov break; 492*d131ad68SLuka Perkov } 493*d131ad68SLuka Perkov 494*d131ad68SLuka Perkov if (FD_ISSET(in, &rfds)) { 495*d131ad68SLuka Perkov rc = kwboot_term_pipe(in, tty, quit, &s); 496*d131ad68SLuka Perkov if (rc) 497*d131ad68SLuka Perkov break; 498*d131ad68SLuka Perkov } 499*d131ad68SLuka Perkov } while (quit[s] != 0); 500*d131ad68SLuka Perkov 501*d131ad68SLuka Perkov tcsetattr(in, TCSANOW, &otio); 502*d131ad68SLuka Perkov out: 503*d131ad68SLuka Perkov return rc; 504*d131ad68SLuka Perkov } 505*d131ad68SLuka Perkov 506*d131ad68SLuka Perkov static void * 507*d131ad68SLuka Perkov kwboot_mmap_image(const char *path, size_t *size, int prot) 508*d131ad68SLuka Perkov { 509*d131ad68SLuka Perkov int rc, fd, flags; 510*d131ad68SLuka Perkov struct stat st; 511*d131ad68SLuka Perkov void *img; 512*d131ad68SLuka Perkov 513*d131ad68SLuka Perkov rc = -1; 514*d131ad68SLuka Perkov fd = -1; 515*d131ad68SLuka Perkov img = NULL; 516*d131ad68SLuka Perkov 517*d131ad68SLuka Perkov fd = open(path, O_RDONLY); 518*d131ad68SLuka Perkov if (fd < 0) 519*d131ad68SLuka Perkov goto out; 520*d131ad68SLuka Perkov 521*d131ad68SLuka Perkov rc = fstat(fd, &st); 522*d131ad68SLuka Perkov if (rc) 523*d131ad68SLuka Perkov goto out; 524*d131ad68SLuka Perkov 525*d131ad68SLuka Perkov flags = (prot & PROT_WRITE) ? MAP_PRIVATE : MAP_SHARED; 526*d131ad68SLuka Perkov 527*d131ad68SLuka Perkov img = mmap(NULL, st.st_size, prot, flags, fd, 0); 528*d131ad68SLuka Perkov if (img == MAP_FAILED) { 529*d131ad68SLuka Perkov img = NULL; 530*d131ad68SLuka Perkov goto out; 531*d131ad68SLuka Perkov } 532*d131ad68SLuka Perkov 533*d131ad68SLuka Perkov rc = 0; 534*d131ad68SLuka Perkov *size = st.st_size; 535*d131ad68SLuka Perkov out: 536*d131ad68SLuka Perkov if (rc && img) { 537*d131ad68SLuka Perkov munmap(img, st.st_size); 538*d131ad68SLuka Perkov img = NULL; 539*d131ad68SLuka Perkov } 540*d131ad68SLuka Perkov if (fd >= 0) 541*d131ad68SLuka Perkov close(fd); 542*d131ad68SLuka Perkov 543*d131ad68SLuka Perkov return img; 544*d131ad68SLuka Perkov } 545*d131ad68SLuka Perkov 546*d131ad68SLuka Perkov static uint8_t 547*d131ad68SLuka Perkov kwboot_img_csum8(void *_data, size_t size) 548*d131ad68SLuka Perkov { 549*d131ad68SLuka Perkov uint8_t *data = _data, csum; 550*d131ad68SLuka Perkov 551*d131ad68SLuka Perkov for (csum = 0; size-- > 0; data++) 552*d131ad68SLuka Perkov csum += *data; 553*d131ad68SLuka Perkov 554*d131ad68SLuka Perkov return csum; 555*d131ad68SLuka Perkov } 556*d131ad68SLuka Perkov 557*d131ad68SLuka Perkov static int 558*d131ad68SLuka Perkov kwboot_img_patch_hdr(void *img, size_t size) 559*d131ad68SLuka Perkov { 560*d131ad68SLuka Perkov int rc; 561*d131ad68SLuka Perkov bhr_t *hdr; 562*d131ad68SLuka Perkov uint8_t csum; 563*d131ad68SLuka Perkov const size_t hdrsz = sizeof(*hdr); 564*d131ad68SLuka Perkov 565*d131ad68SLuka Perkov rc = -1; 566*d131ad68SLuka Perkov hdr = img; 567*d131ad68SLuka Perkov 568*d131ad68SLuka Perkov if (size < hdrsz) { 569*d131ad68SLuka Perkov errno = EINVAL; 570*d131ad68SLuka Perkov goto out; 571*d131ad68SLuka Perkov } 572*d131ad68SLuka Perkov 573*d131ad68SLuka Perkov csum = kwboot_img_csum8(hdr, hdrsz) - hdr->checkSum; 574*d131ad68SLuka Perkov if (csum != hdr->checkSum) { 575*d131ad68SLuka Perkov errno = EINVAL; 576*d131ad68SLuka Perkov goto out; 577*d131ad68SLuka Perkov } 578*d131ad68SLuka Perkov 579*d131ad68SLuka Perkov if (hdr->blockid == IBR_HDR_UART_ID) { 580*d131ad68SLuka Perkov rc = 0; 581*d131ad68SLuka Perkov goto out; 582*d131ad68SLuka Perkov } 583*d131ad68SLuka Perkov 584*d131ad68SLuka Perkov hdr->blockid = IBR_HDR_UART_ID; 585*d131ad68SLuka Perkov 586*d131ad68SLuka Perkov hdr->nandeccmode = IBR_HDR_ECC_DISABLED; 587*d131ad68SLuka Perkov hdr->nandpagesize = 0; 588*d131ad68SLuka Perkov 589*d131ad68SLuka Perkov hdr->srcaddr = hdr->ext 590*d131ad68SLuka Perkov ? sizeof(struct kwb_header) 591*d131ad68SLuka Perkov : sizeof(*hdr); 592*d131ad68SLuka Perkov 593*d131ad68SLuka Perkov hdr->checkSum = kwboot_img_csum8(hdr, hdrsz) - csum; 594*d131ad68SLuka Perkov 595*d131ad68SLuka Perkov rc = 0; 596*d131ad68SLuka Perkov out: 597*d131ad68SLuka Perkov return rc; 598*d131ad68SLuka Perkov } 599*d131ad68SLuka Perkov 600*d131ad68SLuka Perkov static void 601*d131ad68SLuka Perkov kwboot_usage(FILE *stream, char *progname) 602*d131ad68SLuka Perkov { 603*d131ad68SLuka Perkov fprintf(stream, 604*d131ad68SLuka Perkov "Usage: %s -b <image> [ -p ] [ -t ] " 605*d131ad68SLuka Perkov "[-B <baud> ] <TTY>\n", progname); 606*d131ad68SLuka Perkov fprintf(stream, "\n"); 607*d131ad68SLuka Perkov fprintf(stream, " -b <image>: boot <image>\n"); 608*d131ad68SLuka Perkov fprintf(stream, " -p: patch <image> to type 0x69 (uart boot)\n"); 609*d131ad68SLuka Perkov fprintf(stream, "\n"); 610*d131ad68SLuka Perkov fprintf(stream, " -t: mini terminal\n"); 611*d131ad68SLuka Perkov fprintf(stream, "\n"); 612*d131ad68SLuka Perkov fprintf(stream, " -B <baud>: set baud rate\n"); 613*d131ad68SLuka Perkov fprintf(stream, "\n"); 614*d131ad68SLuka Perkov } 615*d131ad68SLuka Perkov 616*d131ad68SLuka Perkov int 617*d131ad68SLuka Perkov main(int argc, char **argv) 618*d131ad68SLuka Perkov { 619*d131ad68SLuka Perkov const char *ttypath, *imgpath; 620*d131ad68SLuka Perkov int rv, rc, tty, term, prot, patch; 621*d131ad68SLuka Perkov void *bootmsg; 622*d131ad68SLuka Perkov void *img; 623*d131ad68SLuka Perkov size_t size; 624*d131ad68SLuka Perkov speed_t speed; 625*d131ad68SLuka Perkov 626*d131ad68SLuka Perkov rv = 1; 627*d131ad68SLuka Perkov tty = -1; 628*d131ad68SLuka Perkov bootmsg = NULL; 629*d131ad68SLuka Perkov imgpath = NULL; 630*d131ad68SLuka Perkov img = NULL; 631*d131ad68SLuka Perkov term = 0; 632*d131ad68SLuka Perkov patch = 0; 633*d131ad68SLuka Perkov size = 0; 634*d131ad68SLuka Perkov speed = B115200; 635*d131ad68SLuka Perkov 636*d131ad68SLuka Perkov kwboot_verbose = isatty(STDOUT_FILENO); 637*d131ad68SLuka Perkov 638*d131ad68SLuka Perkov do { 639*d131ad68SLuka Perkov int c = getopt(argc, argv, "hb:ptB:"); 640*d131ad68SLuka Perkov if (c < 0) 641*d131ad68SLuka Perkov break; 642*d131ad68SLuka Perkov 643*d131ad68SLuka Perkov switch (c) { 644*d131ad68SLuka Perkov case 'b': 645*d131ad68SLuka Perkov bootmsg = kwboot_msg_boot; 646*d131ad68SLuka Perkov imgpath = optarg; 647*d131ad68SLuka Perkov break; 648*d131ad68SLuka Perkov 649*d131ad68SLuka Perkov case 'p': 650*d131ad68SLuka Perkov patch = 1; 651*d131ad68SLuka Perkov break; 652*d131ad68SLuka Perkov 653*d131ad68SLuka Perkov case 't': 654*d131ad68SLuka Perkov term = 1; 655*d131ad68SLuka Perkov break; 656*d131ad68SLuka Perkov 657*d131ad68SLuka Perkov case 'B': 658*d131ad68SLuka Perkov speed = kwboot_tty_speed(atoi(optarg)); 659*d131ad68SLuka Perkov if (speed == -1) 660*d131ad68SLuka Perkov goto usage; 661*d131ad68SLuka Perkov break; 662*d131ad68SLuka Perkov 663*d131ad68SLuka Perkov case 'h': 664*d131ad68SLuka Perkov rv = 0; 665*d131ad68SLuka Perkov default: 666*d131ad68SLuka Perkov goto usage; 667*d131ad68SLuka Perkov } 668*d131ad68SLuka Perkov } while (1); 669*d131ad68SLuka Perkov 670*d131ad68SLuka Perkov if (!bootmsg && !term) 671*d131ad68SLuka Perkov goto usage; 672*d131ad68SLuka Perkov 673*d131ad68SLuka Perkov if (patch && !imgpath) 674*d131ad68SLuka Perkov goto usage; 675*d131ad68SLuka Perkov 676*d131ad68SLuka Perkov if (argc - optind < 1) 677*d131ad68SLuka Perkov goto usage; 678*d131ad68SLuka Perkov 679*d131ad68SLuka Perkov ttypath = argv[optind++]; 680*d131ad68SLuka Perkov 681*d131ad68SLuka Perkov tty = kwboot_open_tty(ttypath, speed); 682*d131ad68SLuka Perkov if (tty < 0) { 683*d131ad68SLuka Perkov perror(ttypath); 684*d131ad68SLuka Perkov goto out; 685*d131ad68SLuka Perkov } 686*d131ad68SLuka Perkov 687*d131ad68SLuka Perkov if (imgpath) { 688*d131ad68SLuka Perkov prot = PROT_READ | (patch ? PROT_WRITE : 0); 689*d131ad68SLuka Perkov 690*d131ad68SLuka Perkov img = kwboot_mmap_image(imgpath, &size, prot); 691*d131ad68SLuka Perkov if (!img) { 692*d131ad68SLuka Perkov perror(imgpath); 693*d131ad68SLuka Perkov goto out; 694*d131ad68SLuka Perkov } 695*d131ad68SLuka Perkov } 696*d131ad68SLuka Perkov 697*d131ad68SLuka Perkov if (patch) { 698*d131ad68SLuka Perkov rc = kwboot_img_patch_hdr(img, size); 699*d131ad68SLuka Perkov if (rc) { 700*d131ad68SLuka Perkov fprintf(stderr, "%s: Invalid image.\n", imgpath); 701*d131ad68SLuka Perkov goto out; 702*d131ad68SLuka Perkov } 703*d131ad68SLuka Perkov } 704*d131ad68SLuka Perkov 705*d131ad68SLuka Perkov if (bootmsg) { 706*d131ad68SLuka Perkov rc = kwboot_bootmsg(tty, bootmsg); 707*d131ad68SLuka Perkov if (rc) { 708*d131ad68SLuka Perkov perror("bootmsg"); 709*d131ad68SLuka Perkov goto out; 710*d131ad68SLuka Perkov } 711*d131ad68SLuka Perkov } 712*d131ad68SLuka Perkov 713*d131ad68SLuka Perkov if (img) { 714*d131ad68SLuka Perkov rc = kwboot_xmodem(tty, img, size); 715*d131ad68SLuka Perkov if (rc) { 716*d131ad68SLuka Perkov perror("xmodem"); 717*d131ad68SLuka Perkov goto out; 718*d131ad68SLuka Perkov } 719*d131ad68SLuka Perkov } 720*d131ad68SLuka Perkov 721*d131ad68SLuka Perkov if (term) { 722*d131ad68SLuka Perkov rc = kwboot_terminal(tty); 723*d131ad68SLuka Perkov if (rc && !(errno == EINTR)) { 724*d131ad68SLuka Perkov perror("terminal"); 725*d131ad68SLuka Perkov goto out; 726*d131ad68SLuka Perkov } 727*d131ad68SLuka Perkov } 728*d131ad68SLuka Perkov 729*d131ad68SLuka Perkov rv = 0; 730*d131ad68SLuka Perkov out: 731*d131ad68SLuka Perkov if (tty >= 0) 732*d131ad68SLuka Perkov close(tty); 733*d131ad68SLuka Perkov 734*d131ad68SLuka Perkov if (img) 735*d131ad68SLuka Perkov munmap(img, size); 736*d131ad68SLuka Perkov 737*d131ad68SLuka Perkov return rv; 738*d131ad68SLuka Perkov 739*d131ad68SLuka Perkov usage: 740*d131ad68SLuka Perkov kwboot_usage(rv ? stderr : stdout, basename(argv[0])); 741*d131ad68SLuka Perkov goto out; 742*d131ad68SLuka Perkov } 743