1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40#include "kwbimage.h"
41#include "mkimage.h"
42#include "version.h"
43
44#include <stdlib.h>
45#include <stdio.h>
46#include <string.h>
47#include <stdarg.h>
48#include <image.h>
49#include <libgen.h>
50#include <fcntl.h>
51#include <errno.h>
52#include <unistd.h>
53#include <stdint.h>
54#include <time.h>
55#include <sys/stat.h>
56#include <pthread.h>
57
58#ifdef __linux__
59#include "termios_linux.h"
60#else
61#include <termios.h>
62#endif
63
64
65
66
67
68extern int setupterm(const char *, int, int *);
69extern char *tigetstr(const char *);
70
71
72
73
74
75static unsigned char kwboot_msg_boot[] = {
76 0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
77};
78
79static unsigned char kwboot_msg_debug[] = {
80 0xDD, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
81};
82
83
84#define KWBOOT_MSG_RSP_TIMEO 50
85
86
87#define KWBOOT_MSG_RSP_TIMEO_AXP 10
88
89
90
91
92
93#define SOH 1
94#define EOT 4
95#define ACK 6
96#define NAK 21
97
98#define KWBOOT_XM_BLKSZ 128
99
100struct kwboot_block {
101 uint8_t soh;
102 uint8_t pnum;
103 uint8_t _pnum;
104 uint8_t data[KWBOOT_XM_BLKSZ];
105 uint8_t csum;
106} __packed;
107
108#define KWBOOT_BLK_RSP_TIMEO 2000
109#define KWBOOT_HDR_RSP_TIMEO 10000
110
111
112static unsigned char kwboot_baud_code[] = {
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 0x0d, 0x02, 0xa0, 0xe3,
143 0x12, 0x0a, 0x80, 0xe3,
144
145
146
147
148 0x14, 0x10, 0x90, 0xe5,
149 0x40, 0x00, 0x11, 0xe3,
150 0xfc, 0xff, 0xff, 0x0a,
151
152
153
154 0x0c, 0x10, 0x90, 0xe5,
155 0x80, 0x10, 0x81, 0xe3,
156 0x0c, 0x10, 0x80, 0xe5,
157
158
159
160 0x00, 0x10, 0x90, 0xe5,
161 0xff, 0x10, 0x01, 0xe2,
162 0x01, 0x20, 0xa0, 0xe1,
163 0x04, 0x10, 0x90, 0xe5,
164 0xff, 0x10, 0x01, 0xe2,
165 0x41, 0x14, 0xa0, 0xe1,
166 0x02, 0x10, 0x81, 0xe1,
167
168
169
170 0x74, 0x20, 0x9f, 0xe5,
171
172
173
174 0x92, 0x01, 0x01, 0xe0,
175
176
177
178 0x70, 0x20, 0x9f, 0xe5,
179
180
181
182
183 0xa2, 0x10, 0x81, 0xe0,
184 0x02, 0x40, 0xa0, 0xe1,
185 0xa1, 0x00, 0x54, 0xe1,
186
187 0x84, 0x40, 0xa0, 0x91,
188 0xa1, 0x00, 0x54, 0xe1,
189 0xfc, 0xff, 0xff, 0x9a,
190 0x00, 0x30, 0xa0, 0xe3,
191
192 0x04, 0x00, 0x51, 0xe1,
193 0x04, 0x10, 0x41, 0x20,
194 0x03, 0x30, 0xa3, 0xe0,
195 0xa4, 0x40, 0xa0, 0xe1,
196 0x02, 0x00, 0x54, 0xe1,
197 0xf9, 0xff, 0xff, 0x2a,
198 0x03, 0x10, 0xa0, 0xe1,
199
200
201
202 0x01, 0x20, 0xa0, 0xe1,
203 0xff, 0x20, 0x02, 0xe2,
204 0x00, 0x20, 0x80, 0xe5,
205
206
207
208 0x41, 0x24, 0xa0, 0xe1,
209 0xff, 0x20, 0x02, 0xe2,
210 0x04, 0x20, 0x80, 0xe5,
211
212
213
214 0x0c, 0x10, 0x90, 0xe5,
215 0x80, 0x10, 0xc1, 0xe3,
216 0x0c, 0x10, 0x80, 0xe5,
217
218
219
220
221 0xb7, 0x19, 0xa0, 0xe3,
222
223 0x01, 0x10, 0x41, 0xe2,
224 0x00, 0x00, 0x51, 0xe3,
225 0xfc, 0xff, 0xff, 0x1a,
226
227
228 0x01, 0x00, 0x00, 0xea,
229
230
231
232 0x00, 0x00, 0x00, 0x00,
233
234
235
236 0x00, 0x00, 0x00, 0x00,
237
238
239};
240
241
242static unsigned char kwboot_baud_code_binhdr_pre[] = {
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260 0xfe, 0x5f, 0x2d, 0xe9,
261
262
263 0x0d, 0x02, 0xa0, 0xe3,
264 0x12, 0x0a, 0x80, 0xe3,
265
266
267 0x00, 0x20, 0x8f, 0xe2,
268
269
270 0x03, 0x00, 0x00, 0xea,
271
272
273
274 0x24, 0x62, 0x61, 0x75,
275 0x64, 0x72, 0x61, 0x74,
276 0x65, 0x63, 0x68, 0x61,
277 0x6e, 0x67, 0x65, 0x00,
278
279
280
281
282
283
284
285 0x14, 0x10, 0x90, 0xe5,
286 0x20, 0x00, 0x11, 0xe3,
287 0xfc, 0xff, 0xff, 0x0a,
288
289
290
291 0x01, 0x10, 0xd2, 0xe4,
292
293 0x00, 0x10, 0x80, 0xe5,
294
295
296 0x00, 0x00, 0x51, 0xe3,
297 0xf8, 0xff, 0xff, 0x1a,
298};
299
300
301static unsigned char kwboot_baud_code_binhdr_post[] = {
302
303 0x00, 0x00, 0xa0, 0xe3,
304 0xfe, 0x9f, 0xbd, 0xe8,
305};
306
307
308static unsigned char kwboot_baud_code_data_jump[] = {
309 0x04, 0xf0, 0x1f, 0xe5,
310
311
312 0x00, 0x00, 0x00, 0x00,
313};
314
315static const char kwb_baud_magic[16] = "$baudratechange";
316
317static int kwboot_verbose;
318
319static int msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO;
320static int blk_rsp_timeo = KWBOOT_BLK_RSP_TIMEO;
321
322static ssize_t
323kwboot_write(int fd, const char *buf, size_t len)
324{
325 ssize_t tot = 0;
326
327 while (tot < len) {
328 ssize_t wr = write(fd, buf + tot, len - tot);
329
330 if (wr < 0 && errno == EINTR)
331 continue;
332 else if (wr < 0)
333 return wr;
334
335 tot += wr;
336 }
337
338 return tot;
339}
340
341static void
342kwboot_printv(const char *fmt, ...)
343{
344 va_list ap;
345
346 if (kwboot_verbose) {
347 va_start(ap, fmt);
348 vprintf(fmt, ap);
349 va_end(ap);
350 fflush(stdout);
351 }
352}
353
354static void
355__spinner(void)
356{
357 const char seq[] = { '-', '\\', '|', '/' };
358 const int div = 8;
359 static int state, bs;
360
361 if (state % div == 0) {
362 fputc(bs, stdout);
363 fputc(seq[state / div % sizeof(seq)], stdout);
364 fflush(stdout);
365 }
366
367 bs = '\b';
368 state++;
369}
370
371static void
372kwboot_spinner(void)
373{
374 if (kwboot_verbose)
375 __spinner();
376}
377
378static void
379__progress(int pct, char c)
380{
381 const int width = 70;
382 static const char *nl = "";
383 static int pos;
384
385 if (pos % width == 0)
386 printf("%s%3d %% [", nl, pct);
387
388 fputc(c, stdout);
389
390 nl = "]\n";
391 pos = (pos + 1) % width;
392
393 if (pct == 100) {
394 while (pos && pos++ < width)
395 fputc(' ', stdout);
396 fputs(nl, stdout);
397 nl = "";
398 pos = 0;
399 }
400
401 fflush(stdout);
402
403}
404
405static void
406kwboot_progress(int _pct, char c)
407{
408 static int pct;
409
410 if (_pct != -1)
411 pct = _pct;
412
413 if (kwboot_verbose)
414 __progress(pct, c);
415
416 if (pct == 100)
417 pct = 0;
418}
419
420static int
421kwboot_tty_recv(int fd, void *buf, size_t len, int timeo)
422{
423 int rc, nfds;
424 fd_set rfds;
425 struct timeval tv;
426 ssize_t n;
427
428 rc = -1;
429
430 FD_ZERO(&rfds);
431 FD_SET(fd, &rfds);
432
433 tv.tv_sec = 0;
434 tv.tv_usec = timeo * 1000;
435 if (tv.tv_usec > 1000000) {
436 tv.tv_sec += tv.tv_usec / 1000000;
437 tv.tv_usec %= 1000000;
438 }
439
440 do {
441 nfds = select(fd + 1, &rfds, NULL, NULL, &tv);
442 if (nfds < 0 && errno == EINTR)
443 continue;
444 else if (nfds < 0)
445 goto out;
446 else if (!nfds) {
447 errno = ETIMEDOUT;
448 goto out;
449 }
450
451 n = read(fd, buf, len);
452 if (n < 0 && errno == EINTR)
453 continue;
454 else if (n <= 0)
455 goto out;
456
457 buf = (char *)buf + n;
458 len -= n;
459 } while (len > 0);
460
461 rc = 0;
462out:
463 return rc;
464}
465
466static int
467kwboot_tty_send(int fd, const void *buf, size_t len, int nodrain)
468{
469 if (!buf)
470 return 0;
471
472 if (kwboot_write(fd, buf, len) < 0)
473 return -1;
474
475 if (nodrain)
476 return 0;
477
478 return tcdrain(fd);
479}
480
481static int
482kwboot_tty_send_char(int fd, unsigned char c)
483{
484 return kwboot_tty_send(fd, &c, 1, 0);
485}
486
487static speed_t
488kwboot_tty_baudrate_to_speed(int baudrate)
489{
490 switch (baudrate) {
491#ifdef B4000000
492 case 4000000:
493 return B4000000;
494#endif
495#ifdef B3500000
496 case 3500000:
497 return B3500000;
498#endif
499#ifdef B3000000
500 case 3000000:
501 return B3000000;
502#endif
503#ifdef B2500000
504 case 2500000:
505 return B2500000;
506#endif
507#ifdef B2000000
508 case 2000000:
509 return B2000000;
510#endif
511#ifdef B1500000
512 case 1500000:
513 return B1500000;
514#endif
515#ifdef B1152000
516 case 1152000:
517 return B1152000;
518#endif
519#ifdef B1000000
520 case 1000000:
521 return B1000000;
522#endif
523#ifdef B921600
524 case 921600:
525 return B921600;
526#endif
527#ifdef B614400
528 case 614400:
529 return B614400;
530#endif
531#ifdef B576000
532 case 576000:
533 return B576000;
534#endif
535#ifdef B500000
536 case 500000:
537 return B500000;
538#endif
539#ifdef B460800
540 case 460800:
541 return B460800;
542#endif
543#ifdef B307200
544 case 307200:
545 return B307200;
546#endif
547#ifdef B230400
548 case 230400:
549 return B230400;
550#endif
551#ifdef B153600
552 case 153600:
553 return B153600;
554#endif
555#ifdef B115200
556 case 115200:
557 return B115200;
558#endif
559#ifdef B76800
560 case 76800:
561 return B76800;
562#endif
563#ifdef B57600
564 case 57600:
565 return B57600;
566#endif
567#ifdef B38400
568 case 38400:
569 return B38400;
570#endif
571#ifdef B19200
572 case 19200:
573 return B19200;
574#endif
575#ifdef B9600
576 case 9600:
577 return B9600;
578#endif
579#ifdef B4800
580 case 4800:
581 return B4800;
582#endif
583#ifdef B2400
584 case 2400:
585 return B2400;
586#endif
587#ifdef B1800
588 case 1800:
589 return B1800;
590#endif
591#ifdef B1200
592 case 1200:
593 return B1200;
594#endif
595#ifdef B600
596 case 600:
597 return B600;
598#endif
599#ifdef B300
600 case 300:
601 return B300;
602#endif
603#ifdef B200
604 case 200:
605 return B200;
606#endif
607#ifdef B150
608 case 150:
609 return B150;
610#endif
611#ifdef B134
612 case 134:
613 return B134;
614#endif
615#ifdef B110
616 case 110:
617 return B110;
618#endif
619#ifdef B75
620 case 75:
621 return B75;
622#endif
623#ifdef B50
624 case 50:
625 return B50;
626#endif
627 default:
628#ifdef BOTHER
629 return BOTHER;
630#else
631 return B0;
632#endif
633 }
634}
635
636static int
637_is_within_tolerance(int value, int reference, int tolerance)
638{
639 return 100 * value >= reference * (100 - tolerance) &&
640 100 * value <= reference * (100 + tolerance);
641}
642
643static int
644kwboot_tty_change_baudrate(int fd, int baudrate)
645{
646 struct termios tio;
647 speed_t speed;
648 int rc;
649
650 rc = tcgetattr(fd, &tio);
651 if (rc)
652 return rc;
653
654 speed = kwboot_tty_baudrate_to_speed(baudrate);
655 if (speed == B0) {
656 errno = EINVAL;
657 return -1;
658 }
659
660#ifdef BOTHER
661 if (speed == BOTHER)
662 tio.c_ospeed = tio.c_ispeed = baudrate;
663#endif
664
665 rc = cfsetospeed(&tio, speed);
666 if (rc)
667 return rc;
668
669 rc = cfsetispeed(&tio, speed);
670 if (rc)
671 return rc;
672
673 rc = tcsetattr(fd, TCSANOW, &tio);
674 if (rc)
675 return rc;
676
677 rc = tcgetattr(fd, &tio);
678 if (rc)
679 return rc;
680
681 if (cfgetospeed(&tio) != speed || cfgetispeed(&tio) != speed)
682 goto baud_fail;
683
684#ifdef BOTHER
685
686
687
688
689
690 if (!_is_within_tolerance(tio.c_ospeed, baudrate, 3))
691 goto baud_fail;
692
693 if (!_is_within_tolerance(tio.c_ispeed, baudrate, 3))
694 goto baud_fail;
695#endif
696
697 return 0;
698
699baud_fail:
700 fprintf(stderr, "Could not set baudrate to requested value\n");
701 errno = EINVAL;
702 return -1;
703}
704
705static int
706kwboot_open_tty(const char *path, int baudrate)
707{
708 int rc, fd, flags;
709 struct termios tio;
710
711 rc = -1;
712
713 fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY);
714 if (fd < 0)
715 goto out;
716
717 rc = tcgetattr(fd, &tio);
718 if (rc)
719 goto out;
720
721 cfmakeraw(&tio);
722 tio.c_cflag |= CREAD | CLOCAL;
723 tio.c_cflag &= ~(CSTOPB | HUPCL | CRTSCTS);
724 tio.c_cc[VMIN] = 1;
725 tio.c_cc[VTIME] = 0;
726
727 rc = tcsetattr(fd, TCSANOW, &tio);
728 if (rc)
729 goto out;
730
731 flags = fcntl(fd, F_GETFL);
732 if (flags < 0)
733 goto out;
734
735 rc = fcntl(fd, F_SETFL, flags & ~O_NDELAY);
736 if (rc)
737 goto out;
738
739 rc = kwboot_tty_change_baudrate(fd, baudrate);
740 if (rc)
741 goto out;
742
743 rc = fd;
744out:
745 if (rc < 0) {
746 if (fd >= 0)
747 close(fd);
748 }
749
750 return rc;
751}
752
753static void *
754kwboot_msg_write_handler(void *arg)
755{
756 int tty = *(int *)((void **)arg)[0];
757 const void *msg = ((void **)arg)[1];
758 int rsp_timeo = msg_rsp_timeo;
759 int i, dummy_oldtype;
760
761
762 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &dummy_oldtype);
763
764 while (1) {
765
766 for (i = 0; i < 128; i++) {
767 if (kwboot_tty_send(tty, msg, 8, 1) < 0) {
768 perror("\nFailed to send message pattern");
769 exit(1);
770 }
771 }
772
773 if (tcdrain(tty) < 0) {
774 perror("\nFailed to send message pattern");
775 exit(1);
776 }
777
778 usleep(rsp_timeo * 1000);
779 }
780}
781
782static int
783kwboot_msg_start_thread(pthread_t *thread, int *tty, void *msg)
784{
785 void *arg[2];
786 int rc;
787
788 arg[0] = tty;
789 arg[1] = msg;
790 rc = pthread_create(thread, NULL, kwboot_msg_write_handler, arg);
791 if (rc) {
792 errno = rc;
793 return -1;
794 }
795
796 return 0;
797}
798
799static int
800kwboot_msg_stop_thread(pthread_t thread)
801{
802 int rc;
803
804 rc = pthread_cancel(thread);
805 if (rc) {
806 errno = rc;
807 return -1;
808 }
809
810 rc = pthread_join(thread, NULL);
811 if (rc) {
812 errno = rc;
813 return -1;
814 }
815
816 return 0;
817}
818
819static int
820kwboot_bootmsg(int tty)
821{
822 struct kwboot_block block;
823 pthread_t write_thread;
824 int rc, err;
825 char c;
826
827
828 tcflush(tty, TCIOFLUSH);
829
830 rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_boot);
831 if (rc) {
832 perror("Failed to start write thread");
833 return rc;
834 }
835
836 kwboot_printv("Sending boot message. Please reboot the target...");
837
838 err = 0;
839 while (1) {
840 kwboot_spinner();
841
842 rc = kwboot_tty_recv(tty, &c, 1, msg_rsp_timeo);
843 if (rc && errno == ETIMEDOUT) {
844 continue;
845 } else if (rc) {
846 err = errno;
847 break;
848 }
849
850 if (c == NAK)
851 break;
852 }
853
854 kwboot_printv("\n");
855
856 rc = kwboot_msg_stop_thread(write_thread);
857 if (rc) {
858 perror("Failed to stop write thread");
859 return rc;
860 }
861
862 if (err) {
863 errno = err;
864 perror("Failed to read response for boot message pattern");
865 return -1;
866 }
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883 rc = tcflush(tty, TCOFLUSH);
884 if (rc) {
885 perror("Failed to flush output queue");
886 return rc;
887 }
888
889
890 memset(&block, 0xff, sizeof(block));
891 rc = kwboot_tty_send(tty, &block, sizeof(block), 0);
892 if (rc) {
893 perror("Failed to send sync sequence");
894 return rc;
895 }
896
897
898
899
900
901 usleep(30 * 1000);
902
903
904 rc = tcflush(tty, TCIFLUSH);
905 if (rc) {
906 perror("Failed to flush input queue");
907 return rc;
908 }
909
910 return 0;
911}
912
913static int
914kwboot_debugmsg(int tty)
915{
916 unsigned char buf[8192];
917 pthread_t write_thread;
918 int rc, err, i, pos;
919 size_t off;
920
921
922 tcflush(tty, TCIOFLUSH);
923
924 rc = kwboot_msg_start_thread(&write_thread, &tty, kwboot_msg_debug);
925 if (rc) {
926 perror("Failed to start write thread");
927 return rc;
928 }
929
930 kwboot_printv("Sending debug message. Please reboot the target...");
931 kwboot_spinner();
932
933 err = 0;
934 off = 0;
935 while (1) {
936
937 rc = read(tty, buf + off, sizeof(buf) - off);
938 if ((rc < 0 && errno == EINTR) || rc == 0) {
939 continue;
940 } else if (rc < 0) {
941 err = errno;
942 break;
943 }
944 off += rc - 1;
945
946 kwboot_spinner();
947
948
949
950
951
952
953 for (pos = 0; pos < sizeof(kwboot_msg_debug); pos++)
954 if (buf[off] == kwboot_msg_debug[(pos + off) % sizeof(kwboot_msg_debug)])
955 break;
956
957 for (i = off; i >= 0; i--)
958 if (buf[i] != kwboot_msg_debug[(pos + i) % sizeof(kwboot_msg_debug)])
959 break;
960
961 off -= i;
962
963 if (off >= 4 * sizeof(kwboot_msg_debug))
964 break;
965
966
967 memmove(buf, buf + i + 1, off);
968 }
969
970 kwboot_printv("\n");
971
972 rc = kwboot_msg_stop_thread(write_thread);
973 if (rc) {
974 perror("Failed to stop write thread");
975 return rc;
976 }
977
978 if (err) {
979 errno = err;
980 perror("Failed to read response for debug message pattern");
981 return -1;
982 }
983
984
985 rc = tcflush(tty, TCOFLUSH);
986 if (rc) {
987 perror("Failed to flush output queue");
988 return rc;
989 }
990
991 kwboot_printv("Clearing input buffer...\n");
992
993
994
995
996
997
998 usleep(500 * 1000);
999
1000
1001
1002
1003
1004
1005
1006
1007
1008 while ((rc = kwboot_tty_recv(tty, &buf[0], 1, 0)) == 0)
1009 off++;
1010 if (errno != ETIMEDOUT) {
1011 perror("Failed to read response");
1012 return rc;
1013 }
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 off *= 3;
1026 memset(buf, '\x08', sizeof(buf));
1027 while (off > sizeof(buf)) {
1028 rc = kwboot_tty_send(tty, buf, sizeof(buf), 1);
1029 if (rc) {
1030 perror("Failed to send clear sequence");
1031 return rc;
1032 }
1033 off -= sizeof(buf);
1034 }
1035 rc = kwboot_tty_send(tty, buf, off, 0);
1036 if (rc) {
1037 perror("Failed to send clear sequence");
1038 return rc;
1039 }
1040
1041 usleep(msg_rsp_timeo * 1000);
1042 rc = tcflush(tty, TCIFLUSH);
1043 if (rc) {
1044 perror("Failed to flush input queue");
1045 return rc;
1046 }
1047
1048 return 0;
1049}
1050
1051static size_t
1052kwboot_xm_makeblock(struct kwboot_block *block, const void *data,
1053 size_t size, int pnum)
1054{
1055 size_t i, n;
1056
1057 block->soh = SOH;
1058 block->pnum = pnum;
1059 block->_pnum = ~block->pnum;
1060
1061 n = size < KWBOOT_XM_BLKSZ ? size : KWBOOT_XM_BLKSZ;
1062 memcpy(&block->data[0], data, n);
1063 memset(&block->data[n], 0, KWBOOT_XM_BLKSZ - n);
1064
1065 block->csum = 0;
1066 for (i = 0; i < n; i++)
1067 block->csum += block->data[i];
1068
1069 return n;
1070}
1071
1072static uint64_t
1073_now(void)
1074{
1075 struct timespec ts;
1076
1077 if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
1078 static int err_print;
1079
1080 if (!err_print) {
1081 perror("clock_gettime() does not work");
1082 err_print = 1;
1083 }
1084
1085
1086 return -1ULL;
1087 }
1088
1089 return ts.tv_sec * 1000ULL + (ts.tv_nsec + 500000) / 1000000;
1090}
1091
1092static int
1093_is_xm_reply(char c)
1094{
1095 return c == ACK || c == NAK;
1096}
1097
1098static int
1099_xm_reply_to_error(int c)
1100{
1101 int rc = -1;
1102
1103 switch (c) {
1104 case ACK:
1105 rc = 0;
1106 break;
1107 case NAK:
1108 errno = EBADMSG;
1109 break;
1110 default:
1111 errno = EPROTO;
1112 break;
1113 }
1114
1115 return rc;
1116}
1117
1118static int
1119kwboot_baud_magic_handle(int fd, char c, int baudrate)
1120{
1121 static size_t rcv_len;
1122
1123 if (rcv_len < sizeof(kwb_baud_magic)) {
1124
1125 if (c == kwb_baud_magic[rcv_len]) {
1126 rcv_len++;
1127 } else {
1128 printf("%.*s%c", (int)rcv_len, kwb_baud_magic, c);
1129 fflush(stdout);
1130 rcv_len = 0;
1131 }
1132 }
1133
1134 if (rcv_len == sizeof(kwb_baud_magic)) {
1135
1136 kwboot_printv("\nChanging baudrate to %d Bd\n", baudrate);
1137
1138 return kwboot_tty_change_baudrate(fd, baudrate) ? : 1;
1139 } else {
1140 return 0;
1141 }
1142}
1143
1144static int
1145kwboot_xm_recv_reply(int fd, char *c, int stop_on_non_xm,
1146 int ignore_nak_reply,
1147 int allow_non_xm, int *non_xm_print,
1148 int baudrate, int *baud_changed)
1149{
1150 int timeout = allow_non_xm ? KWBOOT_HDR_RSP_TIMEO : blk_rsp_timeo;
1151 uint64_t recv_until = _now() + timeout;
1152 int rc;
1153
1154 while (1) {
1155 rc = kwboot_tty_recv(fd, c, 1, timeout);
1156 if (rc) {
1157 if (errno != ETIMEDOUT)
1158 return rc;
1159 else if (allow_non_xm && *non_xm_print)
1160 return -1;
1161 else
1162 *c = NAK;
1163 }
1164
1165
1166 if (_is_xm_reply(*c)) {
1167 if (*c == NAK && ignore_nak_reply) {
1168 timeout = recv_until - _now();
1169 if (timeout >= 0)
1170 continue;
1171 }
1172 break;
1173 }
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184 if (allow_non_xm) {
1185 recv_until = _now() + timeout;
1186
1187 if (baudrate && !*baud_changed) {
1188 rc = kwboot_baud_magic_handle(fd, *c, baudrate);
1189 if (rc == 1)
1190 *baud_changed = 1;
1191 else if (!rc)
1192 *non_xm_print = 1;
1193 else
1194 return rc;
1195 } else if (!baudrate || !*baud_changed) {
1196 putchar(*c);
1197 fflush(stdout);
1198 *non_xm_print = 1;
1199 }
1200 } else {
1201 if (stop_on_non_xm)
1202 break;
1203 timeout = recv_until - _now();
1204 if (timeout < 0) {
1205 errno = ETIMEDOUT;
1206 return -1;
1207 }
1208 }
1209 }
1210
1211 return 0;
1212}
1213
1214static int
1215kwboot_xm_sendblock(int fd, struct kwboot_block *block, int allow_non_xm,
1216 int *done_print, int baudrate, int allow_retries)
1217{
1218 int non_xm_print, baud_changed;
1219 int rc, err, retries;
1220 char c;
1221
1222 *done_print = 0;
1223 non_xm_print = 0;
1224 baud_changed = 0;
1225
1226 retries = 0;
1227 do {
1228 rc = kwboot_tty_send(fd, block, sizeof(*block), 1);
1229 if (rc)
1230 goto err;
1231
1232 if (allow_non_xm && !*done_print) {
1233 kwboot_progress(100, '.');
1234 kwboot_printv("Done\n");
1235 *done_print = 1;
1236 }
1237
1238 rc = kwboot_xm_recv_reply(fd, &c, retries < 3,
1239 retries > 8,
1240 allow_non_xm, &non_xm_print,
1241 baudrate, &baud_changed);
1242 if (rc)
1243 goto err;
1244
1245 if (!allow_non_xm && c != ACK) {
1246 if (c == NAK && allow_retries && retries + 1 < 16)
1247 kwboot_progress(-1, '+');
1248 else
1249 kwboot_progress(-1, 'E');
1250 }
1251 } while (c == NAK && allow_retries && retries++ < 16);
1252
1253 if (non_xm_print)
1254 kwboot_printv("\n");
1255
1256 if (allow_non_xm && baudrate && !baud_changed) {
1257 fprintf(stderr, "Baudrate was not changed\n");
1258 errno = EPROTO;
1259 return -1;
1260 }
1261
1262 return _xm_reply_to_error(c);
1263err:
1264 err = errno;
1265 kwboot_printv("\n");
1266 errno = err;
1267 return rc;
1268}
1269
1270static int
1271kwboot_xm_finish(int fd)
1272{
1273 int rc, retries;
1274 char c;
1275
1276 kwboot_printv("Finishing transfer\n");
1277
1278 retries = 0;
1279 do {
1280 rc = kwboot_tty_send_char(fd, EOT);
1281 if (rc)
1282 return rc;
1283
1284 rc = kwboot_xm_recv_reply(fd, &c, retries < 3,
1285 retries > 8,
1286 0, NULL, 0, NULL);
1287 if (rc)
1288 return rc;
1289 } while (c == NAK && retries++ < 16);
1290
1291 return _xm_reply_to_error(c);
1292}
1293
1294static int
1295kwboot_xmodem_one(int tty, int *pnum, int header, const uint8_t *data,
1296 size_t size, int baudrate)
1297{
1298 int done_print = 0;
1299 size_t sent, left;
1300 int rc;
1301
1302 kwboot_printv("Sending boot image %s (%zu bytes)...\n",
1303 header ? "header" : "data", size);
1304
1305 left = size;
1306 sent = 0;
1307
1308 while (sent < size) {
1309 struct kwboot_block block;
1310 int last_block;
1311 size_t blksz;
1312
1313 blksz = kwboot_xm_makeblock(&block, data, left, (*pnum)++);
1314 data += blksz;
1315
1316 last_block = (left <= blksz);
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340 rc = kwboot_xm_sendblock(tty, &block, header && last_block,
1341 &done_print, baudrate, header);
1342 if (rc)
1343 goto out;
1344
1345 sent += blksz;
1346 left -= blksz;
1347
1348 if (!done_print)
1349 kwboot_progress(sent * 100 / size, '.');
1350 }
1351
1352 if (!done_print)
1353 kwboot_printv("Done\n");
1354
1355 return 0;
1356out:
1357 kwboot_printv("\n");
1358 return rc;
1359}
1360
1361static int
1362kwboot_xmodem(int tty, const void *_img, size_t size, int baudrate)
1363{
1364 const uint8_t *img = _img;
1365 int rc, pnum;
1366 size_t hdrsz;
1367
1368 hdrsz = kwbheader_size(img);
1369
1370
1371
1372
1373
1374
1375
1376 hdrsz += (KWBOOT_XM_BLKSZ - hdrsz % KWBOOT_XM_BLKSZ) % KWBOOT_XM_BLKSZ;
1377
1378 pnum = 1;
1379
1380 rc = kwboot_xmodem_one(tty, &pnum, 1, img, hdrsz, baudrate);
1381 if (rc)
1382 return rc;
1383
1384
1385
1386
1387
1388 if (hdrsz < size) {
1389 img += hdrsz;
1390 size -= hdrsz;
1391 rc = kwboot_xmodem_one(tty, &pnum, 0, img, size, 0);
1392 if (rc)
1393 return rc;
1394 }
1395
1396 rc = kwboot_xm_finish(tty);
1397 if (rc)
1398 return rc;
1399
1400 if (baudrate) {
1401 kwboot_printv("\nChanging baudrate back to 115200 Bd\n\n");
1402 rc = kwboot_tty_change_baudrate(tty, 115200);
1403 if (rc)
1404 return rc;
1405 }
1406
1407 return 0;
1408}
1409
1410static int
1411kwboot_term_pipe(int in, int out, const char *quit, int *s, const char *kbs, int *k)
1412{
1413 char buf[128];
1414 ssize_t nin, noff;
1415
1416 nin = read(in, buf, sizeof(buf));
1417 if (nin <= 0)
1418 return -1;
1419
1420 noff = 0;
1421
1422 if (quit || kbs) {
1423 int i;
1424
1425 for (i = 0; i < nin; i++) {
1426 if ((quit || kbs) &&
1427 (!quit || buf[i] != quit[*s]) &&
1428 (!kbs || buf[i] != kbs[*k])) {
1429 const char *prefix;
1430 int plen;
1431
1432 if (quit && kbs) {
1433 prefix = (*s >= *k) ? quit : kbs;
1434 plen = (*s >= *k) ? *s : *k;
1435 } else if (quit) {
1436 prefix = quit;
1437 plen = *s;
1438 } else {
1439 prefix = kbs;
1440 plen = *k;
1441 }
1442
1443 if (plen > i && kwboot_write(out, prefix, plen - i) < 0)
1444 return -1;
1445 }
1446
1447 if (quit && buf[i] == quit[*s]) {
1448 (*s)++;
1449 if (!quit[*s]) {
1450 nin = (i > *s) ? (i - *s) : 0;
1451 break;
1452 }
1453 } else if (quit) {
1454 *s = 0;
1455 }
1456
1457 if (kbs && buf[i] == kbs[*k]) {
1458 (*k)++;
1459 if (!kbs[*k]) {
1460 if (i > *k + noff &&
1461 kwboot_write(out, buf + noff, i - *k - noff) < 0)
1462 return -1;
1463
1464
1465
1466
1467
1468 if (write(out, "\x08", 1) < 0)
1469 return -1;
1470 noff = i + 1;
1471 *k = 0;
1472 }
1473 } else if (kbs) {
1474 *k = 0;
1475 }
1476 }
1477
1478 if (i == nin) {
1479 i = 0;
1480 if (quit && i < *s)
1481 i = *s;
1482 if (kbs && i < *k)
1483 i = *k;
1484 nin -= (nin > i) ? i : nin;
1485 }
1486 }
1487
1488 if (nin > noff && kwboot_write(out, buf + noff, nin - noff) < 0)
1489 return -1;
1490
1491 return 0;
1492}
1493
1494static int
1495kwboot_terminal(int tty)
1496{
1497 int rc, in, s, k;
1498 const char *kbs = NULL;
1499 const char *quit = "\34c";
1500 struct termios otio, tio;
1501
1502 rc = -1;
1503
1504 in = STDIN_FILENO;
1505 if (isatty(in)) {
1506 rc = tcgetattr(in, &otio);
1507 if (!rc) {
1508 tio = otio;
1509 cfmakeraw(&tio);
1510 rc = tcsetattr(in, TCSANOW, &tio);
1511 }
1512 if (rc) {
1513 perror("tcsetattr");
1514 goto out;
1515 }
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538 if (setupterm(NULL, STDOUT_FILENO, &rc) == 0) {
1539 kbs = tigetstr("kbs");
1540 if (kbs == (char *)-1)
1541 kbs = NULL;
1542 }
1543
1544 kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n",
1545 quit[0] | 0100, quit[1]);
1546 } else
1547 in = -1;
1548
1549 rc = 0;
1550 s = 0;
1551 k = 0;
1552
1553 do {
1554 fd_set rfds;
1555 int nfds = 0;
1556
1557 FD_ZERO(&rfds);
1558 FD_SET(tty, &rfds);
1559 nfds = nfds < tty ? tty : nfds;
1560
1561 if (in >= 0) {
1562 FD_SET(in, &rfds);
1563 nfds = nfds < in ? in : nfds;
1564 }
1565
1566 nfds = select(nfds + 1, &rfds, NULL, NULL, NULL);
1567 if (nfds < 0)
1568 break;
1569
1570 if (FD_ISSET(tty, &rfds)) {
1571 rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL, NULL, NULL);
1572 if (rc)
1573 break;
1574 }
1575
1576 if (in >= 0 && FD_ISSET(in, &rfds)) {
1577 rc = kwboot_term_pipe(in, tty, quit, &s, kbs, &k);
1578 if (rc)
1579 break;
1580 }
1581 } while (quit[s] != 0);
1582
1583 if (in >= 0)
1584 tcsetattr(in, TCSANOW, &otio);
1585 printf("\n");
1586out:
1587 return rc;
1588}
1589
1590static void *
1591kwboot_read_image(const char *path, size_t *size, size_t reserve)
1592{
1593 int rc, fd;
1594 void *img;
1595 off_t len;
1596 off_t tot;
1597
1598 rc = -1;
1599 img = NULL;
1600
1601 fd = open(path, O_RDONLY);
1602 if (fd < 0)
1603 goto out;
1604
1605 len = lseek(fd, 0, SEEK_END);
1606 if (len == (off_t)-1)
1607 goto out;
1608
1609 if (lseek(fd, 0, SEEK_SET) == (off_t)-1)
1610 goto out;
1611
1612 img = malloc(len + reserve);
1613 if (!img)
1614 goto out;
1615
1616 tot = 0;
1617 while (tot < len) {
1618 ssize_t rd = read(fd, img + tot, len - tot);
1619
1620 if (rd < 0)
1621 goto out;
1622
1623 tot += rd;
1624
1625 if (!rd && tot < len) {
1626 errno = EIO;
1627 goto out;
1628 }
1629 }
1630
1631 rc = 0;
1632 *size = len;
1633out:
1634 if (rc && img) {
1635 free(img);
1636 img = NULL;
1637 }
1638 if (fd >= 0)
1639 close(fd);
1640
1641 return img;
1642}
1643
1644static uint8_t
1645kwboot_hdr_csum8(const void *hdr)
1646{
1647 const uint8_t *data = hdr;
1648 uint8_t csum;
1649 size_t size;
1650
1651 size = kwbheader_size_for_csum(hdr);
1652
1653 for (csum = 0; size-- > 0; data++)
1654 csum += *data;
1655
1656 return csum;
1657}
1658
1659static uint32_t *
1660kwboot_img_csum32_ptr(void *img)
1661{
1662 struct main_hdr_v1 *hdr = img;
1663 uint32_t datasz;
1664
1665 datasz = le32_to_cpu(hdr->blocksize) - sizeof(uint32_t);
1666
1667 return img + le32_to_cpu(hdr->srcaddr) + datasz;
1668}
1669
1670static uint32_t
1671kwboot_img_csum32(const void *img)
1672{
1673 const struct main_hdr_v1 *hdr = img;
1674 uint32_t datasz, csum = 0;
1675 const uint32_t *data;
1676
1677 datasz = le32_to_cpu(hdr->blocksize) - sizeof(csum);
1678 if (datasz % sizeof(uint32_t))
1679 return 0;
1680
1681 data = img + le32_to_cpu(hdr->srcaddr);
1682 while (datasz > 0) {
1683 csum += le32_to_cpu(*data++);
1684 datasz -= 4;
1685 }
1686
1687 return cpu_to_le32(csum);
1688}
1689
1690static int
1691kwboot_img_is_secure(void *img)
1692{
1693 struct opt_hdr_v1 *ohdr;
1694
1695 for_each_opt_hdr_v1 (ohdr, img)
1696 if (ohdr->headertype == OPT_HDR_V1_SECURE_TYPE)
1697 return 1;
1698
1699 return 0;
1700}
1701
1702static void *
1703kwboot_img_grow_data_right(void *img, size_t *size, size_t grow)
1704{
1705 struct main_hdr_v1 *hdr = img;
1706 void *result;
1707
1708
1709
1710
1711
1712
1713
1714 result = kwboot_img_csum32_ptr(img);
1715 hdr->blocksize = cpu_to_le32(le32_to_cpu(hdr->blocksize) + grow);
1716 *size += grow;
1717
1718 return result;
1719}
1720
1721static void
1722kwboot_img_grow_hdr(void *img, size_t *size, size_t grow)
1723{
1724 uint32_t hdrsz, datasz, srcaddr;
1725 struct main_hdr_v1 *hdr = img;
1726 struct opt_hdr_v1 *ohdr;
1727 uint8_t *data;
1728
1729 srcaddr = le32_to_cpu(hdr->srcaddr);
1730
1731
1732 if (kwbimage_version(img) == 0) {
1733 hdrsz = kwbheader_size(img);
1734 } else {
1735 hdrsz = sizeof(*hdr);
1736 for_each_opt_hdr_v1 (ohdr, hdr)
1737 hdrsz += opt_hdr_v1_size(ohdr);
1738 }
1739
1740 data = (uint8_t *)img + srcaddr;
1741 datasz = *size - srcaddr;
1742
1743
1744 if (hdrsz + grow > srcaddr) {
1745 size_t need = hdrsz + grow - srcaddr;
1746
1747
1748 memmove(data + need, data, datasz);
1749
1750 hdr->srcaddr = cpu_to_le32(srcaddr + need);
1751 *size += need;
1752 }
1753
1754 if (kwbimage_version(img) == 1) {
1755 hdrsz += grow;
1756 if (hdrsz > kwbheader_size(img)) {
1757 hdr->headersz_msb = hdrsz >> 16;
1758 hdr->headersz_lsb = cpu_to_le16(hdrsz & 0xffff);
1759 }
1760 }
1761}
1762
1763static void *
1764kwboot_add_bin_ohdr_v1(void *img, size_t *size, uint32_t binsz)
1765{
1766 struct main_hdr_v1 *hdr = img;
1767 struct opt_hdr_v1 *ohdr;
1768 uint32_t num_args;
1769 uint32_t offset;
1770 uint32_t ohdrsz;
1771 uint8_t *prev_ext;
1772
1773 if (hdr->ext) {
1774 for_each_opt_hdr_v1 (ohdr, img)
1775 if (opt_hdr_v1_next(ohdr) == NULL)
1776 break;
1777
1778 prev_ext = opt_hdr_v1_ext(ohdr);
1779 ohdr = _opt_hdr_v1_next(ohdr);
1780 } else {
1781 ohdr = (void *)(hdr + 1);
1782 prev_ext = &hdr->ext;
1783 }
1784
1785
1786
1787
1788
1789
1790
1791 offset = &ohdr->data[4] - (char *)img;
1792 num_args = ((16 - offset % 16) % 16) / sizeof(uint32_t);
1793
1794 ohdrsz = sizeof(*ohdr) + 4 + 4 * num_args + binsz + 4;
1795 kwboot_img_grow_hdr(hdr, size, ohdrsz);
1796
1797 *prev_ext = 1;
1798
1799 ohdr->headertype = OPT_HDR_V1_BINARY_TYPE;
1800 ohdr->headersz_msb = ohdrsz >> 16;
1801 ohdr->headersz_lsb = cpu_to_le16(ohdrsz & 0xffff);
1802
1803 memset(&ohdr->data[0], 0, ohdrsz - sizeof(*ohdr));
1804 *(uint32_t *)&ohdr->data[0] = cpu_to_le32(num_args);
1805
1806 return &ohdr->data[4 + 4 * num_args];
1807}
1808
1809static void
1810_inject_baudrate_change_code(void *img, size_t *size, int for_data,
1811 int old_baud, int new_baud)
1812{
1813 struct main_hdr_v1 *hdr = img;
1814 uint32_t orig_datasz;
1815 uint32_t codesz;
1816 uint8_t *code;
1817
1818 if (for_data) {
1819 orig_datasz = le32_to_cpu(hdr->blocksize) - sizeof(uint32_t);
1820
1821 codesz = sizeof(kwboot_baud_code) +
1822 sizeof(kwboot_baud_code_data_jump);
1823 code = kwboot_img_grow_data_right(img, size, codesz);
1824 } else {
1825 codesz = sizeof(kwboot_baud_code_binhdr_pre) +
1826 sizeof(kwboot_baud_code) +
1827 sizeof(kwboot_baud_code_binhdr_post);
1828 code = kwboot_add_bin_ohdr_v1(img, size, codesz);
1829
1830 codesz = sizeof(kwboot_baud_code_binhdr_pre);
1831 memcpy(code, kwboot_baud_code_binhdr_pre, codesz);
1832 code += codesz;
1833 }
1834
1835 codesz = sizeof(kwboot_baud_code) - 2 * sizeof(uint32_t);
1836 memcpy(code, kwboot_baud_code, codesz);
1837 code += codesz;
1838 *(uint32_t *)code = cpu_to_le32(old_baud);
1839 code += sizeof(uint32_t);
1840 *(uint32_t *)code = cpu_to_le32(new_baud);
1841 code += sizeof(uint32_t);
1842
1843 if (for_data) {
1844 codesz = sizeof(kwboot_baud_code_data_jump) - sizeof(uint32_t);
1845 memcpy(code, kwboot_baud_code_data_jump, codesz);
1846 code += codesz;
1847 *(uint32_t *)code = hdr->execaddr;
1848 code += sizeof(uint32_t);
1849 hdr->execaddr = cpu_to_le32(le32_to_cpu(hdr->destaddr) + orig_datasz);
1850 } else {
1851 codesz = sizeof(kwboot_baud_code_binhdr_post);
1852 memcpy(code, kwboot_baud_code_binhdr_post, codesz);
1853 code += codesz;
1854 }
1855}
1856
1857static int
1858kwboot_img_patch(void *img, size_t *size, int baudrate)
1859{
1860 struct main_hdr_v1 *hdr;
1861 uint32_t srcaddr;
1862 uint8_t csum;
1863 size_t hdrsz;
1864 int image_ver;
1865 int is_secure;
1866
1867 hdr = img;
1868
1869 if (*size < sizeof(struct main_hdr_v1))
1870 goto err;
1871
1872 image_ver = kwbimage_version(img);
1873 if (image_ver != 0 && image_ver != 1) {
1874 fprintf(stderr, "Invalid image header version\n");
1875 goto err;
1876 }
1877
1878 hdrsz = kwbheader_size(hdr);
1879
1880 if (*size < hdrsz)
1881 goto err;
1882
1883 csum = kwboot_hdr_csum8(hdr) - hdr->checksum;
1884 if (csum != hdr->checksum)
1885 goto err;
1886
1887 srcaddr = le32_to_cpu(hdr->srcaddr);
1888
1889 switch (hdr->blockid) {
1890 case IBR_HDR_SATA_ID:
1891 if (srcaddr < 1)
1892 goto err;
1893
1894 hdr->srcaddr = cpu_to_le32((srcaddr - 1) * 512);
1895 break;
1896
1897 case IBR_HDR_SDIO_ID:
1898 hdr->srcaddr = cpu_to_le32(srcaddr * 512);
1899 break;
1900
1901 case IBR_HDR_PEX_ID:
1902 if (srcaddr == 0xFFFFFFFF)
1903 hdr->srcaddr = cpu_to_le32(hdrsz);
1904 break;
1905
1906 case IBR_HDR_SPI_ID:
1907 if (hdr->destaddr == cpu_to_le32(0xFFFFFFFF)) {
1908 kwboot_printv("Patching destination and execution addresses from SPI/NOR XIP area to DDR area 0x00800000\n");
1909 hdr->destaddr = cpu_to_le32(0x00800000);
1910 hdr->execaddr = cpu_to_le32(0x00800000);
1911 }
1912 break;
1913 }
1914
1915 if (hdrsz > le32_to_cpu(hdr->srcaddr) ||
1916 *size < le32_to_cpu(hdr->srcaddr) + le32_to_cpu(hdr->blocksize))
1917 goto err;
1918
1919 if (kwboot_img_csum32(img) != *kwboot_img_csum32_ptr(img))
1920 goto err;
1921
1922 is_secure = kwboot_img_is_secure(img);
1923
1924 if (hdr->blockid != IBR_HDR_UART_ID) {
1925 if (is_secure) {
1926 fprintf(stderr,
1927 "Image has secure header with signature for non-UART booting\n");
1928 goto err;
1929 }
1930
1931 kwboot_printv("Patching image boot signature to UART\n");
1932 hdr->blockid = IBR_HDR_UART_ID;
1933 }
1934
1935 if (!is_secure) {
1936 if (image_ver == 1) {
1937
1938
1939
1940
1941
1942
1943 hdr->flags |= 0x1;
1944 hdr->options &= ~0x1F;
1945 hdr->options |= MAIN_HDR_V1_OPT_BAUD_DEFAULT;
1946 hdr->options |= 0 << 3;
1947 }
1948 if (image_ver == 0)
1949 ((struct main_hdr_v0 *)img)->nandeccmode = IBR_HDR_ECC_DISABLED;
1950 hdr->nandpagesize = 0;
1951 }
1952
1953 if (baudrate) {
1954 if (image_ver == 0) {
1955 fprintf(stderr,
1956 "Cannot inject code for changing baudrate into v0 image header\n");
1957 goto err;
1958 }
1959
1960 if (is_secure) {
1961 fprintf(stderr,
1962 "Cannot inject code for changing baudrate into image with secure header\n");
1963 goto err;
1964 }
1965
1966
1967
1968
1969
1970
1971
1972 kwboot_printv("Injecting binary header code for changing baudrate to %d Bd\n",
1973 baudrate);
1974 _inject_baudrate_change_code(img, size, 0, 115200, baudrate);
1975
1976
1977
1978
1979
1980
1981
1982 kwboot_printv("Injecting code for changing baudrate back\n");
1983 _inject_baudrate_change_code(img, size, 1, baudrate, 115200);
1984
1985
1986 *kwboot_img_csum32_ptr(img) = kwboot_img_csum32(img);
1987
1988
1989 hdrsz = kwbheader_size(hdr);
1990 }
1991
1992 if (hdrsz % KWBOOT_XM_BLKSZ) {
1993 size_t grow = KWBOOT_XM_BLKSZ - hdrsz % KWBOOT_XM_BLKSZ;
1994
1995 if (is_secure) {
1996 fprintf(stderr, "Cannot align image with secure header\n");
1997 goto err;
1998 }
1999
2000 kwboot_printv("Aligning image header to Xmodem block size\n");
2001 kwboot_img_grow_hdr(img, size, grow);
2002 }
2003
2004 hdr->checksum = kwboot_hdr_csum8(hdr) - csum;
2005
2006 *size = le32_to_cpu(hdr->srcaddr) + le32_to_cpu(hdr->blocksize);
2007 return 0;
2008err:
2009 errno = EINVAL;
2010 return -1;
2011}
2012
2013static void
2014kwboot_usage(FILE *stream, char *progname)
2015{
2016 fprintf(stream,
2017 "Usage: %s [OPTIONS] [-b <image> | -D <image> | -b | -d ] [-B <baud> ] [-t] <TTY>\n",
2018 progname);
2019 fprintf(stream, "\n");
2020 fprintf(stream,
2021 " -b <image>: boot <image> with preamble (Kirkwood, Avanta, Armada 370/XP/375/38x/39x)\n");
2022 fprintf(stream,
2023 " -D <image>: boot <image> without preamble (Dove)\n");
2024 fprintf(stream, " -b: enter xmodem boot mode\n");
2025 fprintf(stream, " -d: enter console debug mode\n");
2026 fprintf(stream, " -a: use timings for Armada XP\n");
2027 fprintf(stream, " -s <resp-timeo>: use specific response-timeout\n");
2028 fprintf(stream,
2029 " -o <block-timeo>: use specific xmodem block timeout\n");
2030 fprintf(stream, "\n");
2031 fprintf(stream, " -t: mini terminal\n");
2032 fprintf(stream, "\n");
2033 fprintf(stream, " -B <baud>: set baud rate\n");
2034 fprintf(stream, "\n");
2035}
2036
2037int
2038main(int argc, char **argv)
2039{
2040 const char *ttypath, *imgpath;
2041 int rv, rc, tty, term;
2042 int bootmsg;
2043 int debugmsg;
2044 void *img;
2045 size_t size;
2046 size_t after_img_rsv;
2047 int baudrate;
2048 int prev_optind;
2049 int c;
2050
2051 rv = 1;
2052 tty = -1;
2053 bootmsg = 0;
2054 debugmsg = 0;
2055 imgpath = NULL;
2056 img = NULL;
2057 term = 0;
2058 size = 0;
2059 after_img_rsv = KWBOOT_XM_BLKSZ;
2060 baudrate = 115200;
2061
2062 printf("kwboot version %s\n", PLAIN_VERSION);
2063
2064 kwboot_verbose = isatty(STDOUT_FILENO);
2065
2066 do {
2067 prev_optind = optind;
2068 c = getopt(argc, argv, "hbptaB:dD:q:s:o:");
2069 if (c < 0)
2070 break;
2071
2072 switch (c) {
2073 case 'b':
2074 if (imgpath || bootmsg || debugmsg)
2075 goto usage;
2076 bootmsg = 1;
2077 if (prev_optind == optind)
2078 goto usage;
2079
2080 if (optind < argc && argv[optind] && argv[optind][0] != '-')
2081 imgpath = argv[optind++];
2082 break;
2083
2084 case 'D':
2085 if (imgpath || bootmsg || debugmsg)
2086 goto usage;
2087 bootmsg = 0;
2088 imgpath = optarg;
2089 break;
2090
2091 case 'd':
2092 if (imgpath || bootmsg || debugmsg)
2093 goto usage;
2094 debugmsg = 1;
2095 break;
2096
2097 case 'p':
2098
2099 break;
2100
2101 case 't':
2102 term = 1;
2103 break;
2104
2105 case 'a':
2106 msg_rsp_timeo = KWBOOT_MSG_RSP_TIMEO_AXP;
2107 break;
2108
2109 case 'q':
2110
2111 break;
2112
2113 case 's':
2114 msg_rsp_timeo = atoi(optarg);
2115 break;
2116
2117 case 'o':
2118 blk_rsp_timeo = atoi(optarg);
2119 break;
2120
2121 case 'B':
2122 baudrate = atoi(optarg);
2123 break;
2124
2125 case 'h':
2126 rv = 0;
2127 default:
2128 goto usage;
2129 }
2130 } while (1);
2131
2132 if (!bootmsg && !term && !debugmsg && !imgpath)
2133 goto usage;
2134
2135
2136
2137
2138
2139
2140 if (optind == argc && imgpath) {
2141 ttypath = imgpath;
2142 imgpath = NULL;
2143 } else if (optind + 1 == argc) {
2144 ttypath = argv[optind];
2145 } else {
2146 goto usage;
2147 }
2148
2149
2150 if (((bootmsg && !imgpath) || debugmsg) && baudrate != 115200) {
2151 fprintf(stderr, "Baudrate other than 115200 cannot be used for this operation.\n");
2152 goto usage;
2153 }
2154
2155 tty = kwboot_open_tty(ttypath, baudrate);
2156 if (tty < 0) {
2157 perror(ttypath);
2158 goto out;
2159 }
2160
2161
2162
2163
2164
2165 if (imgpath && baudrate != 115200) {
2166 rc = kwboot_tty_change_baudrate(tty, 115200);
2167 if (rc) {
2168 perror(ttypath);
2169 goto out;
2170 }
2171 }
2172
2173 if (baudrate == 115200)
2174
2175 baudrate = 0;
2176 else
2177
2178 after_img_rsv += sizeof(struct opt_hdr_v1) + 8 + 16 +
2179 sizeof(kwboot_baud_code_binhdr_pre) +
2180 sizeof(kwboot_baud_code) +
2181 sizeof(kwboot_baud_code_binhdr_post) +
2182 KWBOOT_XM_BLKSZ +
2183 sizeof(kwboot_baud_code) +
2184 sizeof(kwboot_baud_code_data_jump) +
2185 KWBOOT_XM_BLKSZ;
2186
2187 if (imgpath) {
2188 img = kwboot_read_image(imgpath, &size, after_img_rsv);
2189 if (!img) {
2190 perror(imgpath);
2191 goto out;
2192 }
2193
2194 rc = kwboot_img_patch(img, &size, baudrate);
2195 if (rc) {
2196 fprintf(stderr, "%s: Invalid image.\n", imgpath);
2197 goto out;
2198 }
2199 }
2200
2201 if (debugmsg) {
2202 rc = kwboot_debugmsg(tty);
2203 if (rc)
2204 goto out;
2205 } else if (bootmsg) {
2206 rc = kwboot_bootmsg(tty);
2207 if (rc)
2208 goto out;
2209 }
2210
2211 if (img) {
2212 rc = kwboot_xmodem(tty, img, size, baudrate);
2213 if (rc) {
2214 perror("xmodem");
2215 goto out;
2216 }
2217 }
2218
2219 if (term) {
2220 rc = kwboot_terminal(tty);
2221 if (rc && !(errno == EINTR)) {
2222 perror("terminal");
2223 goto out;
2224 }
2225 }
2226
2227 rv = 0;
2228out:
2229 if (tty >= 0)
2230 close(tty);
2231
2232 if (img)
2233 free(img);
2234
2235 return rv;
2236
2237usage:
2238 kwboot_usage(rv ? stderr : stdout, basename(argv[0]));
2239 goto out;
2240}
2241