Backport tftpput command
authorPiotr Dymacz <pepe2k@gmail.com>
Sun, 5 Feb 2017 15:49:19 +0000 (16:49 +0100)
committerPiotr Dymacz <pepe2k@gmail.com>
Sun, 5 Feb 2017 15:49:19 +0000 (16:49 +0100)
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
u-boot/include/common.h
u-boot/include/net.h
u-boot/net/bootp.c
u-boot/net/net.c
u-boot/net/rarp.c
u-boot/net/tftp.c
u-boot/net/tftp.h

index f02dbaf01128ab178db7f5a80fceb70ea86b95e5..939258f01f475c04660a5a665055ca23258ea11e 100644 (file)
@@ -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);
index 6db3a567ed79a9214f233d85bfeb60d7a4544c8c..a52548e05a8332c90a3f4cfad9fbe863d5aa7d42 100644 (file)
@@ -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);
index ffecb9b6faf3cad8573d31956a715de2f7569989..ac6fddbe5acb2f4b2a4d088c9523e2f3f7482db7 100644 (file)
@@ -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){
index 3620948f2174c004fa2f05c3b3cdfc5a7ef3357c..ed1ec1316dc32243e8d097b7dd8c7e5fef956be9 100644 (file)
@@ -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;
                }
 
index 84b5fd76314758b5487348814c90c6312352f146..639faf8e4df3fc85b9cc4e16e63b1dc6fb823050 100644 (file)
@@ -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);
index e6d89e0d87b319cb2cacbbfc54a82f84aa405157..6c5dfd568c7ded0865de39264e254b8e348b6cc7 100644 (file)
@@ -68,7 +68,7 @@ RarpHandler(uchar * dummi0, unsigned dummi1, unsigned dummi2, unsigned dummi3)
 #endif
                }
        }
-       TftpStart ();
+       TftpStart (TFTPGET);
 }
 
 
index 4b9855aa318f3b0827047dc0c64c797582f338d6..53c622997cfea76014933e8d7283af71626208bb 100644 (file)
@@ -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);
index 42678f797a4e830f5d7e76b7c3772e7648e7f38c..abba6259de308931cc20d7573b55c0e6f9d0daeb 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 /* tftp.c */
-extern void    TftpStart(void);        /* Begin TFTP get */
+extern void    TftpStart(proto_t protocol);    /* Begin TFTP get */
 
 /**********************************************************************/