]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - common/cmd_bootce.c
karo: bootce: add option '-i' to bootce command to init global data struct
[karo-tx-uboot.git] / common / cmd_bootce.c
index 594df392d68a39bf2c9e5b48552c2b542be7f669..c30ed1feeaec843a0496e4977f732b47f59ec098 100644 (file)
+/*
+ * Copyright (C) 2012 Lothar Waßmann <LW@KARO-electronics.de>
+ * based on: code from RedBoot (C) Uwe Steinkohl <US@KARO-electronics.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
 #include <common.h>
 #include <command.h>
 #include <net.h>
 #include <wince.h>
+#include <nand.h>
+#include <malloc.h>
+#include <asm/errno.h>
+#include <jffs2/load_kernel.h>
 
-DECLARE_GLOBAL_DATA_PTR;       /* defines global data structure pointer */
-
+DECLARE_GLOBAL_DATA_PTR;
 
-/*/////////////////////////////////////////////////////////////////////////////////////////////*/
-/* Local macro */
+#define WINCE_VRAM_BASE                0x80000000
+#define CE_FIX_ADDRESS(a)      ((void *)((a) - WINCE_VRAM_BASE + CONFIG_SYS_SDRAM_BASE))
 
-/* Memory macro */
-
-/* #define CE_RAM_BASE                 0x80100000 */
-/* #define CE_WINCE_VRAM_BASE  0x80000000 */
-/* #define CE_FIX_ADDRESS(a)           (((a) - CE_WINCE_VRAM_BASE) + CE_RAM_BASE) */
-#define CE_FIX_ADDRESS(a)              (a)
+#ifndef INT_MAX
+#define INT_MAX                        ((int)(~0U >> 1))
+#endif
 
 /* Bin image parse states */
+#define CE_PS_RTI_ADDR         0
+#define CE_PS_RTI_LEN          1
+#define CE_PS_E_ADDR           2
+#define CE_PS_E_LEN            3
+#define CE_PS_E_CHKSUM         4
+#define CE_PS_E_DATA           5
 
-#define CE_PS_RTI_ADDR                 0
-#define CE_PS_RTI_LEN                  1
-#define CE_PS_E_ADDR                   2
-#define CE_PS_E_LEN                            3
-#define CE_PS_E_CHKSUM                 4
-#define CE_PS_E_DATA                   5
-
-/* Min/max */
-
-#define CE_MIN(a, b)                   (((a) < (b)) ? (a) : (b))
-#define CE_MAX(a, b)                   (((a) > (b)) ? (a) : (b))
-
-// Macro string
-
-#define _STRMAC(s)                             #s
-#define STRMAC(s)                              _STRMAC(s)
-
-
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// Global data
+#define CE_MIN(a, b)           (((a) < (b)) ? (a) : (b))
+#define CE_MAX(a, b)           (((a) > (b)) ? (a) : (b))
 
 static ce_bin __attribute__ ((aligned (32))) g_bin;
 static ce_net __attribute__ ((aligned (32))) g_net;
+static IPaddr_t server_ip;
 
+static void ce_init_bin(ce_bin *bin, unsigned char *dataBuffer)
+{
+       memset(bin, 0, sizeof(*bin));
 
-///////////////////////////////////////////////////////////////////////////////////////////////
-// Local proto
-
+       bin->data = dataBuffer;
+       bin->parseState = CE_PS_RTI_ADDR;
+       bin->parsePtr = (unsigned char *)bin;
+}
 
+static int ce_is_bin_image(void *image, int imglen)
+{
+       if (imglen < CE_BIN_SIGN_LEN) {
+               return 0;
+       }
 
+       return memcmp(image, CE_BIN_SIGN, CE_BIN_SIGN_LEN) == 0;
+}
 
-///////////////////////////////////////////////////////////////////////////////////////////////
-// Implementation
+static const struct ce_magic {
+       char magic[8];
+       size_t size;
+       ce_std_driver_globals drv_glb;
+} ce_magic_template = {
+       .magic = "KARO_CE6",
+       .size = sizeof(ce_std_driver_globals),
+       .drv_glb = {
+               .header = {
+                       .signature = STD_DRV_GLB_SIGNATURE,
+                       .oalVersion = 1,
+                       .bspVersion = 2,
+               },
+       },
+};
 
