From f191a95f50c29cbaf76606611eb1a7a9353c9bd1 Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Sun, 5 Feb 2017 16:49:19 +0100 Subject: [PATCH] Backport tftpput command This command can be used to backup whole or part of the FLASH content. For example, to backup ART data (assuming it's stored in last 64 KB sector in 16 MB FLASH) in 'art_backup.bin' file in TFTP server: tftpp 0x9FFF0000 0x10000 art_backup.bin Important notice: option negotiation mechanism must be enabled in configuration of used TFTP server. --- u-boot/common/cmd_net.c | 24 +++++++- u-boot/include/common.h | 5 +- u-boot/include/net.h | 2 +- u-boot/net/bootp.c | 4 +- u-boot/net/net.c | 17 ++++-- u-boot/net/rarp.c | 2 +- u-boot/net/tftp.c | 132 ++++++++++++++++++++++++++++++---------- u-boot/net/tftp.h | 2 +- 8 files changed, 142 insertions(+), 46 deletions(-) diff --git a/u-boot/common/cmd_net.c b/u-boot/common/cmd_net.c index f02dbaf..939258f 100644 --- a/u-boot/common/cmd_net.c +++ b/u-boot/common/cmd_net.c @@ -30,6 +30,9 @@ #if defined(CONFIG_CMD_NET) +u32 save_addr; /* Default Save Address */ +u32 save_size; /* Default Save Size (in bytes) */ + extern int do_bootm(cmd_tbl_t *, int, int, char *[]); static int netboot_common(proto_t, cmd_tbl_t *, int, char *[]); @@ -41,10 +44,23 @@ U_BOOT_CMD(httpd, 1, 1, do_httpd, "start www server for firmware recovery\n", NU #endif /* CONFIG_CMD_HTTPD */ int do_tftpb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ - return netboot_common(TFTP, cmdtp, argc, argv); + return netboot_common(TFTPGET, cmdtp, argc, argv); } U_BOOT_CMD(tftpboot, 3, 1, do_tftpb, "boot image via network using TFTP protocol\n", "[loadAddress] [bootfilename]\n"); +int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + if (argc < 4) { + print_cmd_help(cmdtp); + return -1; + } + + return netboot_common(TFTPPUT, cmdtp, argc, argv); +} + +U_BOOT_CMD(tftpput, 4, 1, do_tftpput, "send file to TFTP server\n", "address size filename\n" + "\t- sends 'size' of data from 'address' as 'filename' to TFTP server"); + #if defined(CONFIG_CMD_DHCP) int do_dhcp(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){ return netboot_common(DHCP, cmdtp, argc, argv); @@ -154,6 +170,12 @@ static int netboot_common(proto_t proto, cmd_tbl_t *cmdtp, int argc, char *argv[ break; + case 4: + save_addr = simple_strtoul(argv[1], NULL, 16); + save_size = simple_strtoul(argv[2], NULL, 16); + copy_filename(BootFile, argv[3], sizeof(BootFile)); + break; + default: print_cmd_help(cmdtp); diff --git a/u-boot/include/common.h b/u-boot/include/common.h index 6db3a56..a52548e 100644 --- a/u-boot/include/common.h +++ b/u-boot/include/common.h @@ -200,8 +200,9 @@ void flash_perror (int); /* common/cmd_autoscript.c */ int autoscript (ulong addr); -/* Default Load Address */ -extern u32 load_addr; +extern u32 load_addr; /* Default Load Address */ +extern u32 save_addr; /* Default Save Address */ +extern u32 save_size; /* Default Save Size */ /* common/cmd_nvedit.c */ int env_init (void); diff --git a/u-boot/include/net.h b/u-boot/include/net.h index ffecb9b..ac6fddb 100644 --- a/u-boot/include/net.h +++ b/u-boot/include/net.h @@ -343,7 +343,7 @@ extern int NetState; /* Network loop state */ extern int NetRestartWrap; /* Tried all network devices */ #endif -typedef enum { BOOTP, RARP, ARP, TFTP, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP } proto_t; +typedef enum { BOOTP, RARP, ARP, TFTPGET, TFTPPUT, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP } proto_t; /* Set active state */ static inline __attribute__((always_inline)) int eth_init_state_only(bd_t *bis){ diff --git a/u-boot/net/bootp.c b/u-boot/net/bootp.c index 3620948..ed1ec13 100644 --- a/u-boot/net/bootp.c +++ b/u-boot/net/bootp.c @@ -367,7 +367,7 @@ static void BootpHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len) } } - TftpStart(); + TftpStart(TFTPGET); } #endif /* !CONFIG_CMD_DHCP */ @@ -1058,7 +1058,7 @@ static void DhcpHandler(uchar *pkt, unsigned dest, unsigned src, unsigned len) } } - TftpStart(); + TftpStart(TFTPGET); return; } diff --git a/u-boot/net/net.c b/u-boot/net/net.c index 84b5fd7..639faf8 100644 --- a/u-boot/net/net.c +++ b/u-boot/net/net.c @@ -344,7 +344,8 @@ int NetLoop(proto_t protocol){ case SNTP: #endif case NETCONS: - case TFTP: + case TFTPGET: + case TFTPPUT: NetCopyIP(&NetOurIP, &bd->bi_ip_addr); NetOurGatewayIP = getenv_IPaddr("gatewayip"); @@ -357,7 +358,8 @@ int NetLoop(proto_t protocol){ case NFS: #endif case NETCONS: - case TFTP: + case TFTPGET: + case TFTPPUT: NetServerIP = getenv_IPaddr("serverip"); break; #if defined(CONFIG_CMD_PING) @@ -412,10 +414,13 @@ int NetLoop(proto_t protocol){ #ifdef CONFIG_NET_MULTI NetDevExists = 1; #endif + NetBootFileXferSize = 0; + switch(protocol){ - case TFTP: + case TFTPGET: + case TFTPPUT: /* always use ARP to get server ethernet address */ - TftpStart(); + TftpStart(protocol); break; #if defined(CONFIG_CMD_DHCP) @@ -457,7 +462,6 @@ int NetLoop(proto_t protocol){ break; } - NetBootFileXferSize = 0; break; } @@ -1140,7 +1144,8 @@ static int net_check_prereq(proto_t protocol){ case NFS: #endif case NETCONS: - case TFTP: + case TFTPGET: + case TFTPPUT: if(NetServerIP == 0){ printf_err("serverip not set\n"); return(1); diff --git a/u-boot/net/rarp.c b/u-boot/net/rarp.c index e6d89e0..6c5dfd5 100644 --- a/u-boot/net/rarp.c +++ b/u-boot/net/rarp.c @@ -68,7 +68,7 @@ RarpHandler(uchar * dummi0, unsigned dummi1, unsigned dummi2, unsigned dummi3) #endif } } - TftpStart (); + TftpStart (TFTPGET); } diff --git a/u-boot/net/tftp.c b/u-boot/net/tftp.c index 4b9855a..53c6229 100644 --- a/u-boot/net/tftp.c +++ b/u-boot/net/tftp.c @@ -43,6 +43,8 @@ static int TftpServerPort; /* The UDP port at their end */ static int TftpOurPort; /* The UDP port at our end */ static int TftpTimeoutCount; static int TftpState; +static int TftpWriting; /* 1 if writing, else 0 */ +static int TftpFinalBlock; /* 1 if we have sent the last block */ static ulong TftpBlock; /* packet sequence number */ static ulong TftpLastBlock; /* last packet sequence number received */ @@ -54,6 +56,7 @@ static ulong TftpBlockWrapOffset; /* memory offset due to wrapping */ #define STATE_TOO_LARGE 3 #define STATE_BAD_MAGIC 4 #define STATE_OACK 5 +#define STATE_WRQ 7 #define TFTP_BLOCK_SIZE 512 /* default TFTP block size */ #define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) /* sequence number is 16 bit */ @@ -101,13 +104,41 @@ static __inline__ void store_block(unsigned block, uchar * src, unsigned len){ } } +/* Load the next block from memory to be sent over tftp */ +static int load_block(unsigned block, uchar *dst, unsigned len) +{ + ulong offset = (block - 1) * len + TftpBlockWrapOffset; + ulong tosend = len; + + tosend = min(NetBootFileXferSize - offset, tosend); + (void)memcpy(dst, (void *)(save_addr + offset), tosend); + + return tosend; +} + +/* Show download/upload progress */ +static void show_progress(const ulong TftpBlock) +{ + if (((TftpBlock - 1) % 10) == 0) + putc('#'); + else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) + puts("\n "); +} + +static void show_success(void) +{ + puts("\n\nTFTP transfer complete!\n"); + + NetState = NETLOOP_SUCCESS; +} + static void TftpSend(void); static void TftpTimeout(void); /**********************************************************************/ static void TftpSend(void){ - volatile uchar *pkt; + uchar *pkt; volatile uchar *xp; int len = 0; volatile ushort *s; @@ -116,13 +147,14 @@ static void TftpSend(void){ * We will always be sending some sort of packet, so * cobble together the packet headers now. */ - pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE; + pkt = (uchar *)(NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE); switch(TftpState){ case STATE_RRQ: + case STATE_WRQ: xp = pkt; s = (ushort *)pkt; - *s++ = htons(TFTP_RRQ); + *s++ = htons(TftpState == STATE_RRQ ? TFTP_RRQ : TFTP_WRQ); pkt = (uchar *)s; strcpy ((char *)pkt, tftp_filename); @@ -146,9 +178,21 @@ static void TftpSend(void){ case STATE_OACK: xp = pkt; s = (ushort *)pkt; - *s++ = htons(TFTP_ACK); - *s++ = htons(TftpBlock); - pkt = (uchar *)s; + + s[0] = htons(TFTP_ACK); + s[1] = htons(TftpBlock); + pkt = (uchar *)(s + 2); + + if (TftpWriting) { + int toload = TFTP_BLOCK_SIZE; + int loaded = load_block(TftpBlock, pkt, toload); + + s[0] = htons(TFTP_DATA); + pkt += loaded; + + TftpFinalBlock = (loaded < toload); + } + len = pkt - xp; break; @@ -182,12 +226,14 @@ static void TftpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len){ bd_t *bd = gd->bd; ushort proto; ushort *s; + int block; if(dest != TftpOurPort){ return; } - if(TftpState != STATE_RRQ && src != TftpServerPort){ + if (TftpState != STATE_RRQ && TftpState != STATE_WRQ && + src != TftpServerPort) { return; } @@ -202,10 +248,23 @@ static void TftpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len){ proto = *s++; pkt = (uchar *)s; + block = ntohs(*s); + switch(ntohs(proto)){ case TFTP_RRQ: case TFTP_WRQ: + break; + case TFTP_ACK: + if (TftpWriting) { + if (TftpFinalBlock) { + show_success(); + } else { + show_progress(TftpBlock); + TftpBlock = block + 1; + TftpSend(); /* Send next data block */ + } + } break; default: @@ -217,6 +276,13 @@ static void TftpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len){ #endif TftpState = STATE_OACK; TftpServerPort = src; + + if (TftpWriting) { + /* Get ready to send the first block */ + TftpState = STATE_DATA; + TftpBlock++; + } + TftpSend(); /* Send ACK */ break; @@ -239,13 +305,8 @@ static void TftpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len){ TftpBlockWrap++; TftpBlockWrapOffset += TFTP_BLOCK_SIZE * TFTP_SEQUENCE_SIZE; printf("\n %lu MB received\n ", TftpBlockWrapOffset>>20); - } else { - if(((TftpBlock - 1) % 10) == 0){ - putc('#'); - } else if((TftpBlock % (10 * HASHES_PER_LINE)) == 0){ - puts("\n "); - } - } + } else + show_progress(TftpBlock); #ifdef ET_DEBUG if(TftpState == STATE_RRQ){ @@ -287,14 +348,8 @@ static void TftpHandler(uchar * pkt, unsigned dest, unsigned src, unsigned len){ */ TftpSend(); - if(len < TFTP_BLOCK_SIZE){ - /* - * We received the whole thing. Try to - * run it. - */ - puts("\n\nTFTP transfer complete!\n"); - NetState = NETLOOP_SUCCESS; - } + if(len < TFTP_BLOCK_SIZE) + show_success(); break; @@ -320,7 +375,7 @@ static void TftpTimeout(void){ } } -void TftpStart(void){ +void TftpStart(proto_t protocol){ bd_t *bd = gd->bd; #ifdef CONFIG_TFTP_PORT @@ -336,7 +391,7 @@ void TftpStart(void){ tftp_filename = BootFile; } - puts("\nTFTP from IP: "); + printf("\n%s ", protocol == TFTPPUT ? " TFTP to IP:" : "TFTP from IP:"); print_IPaddr(NetServerIP); puts("\n Our IP: "); @@ -355,25 +410,38 @@ void TftpStart(void){ printf("\n Filename: %s", tftp_filename); - if(NetBootFileSize){ - printf("\n Size: 0x%x Bytes = ", NetBootFileSize<<9); - print_size(NetBootFileSize<<9, ""); - } - - printf("\nLoad address: 0x%lx", load_addr); #if defined(CONFIG_NET_MULTI) printf("\n Using: %s", eth_get_name()); #endif - puts("\n\n Loading: *\b"); + TftpWriting = (protocol == TFTPPUT); + + if (TftpWriting) { + printf("\nSave address: 0x%lx", save_addr); + printf("\n Save size: 0x%lx", save_size); + puts("\n\n Sending: *\b"); + + NetBootFileXferSize = save_size; + TftpFinalBlock = 0; + + TftpState = STATE_WRQ; + } else { + printf("\nLoad address: 0x%lx", load_addr); + + if (NetBootFileSize) + printf("\n Load size: 0x%lx", NetBootFileSize << 9); + + puts("\n\n Loading: *\b"); + + TftpState = STATE_RRQ; + } NetSetTimeout(TIMEOUT * CFG_HZ, TftpTimeout); NetSetHandler(TftpHandler); TftpServerPort = WELL_KNOWN_PORT; TftpTimeoutCount = 0; - TftpState = STATE_RRQ; /* Use a pseudo-random port unless a specific port is set */ TftpOurPort = 1024 + (get_timer(0) % 3072); diff --git a/u-boot/net/tftp.h b/u-boot/net/tftp.h index 42678f7..abba625 100644 --- a/u-boot/net/tftp.h +++ b/u-boot/net/tftp.h @@ -14,7 +14,7 @@ */ /* tftp.c */ -extern void TftpStart(void); /* Begin TFTP get */ +extern void TftpStart(proto_t protocol); /* Begin TFTP get */ /**********************************************************************/ -- 2.25.1