1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000-2004
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6 
7 /*
8  * Serial up- and download support
9  */
10 #include <common.h>
11 #include <command.h>
12 #include <console.h>
13 #include <cpu_func.h>
14 #include <efi_loader.h>
15 #include <env.h>
16 #include <exports.h>
17 #include <flash.h>
18 #include <image.h>
19 #include <mapmem.h>
20 #include <net.h>
21 #include <s_record.h>
22 #include <serial.h>
23 #include <xyzModem.h>
24 #include <asm/cache.h>
25 #include <asm/global_data.h>
26 #include <linux/delay.h>
27 
28 DECLARE_GLOBAL_DATA_PTR;
29 
30 #if defined(CONFIG_CMD_LOADB)
31 static ulong load_serial_ymodem(ulong offset, int mode);
32 #endif
33 
34 #if defined(CONFIG_CMD_LOADS)
35 static ulong load_serial(long offset);
36 static int read_record(char *buf, ulong len);
37 # if defined(CONFIG_CMD_SAVES)
38 static int save_serial(ulong offset, ulong size);
39 static int write_record(char *buf);
40 #endif
41 
42 static int do_echo = 1;
43 #endif
44 
45 /* -------------------------------------------------------------------- */
46 
47 #if defined(CONFIG_CMD_LOADS)
do_load_serial(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])48 static int do_load_serial(struct cmd_tbl *cmdtp, int flag, int argc,
49 			  char *const argv[])
50 {
51 	long offset = 0;
52 	ulong addr;
53 	int i;
54 	char *env_echo;
55 	int rcode = 0;
56 #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
57 	int load_baudrate, current_baudrate;
58 
59 	load_baudrate = current_baudrate = gd->baudrate;
60 #endif
61 
62 	env_echo = env_get("loads_echo");
63 	if (env_echo && *env_echo == '1')
64 		do_echo = 1;
65 	else
66 		do_echo = 0;
67 
68 #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
69 	if (argc >= 2) {
70 		offset = simple_strtol(argv[1], NULL, 16);
71 	}
72 	if (argc == 3) {
73 		load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
74 
75 		/* default to current baudrate */
76 		if (load_baudrate == 0)
77 			load_baudrate = current_baudrate;
78 	}
79 	if (load_baudrate != current_baudrate) {
80 		printf("## Switch baudrate to %d bps and press ENTER ...\n",
81 			load_baudrate);
82 		udelay(50000);
83 		gd->baudrate = load_baudrate;
84 		serial_setbrg();
85 		udelay(50000);
86 		for (;;) {
87 			if (getchar() == '\r')
88 				break;
89 		}
90 	}
91 #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
92 	if (argc == 2) {
93 		offset = simple_strtol(argv[1], NULL, 16);
94 	}
95 #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
96 
97 	printf("## Ready for S-Record download ...\n");
98 
99 	addr = load_serial(offset);
100 
101 	/*
102 	 * Gather any trailing characters (for instance, the ^D which
103 	 * is sent by 'cu' after sending a file), and give the
104 	 * box some time (100 * 1 ms)
105 	 */
106 	for (i=0; i<100; ++i) {
107 		if (tstc()) {
108 			getchar();
109 		}
110 		udelay(1000);
111 	}
112 
113 	if (addr == ~0) {
114 		printf("## S-Record download aborted\n");
115 		rcode = 1;
116 	} else {
117 		printf("## Start Addr      = 0x%08lX\n", addr);
118 		image_load_addr = addr;
119 	}
120 
121 #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
122 	if (load_baudrate != current_baudrate) {
123 		printf("## Switch baudrate to %d bps and press ESC ...\n",
124 			current_baudrate);
125 		udelay(50000);
126 		gd->baudrate = current_baudrate;
127 		serial_setbrg();
128 		udelay(50000);
129 		for (;;) {
130 			if (getchar() == 0x1B) /* ESC */
131 				break;
132 		}
133 	}
134 #endif
135 	return rcode;
136 }
137 
load_serial(long offset)138 static ulong load_serial(long offset)
139 {
140 	char	record[SREC_MAXRECLEN + 1];	/* buffer for one S-Record	*/
141 	char	binbuf[SREC_MAXBINLEN];		/* buffer for binary data	*/
142 	int	binlen;				/* no. of data bytes in S-Rec.	*/
143 	int	type;				/* return code for record type	*/
144 	ulong	addr;				/* load address from S-Record	*/
145 	ulong	size;				/* number of bytes transferred	*/
146 	ulong	store_addr;
147 	ulong	start_addr = ~0;
148 	ulong	end_addr   =  0;
149 	int	line_count =  0;
150 
151 	while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {
152 		type = srec_decode(record, &binlen, &addr, binbuf);
153 
154 		if (type < 0) {
155 			return (~0);		/* Invalid S-Record		*/
156 		}
157 
158 		switch (type) {
159 		case SREC_DATA2:
160 		case SREC_DATA3:
161 		case SREC_DATA4:
162 		    store_addr = addr + offset;
163 #ifdef CONFIG_MTD_NOR_FLASH
164 		    if (addr2info(store_addr)) {
165 			int rc;
166 
167 			rc = flash_write((char *)binbuf,store_addr,binlen);
168 			if (rc != 0) {
169 				flash_perror(rc);
170 				return (~0);
171 			}
172 		    } else
173 #endif
174 		    {
175 			memcpy((char *)(store_addr), binbuf, binlen);
176 		    }
177 		    if ((store_addr) < start_addr)
178 			start_addr = store_addr;
179 		    if ((store_addr + binlen - 1) > end_addr)
180 			end_addr = store_addr + binlen - 1;
181 		    break;
182 		case SREC_END2:
183 		case SREC_END3:
184 		case SREC_END4:
185 		    udelay(10000);
186 		    size = end_addr - start_addr + 1;
187 		    printf("\n"
188 			    "## First Load Addr = 0x%08lX\n"
189 			    "## Last  Load Addr = 0x%08lX\n"
190 			    "## Total Size      = 0x%08lX = %ld Bytes\n",
191 			    start_addr, end_addr, size, size
192 		    );
193 		    flush_cache(start_addr, size);
194 		    env_set_hex("filesize", size);
195 		    return (addr);
196 		case SREC_START:
197 		    break;
198 		default:
199 		    break;
200 		}
201 		if (!do_echo) {	/* print a '.' every 100 lines */
202 			if ((++line_count % 100) == 0)
203 				putc('.');
204 		}
205 	}
206 
207 	return (~0);			/* Download aborted		*/
208 }
209 
read_record(char * buf,ulong len)210 static int read_record(char *buf, ulong len)
211 {
212 	char *p;
213 	char c;
214 
215 	--len;	/* always leave room for terminating '\0' byte */
216 
217 	for (p=buf; p < buf+len; ++p) {
218 		c = getchar();		/* read character		*/
219 		if (do_echo)
220 			putc(c);	/* ... and echo it		*/
221 
222 		switch (c) {
223 		case '\r':
224 		case '\n':
225 			*p = '\0';
226 			return (p - buf);
227 		case '\0':
228 		case 0x03:			/* ^C - Control C		*/
229 			return (-1);
230 		default:
231 			*p = c;
232 		}
233 
234 		/* Check for the console hangup (if any different from serial) */
235 		if (gd->jt->getc != getchar) {
236 			if (ctrlc())
237 				return (-1);
238 		}
239 	}
240 
241 	/* line too long - truncate */
242 	*p = '\0';
243 	return (p - buf);
244 }
245 
246 #if defined(CONFIG_CMD_SAVES)
247 
do_save_serial(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])248 int do_save_serial(struct cmd_tbl *cmdtp, int flag, int argc,
249 		   char *const argv[])
250 {
251 	ulong offset = 0;
252 	ulong size   = 0;
253 #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
254 	int save_baudrate, current_baudrate;
255 
256 	save_baudrate = current_baudrate = gd->baudrate;
257 #endif
258 
259 	if (argc >= 2) {
260 		offset = simple_strtoul(argv[1], NULL, 16);
261 	}
262 #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
263 	if (argc >= 3) {
264 		size = simple_strtoul(argv[2], NULL, 16);
265 	}
266 	if (argc == 4) {
267 		save_baudrate = (int)simple_strtoul(argv[3], NULL, 10);
268 
269 		/* default to current baudrate */
270 		if (save_baudrate == 0)
271 			save_baudrate = current_baudrate;
272 	}
273 	if (save_baudrate != current_baudrate) {
274 		printf("## Switch baudrate to %d bps and press ENTER ...\n",
275 			save_baudrate);
276 		udelay(50000);
277 		gd->baudrate = save_baudrate;
278 		serial_setbrg();
279 		udelay(50000);
280 		for (;;) {
281 			if (getchar() == '\r')
282 				break;
283 		}
284 	}
285 #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
286 	if (argc == 3) {
287 		size = simple_strtoul(argv[2], NULL, 16);
288 	}
289 #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
290 
291 	printf("## Ready for S-Record upload, press ENTER to proceed ...\n");
292 	for (;;) {
293 		if (getchar() == '\r')
294 			break;
295 	}
296 	if (save_serial(offset, size)) {
297 		printf("## S-Record upload aborted\n");
298 	} else {
299 		printf("## S-Record upload complete\n");
300 	}
301 #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
302 	if (save_baudrate != current_baudrate) {
303 		printf("## Switch baudrate to %d bps and press ESC ...\n",
304 			(int)current_baudrate);
305 		udelay(50000);
306 		gd->baudrate = current_baudrate;
307 		serial_setbrg();
308 		udelay(50000);
309 		for (;;) {
310 			if (getchar() == 0x1B) /* ESC */
311 				break;
312 		}
313 	}
314 #endif
315 	return 0;
316 }
317 
318 #define SREC3_START				"S0030000FC\n"
319 #define SREC3_FORMAT			"S3%02X%08lX%s%02X\n"
320 #define SREC3_END				"S70500000000FA\n"
321 #define SREC_BYTES_PER_RECORD	16
322 
save_serial(ulong address,ulong count)323 static int save_serial(ulong address, ulong count)
324 {
325 	int i, c, reclen, checksum, length;
326 	char *hex = "0123456789ABCDEF";
327 	char	record[2*SREC_BYTES_PER_RECORD+16];	/* buffer for one S-Record	*/
328 	char	data[2*SREC_BYTES_PER_RECORD+1];	/* buffer for hex data	*/
329 
330 	reclen = 0;
331 	checksum  = 0;
332 
333 	if(write_record(SREC3_START))			/* write the header */
334 		return (-1);
335 	do {
336 		if(count) {						/* collect hex data in the buffer  */
337 			c = *(volatile uchar*)(address + reclen);	/* get one byte    */
338 			checksum += c;							/* accumulate checksum */
339 			data[2*reclen]   = hex[(c>>4)&0x0f];
340 			data[2*reclen+1] = hex[c & 0x0f];
341 			data[2*reclen+2] = '\0';
342 			++reclen;
343 			--count;
344 		}
345 		if(reclen == SREC_BYTES_PER_RECORD || count == 0) {
346 			/* enough data collected for one record: dump it */
347 			if(reclen) {	/* build & write a data record: */
348 				/* address + data + checksum */
349 				length = 4 + reclen + 1;
350 
351 				/* accumulate length bytes into checksum */
352 				for(i = 0; i < 2; i++)
353 					checksum += (length >> (8*i)) & 0xff;
354 
355 				/* accumulate address bytes into checksum: */
356 				for(i = 0; i < 4; i++)
357 					checksum += (address >> (8*i)) & 0xff;
358 
359 				/* make proper checksum byte: */
360 				checksum = ~checksum & 0xff;
361 
362 				/* output one record: */
363 				sprintf(record, SREC3_FORMAT, length, address, data, checksum);
364 				if(write_record(record))
365 					return (-1);
366 			}
367 			address  += reclen;  /* increment address */
368 			checksum  = 0;
369 			reclen    = 0;
370 		}
371 	}
372 	while(count);
373 	if(write_record(SREC3_END))	/* write the final record */
374 		return (-1);
375 	return(0);
376 }
377 
write_record(char * buf)378 static int write_record(char *buf)
379 {
380 	char c;
381 
382 	while((c = *buf++))
383 		putc(c);
384 
385 	/* Check for the console hangup (if any different from serial) */
386 
387 	if (ctrlc()) {
388 	    return (-1);
389 	}
390 	return (0);
391 }
392 # endif
393 
394 #endif
395 
396 
397 #if defined(CONFIG_CMD_LOADB)
398 /*
399  * loadb command (load binary) included
400  */
401 #define XON_CHAR        17
402 #define XOFF_CHAR       19
403 #define START_CHAR      0x01
404 #define ETX_CHAR	0x03
405 #define END_CHAR        0x0D
406 #define SPACE           0x20
407 #define K_ESCAPE        0x23
408 #define SEND_TYPE       'S'
409 #define DATA_TYPE       'D'
410 #define ACK_TYPE        'Y'
411 #define NACK_TYPE       'N'
412 #define BREAK_TYPE      'B'
413 #define tochar(x) ((char) (((x) + SPACE) & 0xff))
414 #define untochar(x) ((int) (((x) - SPACE) & 0xff))
415 
416 static void set_kerm_bin_mode(unsigned long *);
417 static int k_recv(void);
418 static ulong load_serial_bin(ulong offset);
419 
420 
421 static char his_eol;        /* character he needs at end of packet */
422 static int  his_pad_count;  /* number of pad chars he needs */
423 static char his_pad_char;   /* pad chars he needs */
424 static char his_quote;      /* quote chars he'll use */
425 
do_load_serial_bin(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])426 static int do_load_serial_bin(struct cmd_tbl *cmdtp, int flag, int argc,
427 			      char *const argv[])
428 {
429 	ulong offset = 0;
430 	ulong addr;
431 	int load_baudrate, current_baudrate;
432 	int rcode = 0;
433 	char *s;
434 
435 	/* pre-set offset from CONFIG_SYS_LOAD_ADDR */
436 	offset = CONFIG_SYS_LOAD_ADDR;
437 
438 	/* pre-set offset from $loadaddr */
439 	s = env_get("loadaddr");
440 	if (s)
441 		offset = simple_strtoul(s, NULL, 16);
442 
443 	load_baudrate = current_baudrate = gd->baudrate;
444 
445 	if (argc >= 2) {
446 		offset = simple_strtoul(argv[1], NULL, 16);
447 	}
448 	if (argc == 3) {
449 		load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
450 
451 		/* default to current baudrate */
452 		if (load_baudrate == 0)
453 			load_baudrate = current_baudrate;
454 	}
455 
456 	if (load_baudrate != current_baudrate) {
457 		printf("## Switch baudrate to %d bps and press ENTER ...\n",
458 			load_baudrate);
459 		udelay(50000);
460 		gd->baudrate = load_baudrate;
461 		serial_setbrg();
462 		udelay(50000);
463 		for (;;) {
464 			if (getchar() == '\r')
465 				break;
466 		}
467 	}
468 
469 	if (strcmp(argv[0],"loady")==0) {
470 		printf("## Ready for binary (ymodem) download "
471 			"to 0x%08lX at %d bps...\n",
472 			offset,
473 			load_baudrate);
474 
475 		addr = load_serial_ymodem(offset, xyzModem_ymodem);
476 
477 	} else if (strcmp(argv[0],"loadx")==0) {
478 		printf("## Ready for binary (xmodem) download "
479 			"to 0x%08lX at %d bps...\n",
480 			offset,
481 			load_baudrate);
482 
483 		addr = load_serial_ymodem(offset, xyzModem_xmodem);
484 
485 	} else {
486 
487 		printf("## Ready for binary (kermit) download "
488 			"to 0x%08lX at %d bps...\n",
489 			offset,
490 			load_baudrate);
491 		addr = load_serial_bin(offset);
492 
493 		if (addr == ~0) {
494 			image_load_addr = 0;
495 			printf("## Binary (kermit) download aborted\n");
496 			rcode = 1;
497 		} else {
498 			printf("## Start Addr      = 0x%08lX\n", addr);
499 			image_load_addr = addr;
500 		}
501 	}
502 	if (load_baudrate != current_baudrate) {
503 		printf("## Switch baudrate to %d bps and press ESC ...\n",
504 			current_baudrate);
505 		udelay(50000);
506 		gd->baudrate = current_baudrate;
507 		serial_setbrg();
508 		udelay(50000);
509 		for (;;) {
510 			if (getchar() == 0x1B) /* ESC */
511 				break;
512 		}
513 	}
514 
515 	return rcode;
516 }
517 
518 
load_serial_bin(ulong offset)519 static ulong load_serial_bin(ulong offset)
520 {
521 	int size, i;
522 
523 	set_kerm_bin_mode((ulong *) offset);
524 	size = k_recv();
525 
526 	/*
527 	 * Gather any trailing characters (for instance, the ^D which
528 	 * is sent by 'cu' after sending a file), and give the
529 	 * box some time (100 * 1 ms)
530 	 */
531 	for (i=0; i<100; ++i) {
532 		if (tstc()) {
533 			getchar();
534 		}
535 		udelay(1000);
536 	}
537 
538 	flush_cache(offset, size);
539 
540 	printf("## Total Size      = 0x%08x = %d Bytes\n", size, size);
541 	env_set_hex("filesize", size);
542 
543 	return offset;
544 }
545 
send_pad(void)546 static void send_pad(void)
547 {
548 	int count = his_pad_count;
549 
550 	while (count-- > 0)
551 		putc(his_pad_char);
552 }
553 
554 /* converts escaped kermit char to binary char */
ktrans(char in)555 static char ktrans(char in)
556 {
557 	if ((in & 0x60) == 0x40) {
558 		return (char) (in & ~0x40);
559 	} else if ((in & 0x7f) == 0x3f) {
560 		return (char) (in | 0x40);
561 	} else
562 		return in;
563 }
564 
chk1(char * buffer)565 static int chk1(char *buffer)
566 {
567 	int total = 0;
568 
569 	while (*buffer) {
570 		total += *buffer++;
571 	}
572 	return (int) ((total + ((total >> 6) & 0x03)) & 0x3f);
573 }
574 
s1_sendpacket(char * packet)575 static void s1_sendpacket(char *packet)
576 {
577 	send_pad();
578 	while (*packet) {
579 		putc(*packet++);
580 	}
581 }
582 
583 static char a_b[24];
send_ack(int n)584 static void send_ack(int n)
585 {
586 	a_b[0] = START_CHAR;
587 	a_b[1] = tochar(3);
588 	a_b[2] = tochar(n);
589 	a_b[3] = ACK_TYPE;
590 	a_b[4] = '\0';
591 	a_b[4] = tochar(chk1(&a_b[1]));
592 	a_b[5] = his_eol;
593 	a_b[6] = '\0';
594 	s1_sendpacket(a_b);
595 }
596 
send_nack(int n)597 static void send_nack(int n)
598 {
599 	a_b[0] = START_CHAR;
600 	a_b[1] = tochar(3);
601 	a_b[2] = tochar(n);
602 	a_b[3] = NACK_TYPE;
603 	a_b[4] = '\0';
604 	a_b[4] = tochar(chk1(&a_b[1]));
605 	a_b[5] = his_eol;
606 	a_b[6] = '\0';
607 	s1_sendpacket(a_b);
608 }
609 
610 
611 static void (*os_data_init)(void);
612 static void (*os_data_char)(char new_char);
613 static int os_data_state, os_data_state_saved;
614 static char *os_data_addr, *os_data_addr_saved;
615 static char *bin_start_address;
616 
bin_data_init(void)617 static void bin_data_init(void)
618 {
619 	os_data_state = 0;
620 	os_data_addr = bin_start_address;
621 }
622 
os_data_save(void)623 static void os_data_save(void)
624 {
625 	os_data_state_saved = os_data_state;
626 	os_data_addr_saved = os_data_addr;
627 }
628 
os_data_restore(void)629 static void os_data_restore(void)
630 {
631 	os_data_state = os_data_state_saved;
632 	os_data_addr = os_data_addr_saved;
633 }
634 
bin_data_char(char new_char)635 static void bin_data_char(char new_char)
636 {
637 	switch (os_data_state) {
638 	case 0:					/* data */
639 		*os_data_addr++ = new_char;
640 		break;
641 	}
642 }
643 
set_kerm_bin_mode(unsigned long * addr)644 static void set_kerm_bin_mode(unsigned long *addr)
645 {
646 	bin_start_address = (char *) addr;
647 	os_data_init = bin_data_init;
648 	os_data_char = bin_data_char;
649 }
650 
651 
652 /* k_data_* simply handles the kermit escape translations */
653 static int k_data_escape, k_data_escape_saved;
k_data_init(void)654 static void k_data_init(void)
655 {
656 	k_data_escape = 0;
657 	os_data_init();
658 }
659 
k_data_save(void)660 static void k_data_save(void)
661 {
662 	k_data_escape_saved = k_data_escape;
663 	os_data_save();
664 }
665 
k_data_restore(void)666 static void k_data_restore(void)
667 {
668 	k_data_escape = k_data_escape_saved;
669 	os_data_restore();
670 }
671 
k_data_char(char new_char)672 static void k_data_char(char new_char)
673 {
674 	if (k_data_escape) {
675 		/* last char was escape - translate this character */
676 		os_data_char(ktrans(new_char));
677 		k_data_escape = 0;
678 	} else {
679 		if (new_char == his_quote) {
680 			/* this char is escape - remember */
681 			k_data_escape = 1;
682 		} else {
683 			/* otherwise send this char as-is */
684 			os_data_char(new_char);
685 		}
686 	}
687 }
688 
689 #define SEND_DATA_SIZE  20
690 static char send_parms[SEND_DATA_SIZE];
691 static char *send_ptr;
692 
693 /* handle_send_packet interprits the protocol info and builds and
694    sends an appropriate ack for what we can do */
handle_send_packet(int n)695 static void handle_send_packet(int n)
696 {
697 	int length = 3;
698 	int bytes;
699 
700 	/* initialize some protocol parameters */
701 	his_eol = END_CHAR;		/* default end of line character */
702 	his_pad_count = 0;
703 	his_pad_char = '\0';
704 	his_quote = K_ESCAPE;
705 
706 	/* ignore last character if it filled the buffer */
707 	if (send_ptr == &send_parms[SEND_DATA_SIZE - 1])
708 		--send_ptr;
709 	bytes = send_ptr - send_parms;	/* how many bytes we'll process */
710 	do {
711 		if (bytes-- <= 0)
712 			break;
713 		/* handle MAXL - max length */
714 		/* ignore what he says - most I'll take (here) is 94 */
715 		a_b[++length] = tochar(94);
716 		if (bytes-- <= 0)
717 			break;
718 		/* handle TIME - time you should wait for my packets */
719 		/* ignore what he says - don't wait for my ack longer than 1 second */
720 		a_b[++length] = tochar(1);
721 		if (bytes-- <= 0)
722 			break;
723 		/* handle NPAD - number of pad chars I need */
724 		/* remember what he says - I need none */
725 		his_pad_count = untochar(send_parms[2]);
726 		a_b[++length] = tochar(0);
727 		if (bytes-- <= 0)
728 			break;
729 		/* handle PADC - pad chars I need */
730 		/* remember what he says - I need none */
731 		his_pad_char = ktrans(send_parms[3]);
732 		a_b[++length] = 0x40;	/* He should ignore this */
733 		if (bytes-- <= 0)
734 			break;
735 		/* handle EOL - end of line he needs */
736 		/* remember what he says - I need CR */
737 		his_eol = untochar(send_parms[4]);
738 		a_b[++length] = tochar(END_CHAR);
739 		if (bytes-- <= 0)
740 			break;
741 		/* handle QCTL - quote control char he'll use */
742 		/* remember what he says - I'll use '#' */
743 		his_quote = send_parms[5];
744 		a_b[++length] = '#';
745 		if (bytes-- <= 0)
746 			break;
747 		/* handle QBIN - 8-th bit prefixing */
748 		/* ignore what he says - I refuse */
749 		a_b[++length] = 'N';
750 		if (bytes-- <= 0)
751 			break;
752 		/* handle CHKT - the clock check type */
753 		/* ignore what he says - I do type 1 (for now) */
754 		a_b[++length] = '1';
755 		if (bytes-- <= 0)
756 			break;
757 		/* handle REPT - the repeat prefix */
758 		/* ignore what he says - I refuse (for now) */
759 		a_b[++length] = 'N';
760 		if (bytes-- <= 0)
761 			break;
762 		/* handle CAPAS - the capabilities mask */
763 		/* ignore what he says - I only do long packets - I don't do windows */
764 		a_b[++length] = tochar(2);	/* only long packets */
765 		a_b[++length] = tochar(0);	/* no windows */
766 		a_b[++length] = tochar(94);	/* large packet msb */
767 		a_b[++length] = tochar(94);	/* large packet lsb */
768 	} while (0);
769 
770 	a_b[0] = START_CHAR;
771 	a_b[1] = tochar(length);
772 	a_b[2] = tochar(n);
773 	a_b[3] = ACK_TYPE;
774 	a_b[++length] = '\0';
775 	a_b[length] = tochar(chk1(&a_b[1]));
776 	a_b[++length] = his_eol;
777 	a_b[++length] = '\0';
778 	s1_sendpacket(a_b);
779 }
780 
781 /* k_recv receives a OS Open image file over kermit line */
k_recv(void)782 static int k_recv(void)
783 {
784 	char new_char;
785 	char k_state, k_state_saved;
786 	int sum;
787 	int done;
788 	int length;
789 	int n, last_n;
790 	int len_lo, len_hi;
791 
792 	/* initialize some protocol parameters */
793 	his_eol = END_CHAR;		/* default end of line character */
794 	his_pad_count = 0;
795 	his_pad_char = '\0';
796 	his_quote = K_ESCAPE;
797 
798 	/* initialize the k_recv and k_data state machine */
799 	done = 0;
800 	k_state = 0;
801 	k_data_init();
802 	k_state_saved = k_state;
803 	k_data_save();
804 	n = 0;				/* just to get rid of a warning */
805 	last_n = -1;
806 
807 	/* expect this "type" sequence (but don't check):
808 	   S: send initiate
809 	   F: file header
810 	   D: data (multiple)
811 	   Z: end of file
812 	   B: break transmission
813 	 */
814 
815 	/* enter main loop */
816 	while (!done) {
817 		/* set the send packet pointer to begining of send packet parms */
818 		send_ptr = send_parms;
819 
820 		/* With each packet, start summing the bytes starting with the length.
821 		   Save the current sequence number.
822 		   Note the type of the packet.
823 		   If a character less than SPACE (0x20) is received - error.
824 		 */
825 
826 #if 0
827 		/* OLD CODE, Prior to checking sequence numbers */
828 		/* first have all state machines save current states */
829 		k_state_saved = k_state;
830 		k_data_save ();
831 #endif
832 
833 		/* get a packet */
834 		/* wait for the starting character or ^C */
835 		for (;;) {
836 			switch (getchar()) {
837 			case START_CHAR:	/* start packet */
838 				goto START;
839 			case ETX_CHAR:		/* ^C waiting for packet */
840 				return (0);
841 			default:
842 				;
843 			}
844 		}
845 START:
846 		/* get length of packet */
847 		sum = 0;
848 		new_char = getchar();
849 		if ((new_char & 0xE0) == 0)
850 			goto packet_error;
851 		sum += new_char & 0xff;
852 		length = untochar(new_char);
853 		/* get sequence number */
854 		new_char = getchar();
855 		if ((new_char & 0xE0) == 0)
856 			goto packet_error;
857 		sum += new_char & 0xff;
858 		n = untochar(new_char);
859 		--length;
860 
861 		/* NEW CODE - check sequence numbers for retried packets */
862 		/* Note - this new code assumes that the sequence number is correctly
863 		 * received.  Handling an invalid sequence number adds another layer
864 		 * of complexity that may not be needed - yet!  At this time, I'm hoping
865 		 * that I don't need to buffer the incoming data packets and can write
866 		 * the data into memory in real time.
867 		 */
868 		if (n == last_n) {
869 			/* same sequence number, restore the previous state */
870 			k_state = k_state_saved;
871 			k_data_restore();
872 		} else {
873 			/* new sequence number, checkpoint the download */
874 			last_n = n;
875 			k_state_saved = k_state;
876 			k_data_save();
877 		}
878 		/* END NEW CODE */
879 
880 		/* get packet type */
881 		new_char = getchar();
882 		if ((new_char & 0xE0) == 0)
883 			goto packet_error;
884 		sum += new_char & 0xff;
885 		k_state = new_char;
886 		--length;
887 		/* check for extended length */
888 		if (length == -2) {
889 			/* (length byte was 0, decremented twice) */
890 			/* get the two length bytes */
891 			new_char = getchar();
892 			if ((new_char & 0xE0) == 0)
893 				goto packet_error;
894 			sum += new_char & 0xff;
895 			len_hi = untochar(new_char);
896 			new_char = getchar();
897 			if ((new_char & 0xE0) == 0)
898 				goto packet_error;
899 			sum += new_char & 0xff;
900 			len_lo = untochar(new_char);
901 			length = len_hi * 95 + len_lo;
902 			/* check header checksum */
903 			new_char = getchar();
904 			if ((new_char & 0xE0) == 0)
905 				goto packet_error;
906 			if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
907 				goto packet_error;
908 			sum += new_char & 0xff;
909 /* --length; */ /* new length includes only data and block check to come */
910 		}
911 		/* bring in rest of packet */
912 		while (length > 1) {
913 			new_char = getchar();
914 			if ((new_char & 0xE0) == 0)
915 				goto packet_error;
916 			sum += new_char & 0xff;
917 			--length;
918 			if (k_state == DATA_TYPE) {
919 				/* pass on the data if this is a data packet */
920 				k_data_char (new_char);
921 			} else if (k_state == SEND_TYPE) {
922 				/* save send pack in buffer as is */
923 				*send_ptr++ = new_char;
924 				/* if too much data, back off the pointer */
925 				if (send_ptr >= &send_parms[SEND_DATA_SIZE])
926 					--send_ptr;
927 			}
928 		}
929 		/* get and validate checksum character */
930 		new_char = getchar();
931 		if ((new_char & 0xE0) == 0)
932 			goto packet_error;
933 		if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
934 			goto packet_error;
935 		/* get END_CHAR */
936 		new_char = getchar();
937 		if (new_char != END_CHAR) {
938 		  packet_error:
939 			/* restore state machines */
940 			k_state = k_state_saved;
941 			k_data_restore();
942 			/* send a negative acknowledge packet in */
943 			send_nack(n);
944 		} else if (k_state == SEND_TYPE) {
945 			/* crack the protocol parms, build an appropriate ack packet */
946 			handle_send_packet(n);
947 		} else {
948 			/* send simple acknowledge packet in */
949 			send_ack(n);
950 			/* quit if end of transmission */
951 			if (k_state == BREAK_TYPE)
952 				done = 1;
953 		}
954 	}
955 	return ((ulong) os_data_addr - (ulong) bin_start_address);
956 }
957 
getcxmodem(void)958 static int getcxmodem(void) {
959 	if (tstc())
960 		return (getchar());
961 	return -1;
962 }
load_serial_ymodem(ulong offset,int mode)963 static ulong load_serial_ymodem(ulong offset, int mode)
964 {
965 	int size;
966 	int err;
967 	int res;
968 	connection_info_t info;
969 	char ymodemBuf[1024];
970 	ulong store_addr = ~0;
971 	ulong addr = 0;
972 
973 	size = 0;
974 	info.mode = mode;
975 	res = xyzModem_stream_open(&info, &err);
976 	if (!res) {
977 
978 		while ((res =
979 			xyzModem_stream_read(ymodemBuf, 1024, &err)) > 0) {
980 			store_addr = addr + offset;
981 			size += res;
982 			addr += res;
983 #ifdef CONFIG_MTD_NOR_FLASH
984 			if (addr2info(store_addr)) {
985 				int rc;
986 
987 				rc = flash_write((char *) ymodemBuf,
988 						  store_addr, res);
989 				if (rc != 0) {
990 					flash_perror(rc);
991 					return (~0);
992 				}
993 			} else
994 #endif
995 			{
996 				memcpy((char *)(store_addr), ymodemBuf,
997 					res);
998 			}
999 
1000 		}
1001 		if (IS_ENABLED(CONFIG_CMD_BOOTEFI))
1002 			efi_set_bootdev("Uart", "", "",
1003 					map_sysmem(offset, 0), size);
1004 
1005 	} else {
1006 		printf("%s\n", xyzModem_error(err));
1007 	}
1008 
1009 	xyzModem_stream_close(&err);
1010 	xyzModem_stream_terminate(false, &getcxmodem);
1011 
1012 
1013 	flush_cache(offset, ALIGN(size, ARCH_DMA_MINALIGN));
1014 
1015 	printf("## Total Size      = 0x%08x = %d Bytes\n", size, size);
1016 	env_set_hex("filesize", size);
1017 
1018 	return offset;
1019 }
1020 
1021 #endif
1022 
1023 /* -------------------------------------------------------------------- */
1024 
1025 #if defined(CONFIG_CMD_LOADS)
1026 
1027 #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
1028 U_BOOT_CMD(
1029 	loads, 3, 0,	do_load_serial,
1030 	"load S-Record file over serial line",
1031 	"[ off ] [ baud ]\n"
1032 	"    - load S-Record file over serial line"
1033 	" with offset 'off' and baudrate 'baud'"
1034 );
1035 
1036 #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
1037 U_BOOT_CMD(
1038 	loads, 2, 0,	do_load_serial,
1039 	"load S-Record file over serial line",
1040 	"[ off ]\n"
1041 	"    - load S-Record file over serial line with offset 'off'"
1042 );
1043 #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
1044 
1045 /*
1046  * SAVES always requires LOADS support, but not vice versa
1047  */
1048 
1049 
1050 #if defined(CONFIG_CMD_SAVES)
1051 #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
1052 U_BOOT_CMD(
1053 	saves, 4, 0,	do_save_serial,
1054 	"save S-Record file over serial line",
1055 	"[ off ] [size] [ baud ]\n"
1056 	"    - save S-Record file over serial line"
1057 	" with offset 'off', size 'size' and baudrate 'baud'"
1058 );
1059 #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
1060 U_BOOT_CMD(
1061 	saves, 3, 0,	do_save_serial,
1062 	"save S-Record file over serial line",
1063 	"[ off ] [size]\n"
1064 	"    - save S-Record file over serial line with offset 'off' and size 'size'"
1065 );
1066 #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
1067 #endif	/* CONFIG_CMD_SAVES */
1068 #endif	/* CONFIG_CMD_LOADS */
1069 
1070 
1071 #if defined(CONFIG_CMD_LOADB)
1072 U_BOOT_CMD(
1073 	loadb, 3, 0,	do_load_serial_bin,
1074 	"load binary file over serial line (kermit mode)",
1075 	"[ addr [ baud ] ]\n"
1076 	"    - load binary file over serial line"
1077 	" at address 'addr' with baudrate 'baud'"
1078 );
1079 
1080 U_BOOT_CMD(
1081 	loadx, 3, 0,	do_load_serial_bin,
1082 	"load binary file over serial line (xmodem mode)",
1083 	"[ addr [ baud ] ]\n"
1084 	"    - load binary file over serial line"
1085 	" at address 'addr' with baudrate 'baud'"
1086 );
1087 
1088 U_BOOT_CMD(
1089 	loady, 3, 0,	do_load_serial_bin,
1090 	"load binary file over serial line (ymodem mode)",
1091 	"[ addr [ baud ] ]\n"
1092 	"    - load binary file over serial line"
1093 	" at address 'addr' with baudrate 'baud'"
1094 );
1095 
1096 #endif	/* CONFIG_CMD_LOADB */
1097