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