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