-int ce_bin_load(void* image, int imglen)
+#ifdef DEBUG
+static void __attribute__((unused)) ce_dump_block(void *ptr, int length)
 {
-       ce_init_bin(&g_bin, image);
+       char *p = ptr;
+       int i;
+       int j;
 
-       g_bin.dataLen = imglen;
+       for (i = 0; i < length; i++) {
+               if (!(i % 16)) {
+                       printf("\n%p: ", ptr + i);
+               }
 
-       if (ce_parse_bin(&g_bin) == CE_PR_EOF)
-       {
-               ce_prepare_run_bin(&g_bin);
-               return 1;
+               printf("%02x ", p[i]);
+               if (!((i + 1) % 16)){
+                       printf("      ");
+                       for (j = i - 15; j <= i; j++){
+                               if((p[j] > 0x1f) && (p[j] < 0x7f)) {
+                                       printf("%c", p[j]);
+                               } else {
+                                       printf(".");
+                               }
+                       }
+               }
        }
-
-       return 0;
+       printf("\n");
+}
+#else
+static inline void ce_dump_block(void *ptr, int length)
+{
 }
+#endif
 
-int ce_is_bin_image(void* image, int imglen)
+static void ce_setup_std_drv_globals(ce_std_driver_globals *std_drv_glb)
 {
-       if (imglen < CE_BIN_SIGN_LEN)
-       {
-               return 0;
+       char *mtdparts = getenv("mtdparts");
+       size_t max_len = ALIGN((unsigned long)std_drv_glb, SZ_4K) -
+               (unsigned long)&std_drv_glb->mtdparts;
+
+       if (eth_get_dev()) {
+               memcpy(&std_drv_glb->kitl.mac, eth_get_dev()->enetaddr,
+                       sizeof(std_drv_glb->kitl.mac));
        }
+       snprintf(std_drv_glb->deviceId, sizeof(std_drv_glb->deviceId),
+               "Triton%02X", eth_get_dev()->enetaddr[5]);
 
-       return (memcmp(image, CE_BIN_SIGN, CE_BIN_SIGN_LEN) == 0);
+       NetCopyIP(&std_drv_glb->kitl.ipAddress, &NetOurIP);
+       std_drv_glb->kitl.ipMask = getenv_IPaddr("netmask");
+       std_drv_glb->kitl.ipRoute = getenv_IPaddr("gatewayip");
+
+       if (mtdparts) {
+               strncpy(std_drv_glb->mtdparts, mtdparts, max_len);
+               std_drv_glb->mtdparts[max_len - 1] = '\0';
+       } else {
+               printf("Failed to get mtdparts environment variable\n");
+       }
 }
 
-void ce_bin_init_parser(void)
+static void ce_init_drv_globals(void)
 {
-       // No buffer address by now, will be specified
-       // latter by the ce_bin_parse_next routine
-
-       ce_init_bin(&g_bin, NULL);
+       struct ce_magic *ce_magic = (void *)CONFIG_SYS_SDRAM_BASE + 0x160;
+       ce_std_driver_globals *std_drv_glb = &ce_magic->drv_glb;
+
+       debug("Copying CE MAGIC from %p to %p..%p\n",
+               &ce_magic_template, ce_magic,
+               (void *)ce_magic + sizeof(*ce_magic) - 1);
+       memcpy(ce_magic, &ce_magic_template, sizeof(*ce_magic));
+
+       ce_setup_std_drv_globals(std_drv_glb);
+       ce_magic->size = sizeof(*std_drv_glb) +
+               strlen(std_drv_glb->mtdparts) + 1;
+       ce_dump_block(ce_magic, offsetof(struct ce_magic, drv_glb) +
+               ce_magic->size);
 }
 
-int ce_bin_parse_next(void* parseBuffer, int len)
+static void ce_prepare_run_bin(ce_bin *bin)
 {
-       int rc;
-
-       g_bin.data = (unsigned char*)parseBuffer;
-       g_bin.dataLen = len;
-       rc = ce_parse_bin(&g_bin);
+       /* Clear os RAM area (if needed) */
+       if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
+               debug("cleaning memory from %p to %p\n",
+                       bin->eRamStart, bin->eRamStart + bin->eRamLen);
 
-       if (rc == CE_PR_EOF)
-       {
-               ce_prepare_run_bin(&g_bin);
+               printf("Preparing clean boot ... ");
+               memset(bin->eRamStart, 0, bin->eRamLen);
+               printf("ok\n");
        }
 
-       return rc;
+       ce_init_drv_globals();
+
+       /*
+        * Make sure, all the above makes it into SDRAM because
+        * WinCE switches the cache & MMU off, obviously without
+        * flushing it first!
+        */
+       flush_dcache_all();
 }
 
-void ce_init_bin(ce_bin* bin, unsigned char* dataBuffer)
+static int ce_lookup_ep_bin(ce_bin *bin)
 {
-       memset(bin, 0, sizeof(ce_bin));
+       ce_rom_hdr *header;
+       ce_toc_entry *tentry;
+       e32_rom *e32;
+       unsigned int i;
+       uint32_t *sig = (uint32_t *)(bin->rtiPhysAddr + ROM_SIGNATURE_OFFSET);
 
-       bin->data = dataBuffer;
-       bin->parseState = CE_PS_RTI_ADDR;
-       bin->parsePtr = (unsigned char*)&bin->rtiPhysAddr;
+       debug("Looking for TOC signature at %p\n", sig);
+
+       /* Check image Table Of Contents (TOC) signature */
+       if (*sig != ROM_SIGNATURE) {
+               printf("Error: Did not find image TOC signature!\n");
+               printf("Expected %08x at address %p; found %08x instead\n",
+                       ROM_SIGNATURE, sig, *sig);
+               return 0;
+       }
+
+       /* Lookup entry point */
+       header = CE_FIX_ADDRESS(*(unsigned int *)(bin->rtiPhysAddr +
+                                               ROM_SIGNATURE_OFFSET +
+                                               sizeof(unsigned int)));
+       tentry = (ce_toc_entry *)(header + 1);
+
+       for (i = 0; i < header->nummods; i++) {
+               // Look for 'nk.exe' module
+               if (strcmp(CE_FIX_ADDRESS(tentry[i].fileName), "nk.exe") == 0) {
+                       // Save entry point and RAM addresses
+
+                       e32 = CE_FIX_ADDRESS(tentry[i].e32Offset);
+
+                       bin->eEntryPoint = CE_FIX_ADDRESS(tentry[i].loadOffset) +
+                               e32->e32_entryrva;
+                       bin->eRamStart = CE_FIX_ADDRESS(header->ramStart);
+                       bin->eRamLen = header->ramEnd - header->ramStart;
+                       return 1;
+               }
+       }
+
+       // Error: Did not find 'nk.exe' module
+       return 0;
 }
 
-int ce_parse_bin(ce_bin* bin)
+static int ce_parse_bin(ce_bin *bin)
 {
-       unsigned charpbData = bin->data;
-       int pbLen = bin->dataLen;
+       unsigned char *pbData = bin->data;
+       int len = bin->dataLen;
        int copyLen;
 
-       #ifdef DEBUG
-       printf("starting ce image parsing:\n\tbin->binLen: 0x%08X\n", bin->binLen);
-       printf("\tpbData: 0x%08X        pbLEN: 0x%08X\n", pbData, pbLen);
-       #endif
+       debug("starting ce image parsing:\n\tbin->binLen: 0x%08X\n", bin->binLen);
 
-       if (pbLen)
-       {
-               if (bin->binLen == 0)
-               {
+       if (len) {
+               if (bin->binLen == 0) {
                        // Check for the .BIN signature first
-
-                       if (!ce_is_bin_image(pbData, pbLen))
-                       {
+                       if (!ce_is_bin_image(pbData, len)) {
                                printf("Error: Invalid or corrupted .BIN image!\n");
-
                                return CE_PR_ERROR;
                        }
 
                        printf("Loading Windows CE .BIN image ...\n");
-
                        // Skip signature
-
-                       pbLen -= CE_BIN_SIGN_LEN;
+                       len -= CE_BIN_SIGN_LEN;
                        pbData += CE_BIN_SIGN_LEN;
                }
 
-               while (pbLen)
-               {
-                       switch (bin->parseState)
-                       {
+               while (len) {
+                       switch (bin->parseState) {
                        case CE_PS_RTI_ADDR:
                        case CE_PS_RTI_LEN:
                        case CE_PS_E_ADDR:
                        case CE_PS_E_LEN:
                        case CE_PS_E_CHKSUM:
-
-                               copyLen = CE_MIN(sizeof(unsigned int) - bin->parseLen, pbLen);
-
-                               memcpy(&bin->parsePtr[ bin->parseLen ], pbData, copyLen);
+                               copyLen = CE_MIN(sizeof(unsigned int) - bin->parseLen, len);
+                               memcpy(&bin->parsePtr[bin->parseLen], pbData, copyLen);
 
                                bin->parseLen += copyLen;
-                               pbLen -= copyLen;
+                               len -= copyLen;
                                pbData += copyLen;
 
-                               if (bin->parseLen == sizeof(unsigned int))
-                               {
+                               if (bin->parseLen == sizeof(unsigned int)) {
                                        if (bin->parseState == CE_PS_RTI_ADDR)
-                                       {
                                                bin->rtiPhysAddr = CE_FIX_ADDRESS(bin->rtiPhysAddr);
-                                       }
-                                       else if (bin->parseState == CE_PS_E_ADDR)
-                                       {
-                                               if (bin->ePhysAddr)
-                                               {
-                                                       bin->ePhysAddr = CE_FIX_ADDRESS(bin->ePhysAddr);
-                                               }
-                                       }
+                                       else if (bin->parseState == CE_PS_E_ADDR &&
+                                               bin->ePhysAddr)
+                                               bin->ePhysAddr = CE_FIX_ADDRESS(bin->ePhysAddr);
 
-                                       bin->parseState ++;
+                                       bin->parseState++;
                                        bin->parseLen = 0;
                                        bin->parsePtr += sizeof(unsigned int);
 
-                                       if (bin->parseState == CE_PS_E_DATA)
-                                       {
-                                               if (bin->ePhysAddr)
-                                               {
-                                                       bin->parsePtr = (unsigned char*)(bin->ePhysAddr);
+                                       if (bin->parseState == CE_PS_E_DATA) {
+                                               if (bin->ePhysAddr) {
+                                                       bin->parsePtr = bin->ePhysAddr;
                                                        bin->parseChkSum = 0;
-                                               }
-                                               else
-                                               {
-                                                       // EOF
-
-                                                       pbLen = 0;
+                                               } else {
+                                                       /* EOF */
+                                                       len = 0;
                                                        bin->endOfBin = 1;
                                                }
                                        }
                                }
-
                                break;
 
                        case CE_PS_E_DATA:
-
-                               if (bin->ePhysAddr)
-                               {
-                                       copyLen = CE_MIN(bin->ePhysLen - bin->parseLen, pbLen);
+                               debug("ePhysAddr=%p physlen=%08x parselen=%08x\n",
+                                       bin->ePhysAddr, bin->ePhysLen, bin->parseLen);
+                               if (bin->ePhysAddr) {
+                                       copyLen = CE_MIN(bin->ePhysLen - bin->parseLen, len);
                                        bin->parseLen += copyLen;
-                                       pbLen -= copyLen;
+                                       len -= copyLen;
 
-                                       #ifdef DEBUG
-                                       printf("copy %d bytes from: 0x%08X    to:  0x%08X\n", copyLen, pbData, bin->parsePtr);
-                                       #endif
-                                       while (copyLen --)
-                                       {
+                                       while (copyLen--) {
                                                bin->parseChkSum += *pbData;
-                                               *bin->parsePtr ++ = *pbData ++;
+                                               *bin->parsePtr++ = *pbData++;
                                        }
 
-                                       if (bin->parseLen == bin->ePhysLen)
-                                       {
-                                               printf("Section [%02d]: address 0x%08X, size 0x%08X, checksum %s\n",
-                                                       bin->secion,
+                                       if (bin->parseLen == bin->ePhysLen) {
+                                               printf("Section [%02d]: address %p, size 0x%08X, checksum %s\n",
+                                                       bin->section,
                                                        bin->ePhysAddr,
                                                        bin->ePhysLen,
                                                        (bin->eChkSum == bin->parseChkSum) ? "ok" : "fail");
 
-                                               if (bin->eChkSum != bin->parseChkSum)
-                                               {
-                                                       // Checksum error!
-
+                                               if (bin->eChkSum != bin->parseChkSum) {
                                                        printf("Error: Checksum error, corrupted .BIN file!\n");
-
+                                                       printf("checksum calculated: 0x%08x from file: 0x%08x\n",
+                                                               bin->parseChkSum, bin->eChkSum);
                                                        bin->binLen = 0;
-
                                                        return CE_PR_ERROR;
                                                }
 
-                                               bin->secion ++;
+                                               bin->section++;
                                                bin->parseState = CE_PS_E_ADDR;
                                                bin->parseLen = 0;
-                                               bin->parsePtr = (unsigned char*)(&bin->ePhysAddr);
+                                               bin->parsePtr = (unsigned char *)&bin->ePhysAddr;
                                        }
-                               }
-                               else
-                               {
+                               } else {
                                        bin->parseLen = 0;
                                        bin->endOfBin = 1;
-                                       pbLen = 0;
+                                       len = 0;
                                }
-
                                break;
                        }
                }
        }
 
-       if (bin->endOfBin)
-       {
-               // Find entry point
-
-               if (!ce_lookup_ep_bin(bin))
-               {
+       if (bin->endOfBin) {
+               if (!ce_lookup_ep_bin(bin)) {
                        printf("Error: entry point not found!\n");
-
                        bin->binLen = 0;
-
                        return CE_PR_ERROR;
                }
 
-               printf("Entry point: 0x%08X, address range: 0x%08X-0x%08X\n",
+               printf("Entry point: %p, address range: %p-%p\n",
                        bin->eEntryPoint,
                        bin->rtiPhysAddr,
                        bin->rtiPhysAddr + bin->rtiPhysLen);
@@ -277,651 +345,481 @@ int ce_parse_bin(ce_bin* bin)
                return CE_PR_EOF;
        }
 
-       // Need more data
-
+       /* Need more data */
        bin->binLen += bin->dataLen;
-
        return CE_PR_MORE;
 }
 
-
-
-
-
-
-
-void ce_prepare_run_bin(ce_bin* bin)
+static int ce_bin_load(void *image, int imglen)
 {
-       ce_driver_globals* drv_glb;
-       char    *e, *s;
-       char    tmp[64];
-       int                             i;
-
-
-       // Clear os RAM area (if needed)
-
-       //if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT)
-       {
-               #ifdef DEBUG
-               printf("cleaning memory from 0x%08X to 0x%08X\n", bin->eRamStart, bin->eRamStart + bin->eRamLen);
-               #endif
-               printf("Preparing clean boot ... ");
-               memset((void*)bin->eRamStart, 0, bin->eRamLen);
-               printf("ok\n");
-       }
-
-       // Prepare driver globals (if needed)
-
-       if (bin->eDrvGlb)
-       {
-               drv_glb = (ce_driver_globals*)bin->eDrvGlb;
-
-               // Fill out driver globals
-
-               memset(drv_glb, 0, sizeof(ce_driver_globals));
-
-               // Signature
-
-               drv_glb->signature = DRV_GLB_SIGNATURE;
-
-               // No flags by now
-
-               drv_glb->flags = 0;
-
-               /* Local ethernet MAC address */
-               i = getenv_r ("ethaddr", tmp, sizeof (tmp));
-               s = (i > 0) ? tmp : 0;
-
-               for (i = 0; i < 6; ++i) {
-                       drv_glb->macAddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
-                       if (s)
-                               s = (*e) ? e + 1 : e;
-               }
-
-
-               #ifdef DEBUG
-               printf("got MAC address %02X:%02X:%02X:%02X:%02X:%02X from environment\n", drv_glb->macAddr[0],drv_glb->macAddr[1],drv_glb->macAddr[2],drv_glb->macAddr[3],drv_glb->macAddr[4],drv_glb->macAddr[5]);
-               #endif
-
-               /* Local IP address */
-               drv_glb->ipAddr=(unsigned int)getenv_IPaddr("ipaddr");
-               #ifdef DEBUG
-               printf("got IP address ");
-               print_IPaddr((IPaddr_t)drv_glb->ipAddr);
-               printf(" from environment\n");
-               #endif
-
-               /* Subnet mask */
-               drv_glb->ipMask=(unsigned long)getenv_IPaddr("netmask");
-               #ifdef DEBUG
-               printf("got IP mask ");
-               print_IPaddr((IPaddr_t)drv_glb->ipMask);
-               printf(" from environment\n");
-               #endif
-
-               /* Gateway config */
-               drv_glb->ipGate=(unsigned long)getenv_IPaddr("gatewayip");
-               #ifdef DEBUG
-               printf("got gateway address ");
-               print_IPaddr((IPaddr_t)drv_glb->ipGate);
-               printf(" from environment\n");
-               #endif
-
-
-
-
-
-               // EDBG services config
-
-               memcpy(&drv_glb->edbgConfig, &bin->edbgConfig, sizeof(bin->edbgConfig));
-
-
-
-
-       }
-
-}
-
-
-int ce_lookup_ep_bin(ce_bin* bin)
-{
-       ce_rom_hdr* header;
-       ce_toc_entry* tentry;
-       e32_rom* e32;
-       unsigned int i;
-
-       // Check image Table Of Contents (TOC) signature
-
-       if (*(unsigned int*)(bin->rtiPhysAddr + ROM_SIGNATURE_OFFSET) != ROM_SIGNATURE)
-       {
-               // Error: Did not find image TOC signature!
-
-               return 0;
-       }
-
-
-       // Lookup entry point
-
-       header = (ce_rom_hdr*)CE_FIX_ADDRESS(*(unsigned int*)(bin->rtiPhysAddr + ROM_SIGNATURE_OFFSET + sizeof(unsigned int)));
-       tentry = (ce_toc_entry*)(header + 1);
-
-       for (i = 0; i < header->nummods; i ++)
-       {
-               // Look for 'nk.exe' module
-
-               if (strcmp((char*)CE_FIX_ADDRESS(tentry[ i ].fileName), "nk.exe") == 0)
-               {
-                       // Save entry point and RAM addresses
-
-                       e32 = (e32_rom*)CE_FIX_ADDRESS(tentry[ i ].e32Offset);
-
-                       bin->eEntryPoint = CE_FIX_ADDRESS(tentry[ i ].loadOffset) + e32->e32_entryrva;
-                       bin->eRamStart = CE_FIX_ADDRESS(header->ramStart);
-                       bin->eRamLen = header->ramEnd - header->ramStart;
-
-                       // Save driver_globals address
-                       // Must follow RAM section in CE config.bib file
-                       //
-                       // eg.
-                       //
-                       // RAM          80900000        03200000        RAM
-                       // DRV_GLB      83B00000        00001000        RESERVED
-                       //
-
-                       bin->eDrvGlb = CE_FIX_ADDRESS(header->ramEnd);
-
-                       return 1;
-               }
+       ce_init_bin(&g_bin, image);
+       g_bin.dataLen = imglen;
+       if (ce_parse_bin(&g_bin) == CE_PR_EOF) {
+               ce_prepare_run_bin(&g_bin);
+               return 1;
        }
 
-       // Error: Did not find 'nk.exe' module
-
        return 0;
 }
 
-
-
-
-typedef void (*CeEntryPointPtr)(void);
-
-
-
-void ce_run_bin(ce_bin* bin)
+static void ce_run_bin(void (*entry)(void))
 {
-       CeEntryPointPtr EnrtryPoint;
-
        printf("Launching Windows CE ...\n");
-
-
-       EnrtryPoint = (CeEntryPointPtr)bin->eEntryPoint;
-
-       EnrtryPoint();
-
+#ifdef TEST_LAUNCH
+return;
+#endif
+       entry();
 }
 
-int ce_boot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+static int do_bootce(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
-       unsigned long   addr;
-       unsigned long   image_size;
-       unsigned char   *s;
-
+       void *addr;
+       size_t image_size;
 
-       if (argc < 2) {
-               printf ("myUsage:\n%s\n", cmdtp->usage);
-               return 1;
+       if (argc > 1) {
+               if (strcmp(argv[1], "-i") == 0) {
+                       ce_init_drv_globals();
+                       return CMD_RET_SUCCESS;
+               }
+               addr = (void *)simple_strtoul(argv[1], NULL, 16);
+               image_size = INT_MAX;           /* actually we do not know the image size */
+       } else if (getenv("fileaddr") != NULL) {
+               addr = (void *)getenv_ulong("fileaddr", 16, 0);
+               image_size = getenv_ulong("filesize", 16, INT_MAX);
+       } else {
+               return CMD_RET_USAGE;
        }
 
-       addr = simple_strtoul(argv[1], NULL, 16);
-       image_size = 0x7fffffff;                /* actually we do not know the image size */
-
-       printf ("## Booting Windows CE Image from address 0x%08lX ...\n", addr);
-
+       printf ("## Booting Windows CE Image from address %p ...\n", addr);
 
        /* check if there is a valid windows CE image */
-       if (ce_is_bin_image((void *)addr, image_size))
-       {
-               if (!ce_bin_load((void*)addr, image_size))
-               {
-                       /* Ops! Corrupted .BIN image! */
-                       /* Handle error here ...      */
-                       printf("corrupted .BIN image !!!\n");
-                       return 1;
-
-               }
-               if ((s = getenv("autostart")) != NULL) {
-                       if (*s == 'n') {
-                               /*
-                               * just use bootce to load the image to SDRAM;
-                               * Do not start it automatically.
-                               */
-                               return 0;
-                       }
+       if (ce_is_bin_image(addr, image_size)) {
+               if (!ce_bin_load(addr, image_size)) {
+                       /* Ops! Corrupted .BIN image! */
+                       /* Handle error here ...      */
+                       printf("corrupted .BIN image !!!\n");
+                       return CMD_RET_FAILURE;
                }
-       ce_run_bin(&g_bin);             /* start the image */
-
-       } else {
-               printf("Image seems to be no valid Windows CE image !\n");
-               return 1;
-
-       }
-       return 1;       /* never reached - just to keep compiler happy */
-
-
+               if (getenv_yesno("autostart") != 1) {
+                       /*
+                        * just use bootce to load the image to SDRAM;
+                        * Do not start it automatically.
+                        */
+                       setenv_addr("fileaddr", g_bin.eEntryPoint);
+                       return CMD_RET_SUCCESS;
+               }
+               ce_run_bin(g_bin.eEntryPoint);          /* start the image */
+       } else {
+               printf("Image does not seem to be a valid Windows CE image!\n");
+               return CMD_RET_FAILURE;
+       }
+       return CMD_RET_FAILURE; /* never reached - just to keep compiler happy */
 }
-
-
-
 U_BOOT_CMD(
-       bootce, 2,      0,      ce_boot,
-       "bootce\t- Boot a Windows CE image from memory \n",
-       "[args..]\n"
-       "\taddr\t\t-boot image from address addr\n"
+       bootce, 2, 0, do_bootce,
+       "Boot a Windows CE image from RAM",
+       "[addr]\n"
+       "\taddr\t\tboot image from address addr (default ${fileaddr})\n"
+       "or\n"
+       "\t-i\t\tinitialize the WinCE globals data structure (before loading a .nb0 image)"
 );
 
-
-
-#if 1
-static void wince_handler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
+#ifdef CONFIG_CMD_NAND
+static int ce_nand_load(ce_bin *bin, loff_t *offset, void *buf, size_t max_len)
 {
-
-
-       NetState = NETLOOP_SUCCESS;     /* got input - quit net loop */
-       if(!memcmp(g_net.data + g_net.align_offset, gd->bd->bi_enetaddr, 6)) {
-               g_net.got_packet_4me=1;
-               g_net.dataLen=len;
-       } else {
-               g_net.got_packet_4me=0;
-               return;
+       int ret;
+       size_t len = max_len;
+       nand_info_t *nand = &nand_info[0];
+
+       while (nand_block_isbad(nand, *offset & ~(max_len - 1))) {
+               printf("Skipping bad block 0x%08llx\n",
+                       *offset & ~(max_len - 1));
+               *offset += max_len;
+               if (*offset + max_len > nand->size)
+                       return -EINVAL;
        }
 
-       if(1) {
-               g_net.srvAddrRecv.sin_port = ntohs(*((unsigned short *)(g_net.data + ETHER_HDR_SIZE + IP_HDR_SIZE_NO_UDP + g_net.align_offset)));
-               NetCopyIP(&g_net.srvAddrRecv.sin_addr, g_net.data + ETHER_HDR_SIZE + g_net.align_offset + 12);
-               memcpy(NetServerEther, g_net.data + g_net.align_offset +6, 6);
-
-               #if 0
-               printf("received packet:   buffer 0x%08X   Laenge %d \n", (unsigned long) pkt, len);
-               printf("from ");
-               print_IPaddr(g_net.srvAddrRecv.sin_addr);
-               printf(", port: %d\n", g_net.srvAddrRecv.sin_port);
-
-
-
-               ce_dump_block(pkt, len);
-
-               printf("Headers:\n");
-               ce_dump_block(pkt - ETHER_HDR_SIZE - IP_HDR_SIZE, ETHER_HDR_SIZE + IP_HDR_SIZE);
-               printf("\n\nmy port should be: %d\n", ntohs(*((unsigned short *)(g_net.data + ETHER_HDR_SIZE + IP_HDR_SIZE_NO_UDP + g_net.align_offset +2))));
-               #endif
-       }
+       ret = nand_read(nand, *offset, &len, buf);
+       if (ret < 0)
+               return ret;
 
+       bin->dataLen = len;
+       return len;
 }
 
+static int do_nbootce(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+       int ret;
+       struct mtd_device *dev;
+       struct part_info *part_info;
+       u8 part_num;
+       loff_t offset;
+       char *end;
+       void *buffer;
+       size_t bufsize = nand_info[0].erasesize, len;
+
+       if (argc < 2 || argc > 3)
+               return CMD_RET_USAGE;
+
+       ret = mtdparts_init();
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       offset = simple_strtoul(argv[1], &end, 16);
+       if (*end != '\0') {
+               ret = find_dev_and_part(argv[1], &dev, &part_num,
+                                       &part_info);
+               if (ret != 0) {
+                       printf("Partition '%s' not found\n", argv[1]);
+                       return CMD_RET_FAILURE;
+               }
+               offset = part_info->offset;
+               printf ("## Booting Windows CE Image from NAND partition %s at offset %08llx\n",
+                       argv[1], offset);
+       } else {
+               printf ("## Booting Windows CE Image from NAND offset %08llx\n",
+                       offset);
+       }
 
+       buffer = malloc(bufsize);
+       if (buffer == NULL) {
+               printf("Failed to allocate %u byte buffer\n", bufsize);
+               return CMD_RET_FAILURE;
+       }
 
-/* returns packet lengt if successfull */
-int ce_recv_packet(char *buf, int len, struct sockaddr_in *from, struct sockaddr_in *local, struct timeval *timeout){
-
-       int rxlength;
-       ulong time_started;
-
-
-
-       g_net.got_packet_4me=0;
-       time_started = get_timer(0);
+       ce_init_bin(&g_bin, buffer);
 
+       ret = ce_nand_load(&g_bin, &offset, buffer, bufsize);
+       if (ret < 0) {
+               printf("Failed to read NAND: %d\n", ret);
+               goto err;
+       }
+       len = ret;
+       /* check if there is a valid windows CE image header */
+       if (ce_is_bin_image(buffer, len)) {
+               do {
+                       ret = ce_parse_bin(&g_bin);
+                       switch (ret) {
+                       case CE_PR_MORE:
+                       {
+                               if (ctrlc()) {
+                                       printf("NBOOTCE - canceled by user\n");
+                                       goto err;
+                               }
+                               offset += len;
+                               len = ce_nand_load(&g_bin, &offset, buffer,
+                                               bufsize);
+                               if (len < 0) {
+                                       printf("Nand read error: %d\n", len);
+                                       ret = len;
+                                       goto err;
+                               }
+                       }
+                       break;
 
-       NetRxPackets[0] = (uchar *)buf;
-       NetSetHandler(wince_handler);
+                       case CE_PR_EOF:
+                               ce_prepare_run_bin(&g_bin);
+                               break;
 
-       while(1) {
-               rxlength=eth_rx();
-               if(g_net.got_packet_4me)
-                       return g_net.dataLen;
-               /* check for timeout */
-               if (get_timer(time_started) > timeout->tv_sec * CFG_HZ) {
-                       return -1;
+                       case CE_PR_ERROR:
+                               break;
+                       }
+               } while (ret == CE_PR_MORE);
+               free(buffer);
+               if (ret != CE_PR_EOF)
+                       return CMD_RET_FAILURE;
+
+               if (getenv_yesno("autostart") != 1) {
+                       /*
+                        * just use bootce to load the image to SDRAM;
+                        * Do not start it automatically.
+                        */
+                       setenv_addr("fileaddr", g_bin.eEntryPoint);
+                       return CMD_RET_SUCCESS;
                }
+               ce_run_bin(g_bin.eEntryPoint);          /* start the image */
+       } else {
+               printf("Image does not seem to be a valid Windows CE image!\n");
        }
+err:
+       free(buffer);
+       return CMD_RET_FAILURE;
 }
+U_BOOT_CMD(
+       nbootce, 2, 0, do_nbootce,
+       "Boot a Windows CE image from NAND",
+       "off|partitition\n"
+       "\toff\t\t- flash offset (hex)\n"
+       "\tpartition\t- partition name"
+);
+#endif
 
-
-
-int ce_recv_frame(ce_net* net, int timeout)
+static int ce_send_write_ack(ce_net *net)
 {
-       struct timeval timeo;
-
-       // Setup timeout
-
-       timeo.tv_sec = timeout;
-       timeo.tv_usec = 0;
-
-       /* Receive UDP packet */
-
-       net->dataLen = ce_recv_packet(net->data+net->align_offset, sizeof(net->data)-net->align_offset, &net->srvAddrRecv, &net->locAddr, &timeo);
-
-       if (net->dataLen < 0)
-       {
-               /* Error! No data available */
-
-               net->dataLen = 0;
-       }
-
-       return net->dataLen;
+       int ret;
+       unsigned short wdata[2];
+       int retries = 0;
+
+       wdata[0] = htons(EDBG_CMD_WRITE_ACK);
+       wdata[1] = htons(net->blockNum);
+       net->dataLen = sizeof(wdata);
+       memcpy(net->data, wdata, net->dataLen);
+
+       do {
+               ret = bootme_send_frame(net->data, net->dataLen);
+               if (ret) {
+                       printf("Failed to send write ack %d; retries=%d\n",
+                               ret, retries);
+               }
+       } while (ret != 0 && retries-- > 0);
+       return ret;
 }
 
-int ce_process_download(ce_net* net, ce_bin* bin)
+static enum bootme_state ce_process_download(ce_net *net, ce_bin *bin)
 {
-       int ret = CE_PR_MORE;
+       int ret = net->state;
 
-       if (net->dataLen >= 2)
-       {
+       if (net->dataLen >= 4) {
                unsigned short command;
+               unsigned short blknum;
 
-               command = ntohs(*(unsigned short*)(net->data+CE_DOFFSET));
+               memcpy(&command, net->data, sizeof(command));
+               command = ntohs(command);
+               debug("command found: 0x%04X\n", command);
 
-               #ifdef DEBUG
-               printf("command found: 0x%04X\n", command);
-               #endif
+               if (net->state == BOOTME_DOWNLOAD) {
+                       unsigned short nxt = net->blockNum + 1;
 
-               switch (command)
-               {
-               case EDBG_CMD_WRITE_REQ:
+                       memcpy(&blknum, &net->data[2], sizeof(blknum));
+                       blknum = ntohs(blknum);
+                       if (blknum == nxt) {
+                               net->blockNum = blknum;
+                       } else {
+                               int rc = ce_send_write_ack(net);
 
-                       if (!net->link)
-                       {
-                               // Check file name for WRITE request
-                               // CE EShell uses "boot.bin" file name
+                               if (net->verbose)
+                                       printf("Dropping out of sequence packet with ID %d (expected %d)\n",
+                                               blknum, nxt);
+                               if (rc != 0)
+                                       return rc;
 
-                               /*printf(">>>>>>>> First Frame, IP: %s, port: %d\n",
-                                                       inet_ntoa((in_addr_t *)&net->srvAddrRecv),
-                                                       net->srvAddrRecv.sin_port);*/
+                               return ret;
+                       }
+               }
 
-                               if (strncmp((char*)(net->data +CE_DOFFSET + 2), "boot.bin", 8) == 0)
-                               {
+               switch (command) {
+               case EDBG_CMD_WRITE_REQ:
+                       if (net->state == BOOTME_INIT) {
+                               // Check file name for WRITE request
+                               // CE EShell uses "boot.bin" file name
+                               if (strncmp((char *)&net->data[2],
+                                               "boot.bin", 8) == 0) {
                                        // Some diag output
-
-                                       if (net->verbose)
-                                       {
-                                               printf("Locked Down download link, IP: ");
-                                               print_IPaddr(net->srvAddrRecv.sin_addr);
-                                               printf(", port: %d\n", net->srvAddrRecv.sin_port);
+                                       if (net->verbose) {
+                                               printf("Locked Down download link, IP: %pI4\n",
+                                                       &NetServerIP);
+                                               printf("Sending BOOTME request [%d] to %pI4\n",
+                                                       net->seqNum, &NetServerIP);
                                        }
 
-
-
-
-                                       if (net->verbose)
-                                               {
-                                               printf("Sending BOOTME request [%d] to ", (int)net->secNum);
-                                               print_IPaddr(net->srvAddrSend.sin_addr);
-                                               printf("\n");
-                                       }
-
-
-
-
                                        // Lock down EShell download link
-
-                                       net->locAddr.sin_port = (EDBG_DOWNLOAD_PORT + 1);
-                                       net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
-                                       net->srvAddrSend.sin_addr = net->srvAddrRecv.sin_addr;
-                                       net->link = 1;
-                               }
-                               else
-                               {
+                                       ret = BOOTME_DOWNLOAD;
+                               } else {
                                        // Unknown link
-
-                                       net->srvAddrRecv.sin_port = 0;
+                                       printf("Unknown link\n");
                                }
 
-                               // Return write ack
-
-                               if (net->link)
-                               {
-                                       ce_send_write_ack(net);
+                               if (ret == BOOTME_DOWNLOAD) {
+                                       int rc = ce_send_write_ack(net);
+                                       if (rc != 0)
+                                               return rc;
                                }
-
-                               break;
                        }
+                       break;
 
                case EDBG_CMD_WRITE:
-
-                       /* Fix data len */
+                       /* Fixup data len */
+                       bin->data = &net->data[4];
                        bin->dataLen = net->dataLen - 4;
-
-                       // Parse next block of .bin file
-
                        ret = ce_parse_bin(bin);
-
-                       // Request next block
-
-                       if (ret != CE_PR_ERROR)
-                       {
-                               net->blockNum ++;
-
-                               ce_send_write_ack(net);
+                       if (ret != CE_PR_ERROR) {
+                               int rc = ce_send_write_ack(net);
+                               if (rc)
+                                       return rc;
+                               if (ret == CE_PR_EOF)
+                                       ret = BOOTME_DONE;
+                       } else {
+                               ret = BOOTME_ERROR;
                        }
-
                        break;
 
                case EDBG_CMD_READ_REQ:
-
-                       // Read requests are not supported
-                       // Do nothing ...
-
+                       printf("Ignoring EDBG_CMD_READ_REQ\n");
+                       /* Read requests are not supported
+                        * Do nothing ...
+                        */
                        break;
 
                case EDBG_CMD_ERROR:
-
-                       // Error condition on the host side
-
                        printf("Error: unknown error on the host side\n");
 
                        bin->binLen = 0;
-                       ret = CE_PR_ERROR;
-
+                       ret = BOOTME_ERROR;
                        break;
+
                default:
-                       printf("unknown command 0x%04X ????\n", command);
-                       while(1);
+                       printf("unknown command 0x%04X\n", command);
+                       net->state = BOOTME_ERROR;
                }
-
-
        }
-
        return ret;
 }
 
-
-
-void ce_init_edbg_link(ce_net* net)
-{
-       /* Initialize EDBG link for commands */
-
-       net->locAddr.sin_port = EDBG_DOWNLOAD_PORT;
-       net->srvAddrSend.sin_port = EDBG_DOWNLOAD_PORT;
-       net->srvAddrRecv.sin_port = 0;
-       net->link = 0;
-}
-
-void ce_process_edbg(ce_net* net, ce_bin* bin)
+static enum bootme_state ce_process_edbg(ce_net *net, ce_bin *bin)
 {
-       eth_dbg_hdr* header;
+       enum bootme_state ret = net->state;
+       eth_dbg_hdr header;
 
-
-
-       if (net->dataLen < sizeof(eth_dbg_hdr))
-       {
+       if (net->dataLen < sizeof(header)) {
                /* Bad packet */
-
-               net->srvAddrRecv.sin_port = 0;
-               return;
+               printf("Invalid packet size %u\n", net->dataLen);
+               net->dataLen = 0;
+               return ret;
        }
-
-       header = (eth_dbg_hdr*)(net->data + net->align_offset + ETHER_HDR_SIZE + IP_HDR_SIZE);
-
-       if (header->id != EDBG_ID)
-       {
+       memcpy(&header, net->data, sizeof(header));
+       if (header.id != EDBG_ID) {
                /* Bad packet */
-
-               net->srvAddrRecv.sin_port = 0;
-               return;
+               printf("Bad EDBG ID %08x\n", header.id);
+               net->dataLen = 0;
+               return ret;
        }
 
-       if (header->service != EDBG_SVC_ADMIN)
-       {
+       if (header.service != EDBG_SVC_ADMIN) {
                /* Unknown service */
-
-               return;
+               printf("Bad EDBG service %02x\n", header.service);
+               net->dataLen = 0;
+               return ret;
        }
 
-       if (!net->link)
-       {
+       if (net->state == BOOTME_INIT) {
                /* Some diag output */
-
-               if (net->verbose)
-               {
-                       printf("Locked Down EDBG service link, IP: ");
-                       print_IPaddr(net->srvAddrRecv.sin_addr);
-                       printf(", port: %d\n", net->srvAddrRecv.sin_port);
+               if (net->verbose) {
+                       printf("Locked Down EDBG service link, IP: %pI4\n",
+                               &NetServerIP);
                }
 
                /* Lock down EDBG link */
-
-               net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
-               net->link = 1;
+               net->state = BOOTME_DEBUG;
        }
 
-       switch (header->cmd)
-       {
+       switch (header.cmd) {
        case EDBG_CMD_JUMPIMG:
-
                net->gotJumpingRequest = 1;
 
-               if (net->verbose)
-               {
+               if (net->verbose) {
                        printf("Received JUMPING command\n");
                }
-
-               /* Just pass through and copy CONFIG structure  */
-
+               /* Just pass through and copy CONFIG structure */
+               ret = BOOTME_DONE;
        case EDBG_CMD_OS_CONFIG:
-
                /* Copy config structure */
-
-               memcpy(&bin->edbgConfig, header->data, sizeof(edbg_os_config_data));
-
-               if (net->verbose)
-               {
+               memcpy(&bin->edbgConfig, &net->data[sizeof(header)],
+                       sizeof(edbg_os_config_data));
+               if (net->verbose) {
                        printf("Received CONFIG command\n");
-
-                       if (bin->edbgConfig.flags & EDBG_FL_DBGMSG)
-                       {
-                               printf("--> Enabling DBGMSG service, IP: %d.%d.%d.%d, port: %d\n",
-                                       (bin->edbgConfig.dbgMsgIPAddr >> 0) & 0xFF,
-                                       (bin->edbgConfig.dbgMsgIPAddr >> 8) & 0xFF,
-                                       (bin->edbgConfig.dbgMsgIPAddr >> 16) & 0xFF,
-                                       (bin->edbgConfig.dbgMsgIPAddr >> 24) & 0xFF,
-                                       (int)bin->edbgConfig.dbgMsgPort);
+                       if (bin->edbgConfig.flags & EDBG_FL_DBGMSG) {
+                               printf("--> Enabling DBGMSG service, IP: %pI4, port: %d\n",
+                                       &bin->edbgConfig.dbgMsgIPAddr,
+                                       ntohs(bin->edbgConfig.dbgMsgPort));
                        }
 
-                       if (bin->edbgConfig.flags & EDBG_FL_PPSH)
-                       {
-                               printf("--> Enabling PPSH service, IP: %d.%d.%d.%d, port: %d\n",
-                                       (bin->edbgConfig.ppshIPAddr >> 0) & 0xFF,
-                                       (bin->edbgConfig.ppshIPAddr >> 8) & 0xFF,
-                                       (bin->edbgConfig.ppshIPAddr >> 16) & 0xFF,
-                                       (bin->edbgConfig.ppshIPAddr >> 24) & 0xFF,
-                                       (int)bin->edbgConfig.ppshPort);
+                       if (bin->edbgConfig.flags & EDBG_FL_PPSH) {
+                               printf("--> Enabling PPSH service, IP: %pI4, port: %d\n",
+                                       &bin->edbgConfig.ppshIPAddr,
+                                       ntohs(bin->edbgConfig.ppshPort));
                        }
 
-                       if (bin->edbgConfig.flags & EDBG_FL_KDBG)
-                       {
-                               printf("--> Enabling KDBG service, IP: %d.%d.%d.%d, port: %d\n",
-                                       (bin->edbgConfig.kdbgIPAddr >> 0) & 0xFF,
-                                       (bin->edbgConfig.kdbgIPAddr >> 8) & 0xFF,
-                                       (bin->edbgConfig.kdbgIPAddr >> 16) & 0xFF,
-                                       (bin->edbgConfig.kdbgIPAddr >> 24) & 0xFF,
-                                       (int)bin->edbgConfig.kdbgPort);
+                       if (bin->edbgConfig.flags & EDBG_FL_KDBG) {
+                               printf("--> Enabling KDBG service, IP: %pI4, port: %d\n",
+                                       &bin->edbgConfig.kdbgIPAddr,
+                                       ntohs(bin->edbgConfig.kdbgPort));
                        }
 
-                       if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT)
-                       {
+                       if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
                                printf("--> Force clean boot\n");
                        }
                }
-
                break;
 
        default:
                if (net->verbose) {
-                       printf("Received unknown command: %08X\n", header->cmd);
+                       printf("Received unknown command: %08X\n", header.cmd);
                }
-               return;
+               return BOOTME_ERROR;
        }
 
        /* Respond with ack */
-       header->flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK;
+       header.flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK;
+       memcpy(net->data, &header, sizeof(header));
        net->dataLen = EDBG_DATA_OFFSET;
-       ce_send_frame(net);
+
+       int retries = 10;
+       int rc;
+       do {
+               rc = bootme_send_frame(net->data, net->dataLen);
+               if (rc != 0) {
+                       printf("Failed to send ACK: %d\n", rc);
+               }
+       } while (rc && retries-- > 0);
+       return rc ?: ret;
 }
 
-int ce_send_write_ack(ce_net* net)
+static enum bootme_state ce_edbg_handler(const void *buf, size_t len)
 {
-       unsigned short* wdata;
-       unsigned long aligned_address;
+       if (len == 0)
+               return BOOTME_DONE;
 
-       aligned_address=(unsigned long)net->data+ETHER_HDR_SIZE+IP_HDR_SIZE+net->align_offset;
+       g_net.data = (void *)buf;
+       g_net.dataLen = len;
 
-       wdata = (unsigned short*)aligned_address;
-       wdata[ 0 ] = htons(EDBG_CMD_WRITE_ACK);
-       wdata[ 1 ] = htons(net->blockNum);
-
-       net->dataLen = 4;
-
-       return ce_send_frame(net);
+       return ce_process_edbg(&g_net, &g_bin);
 }
 
-
-
-int ce_send_frame(ce_net* net)
+static void ce_init_edbg_link(ce_net *net)
 {
-       /* Send UDP packet */
-       NetTxPacket = (uchar *)net->data + net->align_offset;
-       return NetSendUDPPacket(NetServerEther, net->srvAddrSend.sin_addr, (int)net->srvAddrSend.sin_port, (int)net->locAddr.sin_port, net->dataLen);
+       /* Initialize EDBG link for commands */
+       net->state = BOOTME_INIT;
 }
 
-
-
-
-
-
-
-int ce_send_bootme(ce_net* net)
+static enum bootme_state ce_download_handler(const void *buf, size_t len)
 {
-       eth_dbg_hdr* header;
-       edbg_bootme_data* data;
-
-       char    *e, *s;
-       int                             i;
-       unsigned char   tmp[64];
-       unsigned char   *macp;
-
-       #ifdef DEBUG
-       char    *pkt;
-       #endif
+       g_net.data = (void *)buf;
+       g_net.dataLen = len;
 
+       g_net.state = ce_process_download(&g_net, &g_bin);
+       return g_net.state;
+}
 
+static int ce_send_bootme(ce_net *net)
+{
+       eth_dbg_hdr *header;
+       edbg_bootme_data *data;
+       unsigned char txbuf[PKTSIZE_ALIGN];
+#ifdef DEBUG
+       int     i;
+       unsigned char   *pkt;
+#endif
        /* Fill out BOOTME packet */
+       net->data = txbuf;
+
        memset(net->data, 0, PKTSIZE);
-       header = (eth_dbg_hdr*)(net->data +CE_DOFFSET);
-       data = (edbg_bootme_data*)header->data;
+       header = (eth_dbg_hdr *)net->data;
+       data = (edbg_bootme_data *)header->data;
 
-       header->id=EDBG_ID;
+       header->id = EDBG_ID;
        header->service = EDBG_SVC_ADMIN;
        header->flags = EDBG_FL_FROM_DEV;
-       header->seqNum = net->secNum ++;
+       header->seqNum = net->seqNum++;
        header->cmd = EDBG_CMD_BOOTME;
 
        data->versionMajor = 0;
@@ -932,18 +830,14 @@ int ce_send_bootme(ce_net* net)
        data->downloadPort = 0;
        data->svcPort = 0;
 
-       macp=(unsigned char     *)data->macAddr;
        /* MAC address from environment*/
-       i = getenv_r ("ethaddr", tmp, sizeof (tmp));
-       s = (i > 0) ? tmp : 0;
-       for (i = 0; i < 6; ++i) {
-               macp[i] = s ? simple_strtoul (s, &e, 16) : 0;
-               if (s)
-                       s = (*e) ? e + 1 : e;
+       if (!eth_getenv_enetaddr("ethaddr", data->macAddr)) {
+               printf("'ethaddr' is not set or invalid\n");
+               memset(data->macAddr, 0, sizeof(data->macAddr));
        }
 
-       /* IP address from environment */
-       data->ipAddr = (unsigned int)getenv_IPaddr("ipaddr");
+       /* IP address from active config */
+       NetCopyIP(&data->ipAddr, &NetOurIP);
 
        // Device name string (NULL terminated). Should include
        // platform and number based on Ether address (e.g. Odo42, CEPCLS2346, etc)
@@ -951,355 +845,196 @@ int ce_send_bootme(ce_net* net)
        // We will use lower MAC address segment to create device name
        // eg. MAC '00-0C-C6-69-09-05', device name 'Triton05'
 
-       strcpy(data->platformId, "Triton");
-       sprintf(data->deviceName, "%s%02X", data->platformId, macp[5]);
-
+       strncpy(data->platformId, "Triton", sizeof(data->platformId));
+       snprintf(data->deviceName, sizeof(data->deviceName), "%s%02X",
+               data->platformId, data->macAddr[5]);
 
 #ifdef DEBUG
-
-       printf("header->id: %08X\r\n", header->id);
-       printf("header->service: %08X\r\n", header->service);
-       printf("header->flags: %08X\r\n", header->flags);
-       printf("header->seqNum: %08X\r\n", header->seqNum);
-       printf("header->cmd: %08X\r\n\r\n", header->cmd);
-
-       printf("data->versionMajor: %08X\r\n", data->versionMajor);
-       printf("data->versionMinor: %08X\r\n", data->versionMinor);
-       printf("data->cpuId: %08X\r\n", data->cpuId);
-       printf("data->bootmeVer: %08X\r\n", data->bootmeVer);
-       printf("data->bootFlags: %08X\r\n", data->bootFlags);
-       printf("data->svcPort: %08X\r\n\r\n", data->svcPort);
-
-       printf("data->macAddr: %02X-%02X-%02X-%02X-%02X-%02X\r\n",
-               (data->macAddr[0] >> 0) & 0xFF,
-               (data->macAddr[0] >> 8) & 0xFF,
-               (data->macAddr[1] >> 0) & 0xFF,
-               (data->macAddr[1] >> 8) & 0xFF,
-               (data->macAddr[2] >> 0) & 0xFF,
-               (data->macAddr[2] >> 8) & 0xFF);
-
-       printf("data->ipAddr: %d.%d.%d.%d\r\n",
-               (data->ipAddr >> 0) & 0xFF,
-               (data->ipAddr >> 8) & 0xFF,
-               (data->ipAddr >> 16) & 0xFF,
-               (data->ipAddr >> 24) & 0xFF);
-
-       printf("data->platformId: %s\r\n", data->platformId);
-
-       printf("data->deviceName: %s\r\n", data->deviceName);
-
+       printf("header->id: %08X\n", header->id);
+       printf("header->service: %08X\n", header->service);
+       printf("header->flags: %08X\n", header->flags);
+       printf("header->seqNum: %08X\n", header->seqNum);
+       printf("header->cmd: %08X\n\n", header->cmd);
+
+       printf("data->versionMajor: %08X\n", data->versionMajor);
+       printf("data->versionMinor: %08X\n", data->versionMinor);
+       printf("data->cpuId: %08X\n", data->cpuId);
+       printf("data->bootmeVer: %08X\n", data->bootmeVer);
+       printf("data->bootFlags: %08X\n", data->bootFlags);
+       printf("data->svcPort: %08X\n\n", ntohs(data->svcPort));
+
+       printf("data->macAddr: %pM\n", data->macAddr);
+       printf("data->ipAddr: %pI4\n", &data->ipAddr);
+       printf("data->platformId: %s\n", data->platformId);
+       printf("data->deviceName: %s\n", data->deviceName);
 #endif
-
-
        // Some diag output ...
-
-       if (net->verbose)
-       {
-               printf("Sending BOOTME request [%d] to ", (int)net->secNum);
-               print_IPaddr(net->srvAddrSend.sin_addr);
-               printf("\n");
+       if (net->verbose) {
+               printf("Sending BOOTME request [%d] to %pI4\n", net->seqNum,
+                       &server_ip);
        }
 
-       // Send packet
-
        net->dataLen = BOOTME_PKT_SIZE;
+//     net->status = CE_PR_MORE;
+       net->state = BOOTME_INIT;
+#ifdef DEBUG
+       debug("Start of buffer:      %p\n", net->data);
+       debug("Start of ethernet buffer:   %p\n", net->data);
+       debug("Start of CE header:         %p\n", header);
+       debug("Start of CE data:           %p\n", data);
+
+       pkt = net->data;
+       debug("packet to send (ceconnect): \n");
+       for (i = 0; i < net->dataLen; i++) {
+               debug("0x%02X ", pkt[i]);
+               if (!((i + 1) % 16))
+                       debug("\n");
+       }
+       debug("\n");
+#endif
+       return BootMeRequest(server_ip, net->data, net->dataLen, 1);
+}
 
-
-       #ifdef DEBUG
-       printf("\n\n\nStart of buffer:      0x%08X\n", (unsigned long)net->data);
-       printf("Start of ethernet buffer:   0x%08X\n", (unsigned long)net->data+net->align_offset);
-       printf("Start of CE header:         0x%08X\n", (unsigned long)header);
-       printf("Start of CE data:           0x%08X\n", (unsigned long)data);
-
-       pkt = (uchar *)net->data+net->align_offset;
-       printf("\n\npacket to send (ceconnect): \n");
-       for(i=0; i<(net->dataLen+ETHER_HDR_SIZE+IP_HDR_SIZE); i++) {
-               printf("0x%02X ", pkt[i]);
-               if(!((i+1)%16))
-                       printf("\n");
+static inline int ce_init_download_link(ce_net *net, ce_bin *bin, int verbose)
+{
+       if (!eth_get_dev()) {
+               printf("No network interface available\n");
+               return -ENODEV;
        }
-       printf("\n\n");
-       #endif
+       printf("Using device '%s'\n", eth_get_name());
 
-       memcpy(NetServerEther, NetBcastAddr, 6);
+       /* Initialize EDBG link for download */
+       memset(net, 0, sizeof(*net));
 
-       return ce_send_frame(net);
+       net->verbose = verbose;
+
+       /* buffer will be dynamically assigned in ce_download_handler() */
+       ce_init_bin(bin, NULL);
+       return 0;
 }
 
+#define UINT_MAX ~0UL
 
+static inline int ce_download_file(ce_net *net, ulong timeout)
+{
+       ulong start = get_timer_masked();
 
-void ce_dump_block(unsigned char *ptr, int length) {
+       while (net->state == BOOTME_INIT) {
+               int ret;
 
-       int i;
-       int j;
-
-       for(i=0; i<length; i++) {
-               if(!(i%16)) {
-                       printf("\n0x%08X: ", (unsigned long)ptr + i);
+               if (timeout && get_timer(start) > timeout) {
+                       printf("CELOAD - Canceled, timeout\n");
+                       return 1;
                }
 
-               printf("0x%02X ", ptr[i]);
+               if (ctrlc()) {
+                       printf("CELOAD - canceled by user\n");
+                       return 1;
+               }
 
-               if(!((i+1)%16)){
-                       printf("      ");
-                       for(j=i-15; j<i; j++){
-                               if((ptr[j]>0x1f) && (ptr[j]<0x7f)) {
-                                       printf("%c", ptr[j]);
-                               } else {
-                                       printf(".");
-                               }
+               if (ce_send_bootme(&g_net)) {
+                       printf("CELOAD - error while sending BOOTME request\n");
+                       return 1;
+               }
+               if (net->verbose) {
+                       if (timeout) {
+                               printf("Waiting for connection, timeout %lu sec\n",
+                                       DIV_ROUND_UP(timeout - get_timer(start),
+                                               CONFIG_SYS_HZ));
+                       } else {
+                               printf("Waiting for connection, enter ^C to abort\n");
                        }
                }
 
+               ret = BootMeDownload(ce_download_handler);
+               if (ret == BOOTME_ERROR) {
+                       printf("CELOAD - aborted\n");
+                       return 1;
+               }
        }
-
-       printf("\n\n");
+       return 0;
 }
 
-
-
-
-
-
-
-
-
-
-void ce_init_download_link(ce_net* net, ce_bin* bin, struct sockaddr_in* host_addr, int verbose)
+static void ce_disconnect(void)
 {
-       unsigned long aligned_address;
-       /* Initialize EDBG link for download */
-
-
-       memset(net, 0, sizeof(ce_net));
-
-       /* our buffer contains space for ethernet- ip- and udp- headers */
-       /* calucalate an offset that our ce field is aligned to 4 bytes */
-       aligned_address=(unsigned long)net->data;                       /* this is the start of our physical buffer */
-       aligned_address += (ETHER_HDR_SIZE+IP_HDR_SIZE);        /* we need 42 bytes room for headers (14 Ethernet , 20 IPv4, 8 UDP) */
-       net->align_offset =     4-(aligned_address%4);                  /* want CE header aligned to 4 Byte boundary */
-       if(net->align_offset == 4) {
-               net->align_offset=0;
-       }
-
-       net->locAddr.sin_family = AF_INET;
-    net->locAddr.sin_addr = getenv_IPaddr("ipaddr");
-    net->locAddr.sin_port = EDBG_DOWNLOAD_PORT;
-
-       net->srvAddrSend.sin_family = AF_INET;
-    net->srvAddrSend.sin_port = EDBG_DOWNLOAD_PORT;
-
-       net->srvAddrRecv.sin_family = AF_INET;
-    net->srvAddrRecv.sin_port = 0;
-
-       if (host_addr->sin_addr)
-       {
-               /* Use specified host address ... */
-
-               net->srvAddrSend.sin_addr = host_addr->sin_addr;
-               net->srvAddrRecv.sin_addr = host_addr->sin_addr;
-       }
-       else
-       {
-               /* ... or use default server address */
-
-               net->srvAddrSend.sin_addr = getenv_IPaddr("serverip");
-               net->srvAddrRecv.sin_addr = getenv_IPaddr("serverip");
-       }
-
-       net->verbose =  verbose;
-       /* Initialize .BIN parser */
-       ce_init_bin(bin, net->data + CE_DOFFSET + 4);
-
-
-
+       net_set_udp_handler(NULL);
        eth_halt();
-
-#ifdef CONFIG_NET_MULTI
-       eth_set_current();
-#endif
-       if (eth_init(gd->bd) < 0) {
-               #ifdef ET_DEBUG
-               puts("ceconnect: failed to init ethernet !\n");
-               #endif
-               eth_halt();
-               return;
-       }
-       #ifdef ET_DEBUG
-       puts("ceconnect: init ethernet done!\n");
-       #endif
-
-
-       memcpy (NetOurEther, gd->bd->bi_enetaddr, 6);
-       NetCopyIP(&NetOurIP, &gd->bd->bi_ip_addr);
-       NetOurGatewayIP = getenv_IPaddr ("gatewayip");
-       NetOurSubnetMask= getenv_IPaddr ("netmask");
-       NetServerIP = getenv_IPaddr ("serverip");
-
 }
 
-
-int ce_load(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+static int do_ceconnect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
+       int verbose = 0;
+       ulong timeout = 0;
+       int ret = 1;
        int i;
-       int verbose, use_timeout;
-       int timeout, recv_timeout, ret;
-       struct sockaddr_in host_ip_addr;
-
-       // -v verbose
 
-       verbose = 0;
-       use_timeout = 0;
-       timeout = 0;
+       server_ip = 0;
 
-
-       for(i=0;i<argc;i++){
-               if (strcmp(argv[i+1], "-v") == 0){
+       for (i = 1; i < argc; i++){
+               if (*argv[i] != '-')
+                       break;
+               if (argv[i][1] == 'v') {
                        verbose = 1;
-               }
-       }
-
-
-       for(i=0;i<(argc-1);i++){
-               if (strcmp(argv[i+1], "-t") == 0){
-                       use_timeout = 1;
-                       timeout = simple_strtoul(argv[i+2], NULL, 10);
-               }
-       }
-
-       #ifdef DEBUG
-       printf("verbose=%d, use_timeout=%d, timeout=%d\n", verbose, use_timeout, timeout);
-       #endif
-
-       // Check host IP address (if specified)
-
-       *((unsigned int *)&host_ip_addr) = 0xFFFFFFFF;
-
-
-       // Initialize download link
-
-       ce_init_download_link(&g_net, &g_bin, &host_ip_addr, verbose);
-
-       // Download loop
-
-       while (1)
-       {
-               if (g_net.link)
-               {
-                       recv_timeout = 3;
-               }
-               else
-               {
-                       recv_timeout = 1;
-
-                       if (use_timeout)
-                       {
-                               if (timeout <= 0)
-                               {
-                                       printf("CELOAD - Canceled, timeout\n");
-                                       eth_halt();
-                                       return 1;
+               } else if (argv[i][1] == 't') {
+                       i++;
+                       if (argc > i) {
+                               timeout = simple_strtoul(argv[i],
+                                                       NULL, 0);
+                               if (timeout >= UINT_MAX / CONFIG_SYS_HZ) {
+                                       printf("Timeout value %lu out of range (max.: %lu)\n",
+                                               timeout, UINT_MAX / CONFIG_SYS_HZ - 1);
+                                       return CMD_RET_USAGE;
                                }
+                               timeout *= CONFIG_SYS_HZ;
                        } else {
-                               /* Try to catch ^C */
-                               #ifdef DEBUG
-                               puts("try to catch ^C\n");
-                               #endif
-                               if (ctrlc())
-                               {
-                                       printf("CELOAD - canceled by user\n");
-                                       eth_halt();
-                                       return 1;
-                               }
-                       }
-                       #ifdef DEBUG
-                       puts("sending broadcast frame bootme\n");
-                       #endif
-
-                       if (ce_send_bootme(&g_net))
-                       {
-                               printf("CELOAD - error while sending BOOTME request\n");
-                               eth_halt();
-                               return 1;
+                               printf("Option requires an argument - t\n");
+                               return CMD_RET_USAGE;
                        }
-                       printf("net state is: %d\n", NetState);
-                       if (verbose)
-                       {
-                               if (use_timeout)
-                               {
-                                       printf("Waiting for connection, timeout %d sec\n", timeout);
-                               }
-                               else
-                               {
-                                       printf("Waiting for connection, enter ^C to abort\n");
-                               }
+               } else if (argv[i][1] == 'h') {
+                       i++;
+                       if (argc > i) {
+                               server_ip = string_to_ip(argv[i]);
+                               printf("Using server %pI4\n", &server_ip);
+                       } else {
+                               printf("Option requires an argument - h\n");
+                               return CMD_RET_USAGE;
                        }
                }
+       }
 
-               // Try to receive frame
-
-               if (ce_recv_frame(&g_net, recv_timeout))
-               {
-                       // Process received data
+       if (ce_init_download_link(&g_net, &g_bin, verbose) != 0)
+               goto err;
 
-                       ret = ce_process_download(&g_net, &g_bin);
+       if (ce_download_file(&g_net, timeout))
+               goto err;
 
-                       if (ret != CE_PR_MORE)
-                       {
-                               break;
-                       }
-               }
-               else if (use_timeout)
-               {
-                       timeout -= recv_timeout;
-               }
-       }
-
-       if (g_bin.binLen)
-       {
+       if (g_bin.binLen) {
                // Try to receive edbg commands from host
-
                ce_init_edbg_link(&g_net);
-
                if (verbose)
-               {
                        printf("Waiting for EDBG commands ...\n");
-               }
 
-               while (ce_recv_frame(&g_net, 3))
-               {
-                       ce_process_edbg(&g_net, &g_bin);
-               }
+               ret = BootMeDebugStart(ce_edbg_handler);
+               if (ret != BOOTME_DONE)
+                       goto err;
 
                // Prepare WinCE image for execution
-
                ce_prepare_run_bin(&g_bin);
 
                // Launch WinCE, if necessary
-
                if (g_net.gotJumpingRequest)
-               {
-                       ce_run_bin(&g_bin);
-               }
+                       ce_run_bin(g_bin.eEntryPoint);
        }
-       eth_halt();
-       return 0;
+       ret = 0;
+err:
+       ce_disconnect();
+       return ret == 0 ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
 }
-
-
-
-
-
-
-
 U_BOOT_CMD(
-       ceconnect,      2,      1,      ce_load,
-       "ceconnect    - Set up a connection to the CE host PC over TCP/IP and download the run-time image\n",
-       "ceconnect [-v] [-t <timeout>]\n"
-       "  -v verbose operation\n"
-       "  -t <timeout> - max wait time (#sec) for the connection\n"
+       ceconnect, 6, 1, do_ceconnect,
+       "Set up a connection to the CE host PC over TCP/IP and download the run-time image",
+       "[-v] [-t <timeout>] [-h host]\n"
+       "  -v            - verbose operation\n"
+       "  -t <timeout>  - max wait time (#sec) for the connection\n"
+       "  -h <host>     - send BOOTME requests to <host> (default: broadcast address 255.255.255.255)"
 );
-
-#endif
-
-/* CFG_CMD_WINCE */