]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_bootce.c
TX6 Release 2013-04-22
[karo-tx-uboot.git] / common / cmd_bootce.c
1 /*
2  * Copyright (C) 2012 Lothar Waßmann <LW@KARO-electronics.de>
3  * based on: code from RedBoot (C) Uwe Steinkohl <US@KARO-electronics.de>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 //#define DEBUG
24 //#define TEST_LAUNCH
25 //#define DDEBUG
26 #ifdef DDEBUG
27 #define _debug printf
28 #else
29 #define _debug debug
30 #endif
31
32 #include <common.h>
33 #include <command.h>
34 #include <net.h>
35 #include <wince.h>
36 #include <asm/errno.h>
37
38 DECLARE_GLOBAL_DATA_PTR;
39
40 #define WINCE_VRAM_BASE         0x80000000
41 #define CE_FIX_ADDRESS(a)       ((void *)((a) - WINCE_VRAM_BASE + CONFIG_SYS_SDRAM_BASE))
42
43 #ifndef INT_MAX
44 #define INT_MAX                 ((int)(~0 >> 1))
45 #endif
46
47 /* Bin image parse states */
48 #define CE_PS_RTI_ADDR          0
49 #define CE_PS_RTI_LEN           1
50 #define CE_PS_E_ADDR            2
51 #define CE_PS_E_LEN             3
52 #define CE_PS_E_CHKSUM          4
53 #define CE_PS_E_DATA            5
54
55 #define CE_MIN(a, b)            (((a) < (b)) ? (a) : (b))
56 #define CE_MAX(a, b)            (((a) > (b)) ? (a) : (b))
57
58 #define _STRMAC(s)              #s
59 #define STRMAC(s)               _STRMAC(s)
60
61 static ce_bin __attribute__ ((aligned (32))) g_bin;
62 static ce_net __attribute__ ((aligned (32))) g_net;
63 static IPaddr_t server_ip;
64
65 static void ce_init_bin(ce_bin *bin, unsigned char *dataBuffer)
66 {
67         memset(bin, 0, sizeof(*bin));
68
69 debug("%s@%d: \n", __func__, __LINE__);
70         bin->data = dataBuffer;
71         bin->parseState = CE_PS_RTI_ADDR;
72         bin->parsePtr = (unsigned char *)bin;
73 debug("%s@%d: \n", __func__, __LINE__);
74 }
75
76 static int ce_is_bin_image(void *image, int imglen)
77 {
78         if (imglen < CE_BIN_SIGN_LEN) {
79                 return 0;
80         }
81
82         return memcmp(image, CE_BIN_SIGN, CE_BIN_SIGN_LEN) == 0;
83 }
84
85 static const struct ce_magic {
86         char magic[8];
87         size_t size;
88         ce_std_driver_globals drv_glb;
89 } ce_magic_template = {
90         .magic = "KARO_CE6",
91         .size = sizeof(ce_std_driver_globals),
92         .drv_glb = {
93                 .header = {
94                         .signature = STD_DRV_GLB_SIGNATURE,
95                         .oalVersion = 1,
96                         .bspVersion = 2,
97                 },
98         },
99 };
100
101 #ifdef DEBUG
102 static void __attribute__((unused)) ce_dump_block(void *ptr, int length)
103 {
104         char *p = ptr;
105         int i;
106         int j;
107
108         for (i = 0; i < length; i++) {
109                 if (!(i % 16)) {
110                         printf("\n%p: ", ptr + i);
111                 }
112
113                 printf("%02x ", p[i]);
114                 if (!((i + 1) % 16)){
115                         printf("      ");
116                         for (j = i - 15; j <= i; j++){
117                                 if((p[j] > 0x1f) && (p[j] < 0x7f)) {
118                                         printf("%c", p[j]);
119                                 } else {
120                                         printf(".");
121                                 }
122                         }
123                 }
124         }
125         printf("\n");
126 }
127 #else
128 static inline void ce_dump_block(void *ptr, int length)
129 {
130 }
131 #endif
132
133 static void ce_setup_std_drv_globals(ce_std_driver_globals *std_drv_glb)
134 {
135         char *mtdparts = getenv("mtdparts");
136         size_t max_len = ALIGN((unsigned long)std_drv_glb, SZ_4K) -
137                 (unsigned long)&std_drv_glb->mtdparts;
138
139         if (eth_get_dev()) {
140                 memcpy(&std_drv_glb->kitl.mac, eth_get_dev()->enetaddr,
141                         sizeof(std_drv_glb->kitl.mac));
142         }
143         snprintf(std_drv_glb->deviceId, sizeof(std_drv_glb->deviceId),
144                 "Triton%02X", eth_get_dev()->enetaddr[5]);
145
146         NetCopyIP(&std_drv_glb->kitl.ipAddress, &NetOurIP);
147         std_drv_glb->kitl.ipMask = getenv_IPaddr("netmask");
148         std_drv_glb->kitl.ipRoute = getenv_IPaddr("gatewayip");
149
150         if (mtdparts) {
151                 strncpy(std_drv_glb->mtdparts, mtdparts, max_len);
152                 std_drv_glb->mtdparts[max_len - 1] = '\0';
153         } else {
154                 printf("Failed to get mtdparts environment variable\n");
155         }
156 }
157
158 static void ce_prepare_run_bin(ce_bin *bin)
159 {
160         ce_driver_globals *drv_glb;
161         struct ce_magic *ce_magic = (void *)CONFIG_SYS_SDRAM_BASE + 0x160;
162         ce_std_driver_globals *std_drv_glb = &ce_magic->drv_glb;
163
164         /* Clear os RAM area (if needed) */
165         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
166                 debug("cleaning memory from %p to %p\n",
167                         bin->eRamStart, bin->eRamStart + bin->eRamLen);
168
169                 printf("Preparing clean boot ... ");
170                 memset(bin->eRamStart, 0, bin->eRamLen);
171                 printf("ok\n");
172         }
173
174         /* Prepare driver globals (if needed) */
175         if (bin->eDrvGlb) {
176                 debug("Copying CE MAGIC from %p to %p..%p\n",
177                         &ce_magic_template, ce_magic,
178                         (void *)ce_magic + sizeof(*ce_magic) - 1);
179                 memcpy(ce_magic, &ce_magic_template, sizeof(*ce_magic));
180
181                 ce_setup_std_drv_globals(std_drv_glb);
182                 ce_magic->size = sizeof(*std_drv_glb) +
183                         strlen(std_drv_glb->mtdparts) + 1;
184                 ce_dump_block(ce_magic, offsetof(struct ce_magic, drv_glb) +
185                         ce_magic->size);
186
187                 drv_glb = bin->eDrvGlb;
188                 memset(drv_glb, 0, sizeof(*drv_glb));
189
190                 drv_glb->signature = DRV_GLB_SIGNATURE;
191
192                 /* Local ethernet MAC address */
193                 memcpy(drv_glb->macAddr, std_drv_glb->kitl.mac,
194                         sizeof(drv_glb->macAddr));
195                 debug("got MAC address %02x:%02x:%02x:%02x:%02x:%02x from environment\n",
196                         drv_glb->macAddr[0], drv_glb->macAddr[1],
197                         drv_glb->macAddr[2], drv_glb->macAddr[3],
198                         drv_glb->macAddr[4], drv_glb->macAddr[5]);
199
200                 /* Local IP address */
201                 drv_glb->ipAddr = getenv_IPaddr("ipaddr");
202
203                 /* Subnet mask */
204                 drv_glb->ipMask = getenv_IPaddr("netmask");
205
206                 /* Gateway config */
207                 drv_glb->ipGate = getenv_IPaddr("gatewayip");
208 #ifdef DEBUG
209                 debug("got IP address %pI4 from environment\n", &drv_glb->ipAddr);
210                 debug("got IP mask %pI4 from environment\n", &drv_glb->ipMask);
211                 debug("got gateway address %pI4 from environment\n", &drv_glb->ipGate);
212 #endif
213                 /* EDBG services config */
214                 memcpy(&drv_glb->edbgConfig, &bin->edbgConfig,
215                         sizeof(bin->edbgConfig));
216         }
217
218         /*
219          * Make sure, all the above makes it into SDRAM because
220          * WinCE switches the cache & MMU off, obviously without
221          * flushing it first!
222          */
223         flush_dcache_all();
224 }
225
226 static int ce_lookup_ep_bin(ce_bin *bin)
227 {
228         ce_rom_hdr *header;
229         ce_toc_entry *tentry;
230         e32_rom *e32;
231         unsigned int i;
232         uint32_t *sig = (uint32_t *)(bin->rtiPhysAddr + ROM_SIGNATURE_OFFSET);
233
234         debug("Looking for TOC signature at %p\n", sig);
235
236         /* Check image Table Of Contents (TOC) signature */
237         if (*sig != ROM_SIGNATURE) {
238                 printf("Error: Did not find image TOC signature!\n");
239                 printf("Expected %08x at address %p; found %08x instead\n",
240                         ROM_SIGNATURE, sig, *sig);
241                 return 0;
242         }
243
244         /* Lookup entry point */
245         header = CE_FIX_ADDRESS(*(unsigned int *)(bin->rtiPhysAddr +
246                                                 ROM_SIGNATURE_OFFSET +
247                                                 sizeof(unsigned int)));
248         tentry = (ce_toc_entry *)(header + 1);
249
250         for (i = 0; i < header->nummods; i++) {
251                 // Look for 'nk.exe' module
252                 if (strcmp(CE_FIX_ADDRESS(tentry[i].fileName), "nk.exe") == 0) {
253                         // Save entry point and RAM addresses
254
255                         e32 = CE_FIX_ADDRESS(tentry[i].e32Offset);
256
257                         bin->eEntryPoint = CE_FIX_ADDRESS(tentry[i].loadOffset) +
258                                 e32->e32_entryrva;
259                         bin->eRamStart = CE_FIX_ADDRESS(header->ramStart);
260                         bin->eRamLen = header->ramEnd - header->ramStart;
261                         // Save driver_globals address
262                         // Must follow RAM section in CE config.bib file
263                         //
264                         // eg.
265                         //
266                         // RAM          80900000        03200000        RAM
267                         // DRV_GLB      83B00000        00001000        RESERVED
268                         //
269                         bin->eDrvGlb = CE_FIX_ADDRESS(header->ramEnd);
270                         return 1;
271                 }
272         }
273
274         // Error: Did not find 'nk.exe' module
275         return 0;
276 }
277
278 static int ce_parse_bin(ce_bin *bin)
279 {
280         unsigned char *pbData = g_net.data + 4;//bin->data;
281         int len = bin->dataLen;
282         int copyLen;
283
284         debug("starting ce image parsing:\n\tbin->binLen: 0x%08X\n", bin->binLen);
285         debug("\tlen=%d\n", len);
286         debug("\tparse_state=%d\n", bin->parseState);
287
288         if (len) {
289                 ce_dump_block(pbData, len);
290 #if 0
291 if (bin->binLen > 1024)
292         return CE_PR_EOF;
293 #endif
294                 if (bin->binLen == 0) {
295                         // Check for the .BIN signature first
296                         if (!ce_is_bin_image(pbData, len)) {
297                                 printf("Error: Invalid or corrupted .BIN image!\n");
298                                 return CE_PR_ERROR;
299                         }
300
301                         printf("Loading Windows CE .BIN image ...\n");
302                         // Skip signature
303                         len -= CE_BIN_SIGN_LEN;
304                         pbData += CE_BIN_SIGN_LEN;
305                 }
306
307                 while (len) {
308                         switch (bin->parseState) {
309                         case CE_PS_RTI_ADDR:
310                         case CE_PS_RTI_LEN:
311                         case CE_PS_E_ADDR:
312                         case CE_PS_E_LEN:
313                         case CE_PS_E_CHKSUM:
314                                 copyLen = CE_MIN(sizeof(unsigned int) - bin->parseLen, len);
315                                 memcpy(&bin->parsePtr[bin->parseLen], pbData, copyLen);
316
317                                 bin->parseLen += copyLen;
318                                 len -= copyLen;
319                                 pbData += copyLen;
320
321                                 if (bin->parseLen == sizeof(unsigned int)) {
322                                         if (bin->parseState == CE_PS_RTI_ADDR)
323                                                 bin->rtiPhysAddr = CE_FIX_ADDRESS(bin->rtiPhysAddr);
324                                         else if (bin->parseState == CE_PS_E_ADDR &&
325                                                 bin->ePhysAddr)
326                                                 bin->ePhysAddr = CE_FIX_ADDRESS(bin->ePhysAddr);
327
328                                         bin->parseState++;
329                                         bin->parseLen = 0;
330                                         bin->parsePtr += sizeof(unsigned int);
331
332                                         if (bin->parseState == CE_PS_E_DATA) {
333                                                 if (bin->ePhysAddr) {
334                                                         bin->parsePtr = bin->ePhysAddr;
335                                                         bin->parseChkSum = 0;
336                                                 } else {
337                                                         /* EOF */
338                                                         len = 0;
339                                                         bin->endOfBin = 1;
340                                                 }
341                                         }
342                                 }
343                                 break;
344
345                         case CE_PS_E_DATA:
346                                 debug("ePhysAddr=%p physlen=%08x parselen=%08x\n",
347                                         bin->ePhysAddr, bin->ePhysLen, bin->parseLen);
348                                 if (bin->ePhysAddr) {
349                                         copyLen = CE_MIN(bin->ePhysLen - bin->parseLen, len);
350                                         bin->parseLen += copyLen;
351                                         len -= copyLen;
352
353                                         while (copyLen--) {
354                                                 bin->parseChkSum += *pbData;
355                                                 *bin->parsePtr++ = *pbData++;
356                                         }
357
358                                         if (bin->parseLen == bin->ePhysLen) {
359                                                 printf("Section [%02d]: address %p, size 0x%08X, checksum %s\n",
360                                                         bin->section,
361                                                         bin->ePhysAddr,
362                                                         bin->ePhysLen,
363                                                         (bin->eChkSum == bin->parseChkSum) ? "ok" : "fail");
364
365                                                 if (bin->eChkSum != bin->parseChkSum) {
366                                                         printf("Error: Checksum error, corrupted .BIN file!\n");
367                                                         printf("checksum calculated: 0x%08x from file: 0x%08x\n",
368                                                                 bin->parseChkSum, bin->eChkSum);
369                                                         bin->binLen = 0;
370                                                         return CE_PR_ERROR;
371                                                 }
372
373                                                 bin->section++;
374                                                 bin->parseState = CE_PS_E_ADDR;
375                                                 bin->parseLen = 0;
376                                                 bin->parsePtr = (unsigned char *)&bin->ePhysAddr;
377                                         }
378                                 } else {
379                                         bin->parseLen = 0;
380                                         bin->endOfBin = 1;
381                                         len = 0;
382                                 }
383                                 break;
384                         }
385                 }
386         }
387
388         if (bin->endOfBin) {
389                 if (!ce_lookup_ep_bin(bin)) {
390                         printf("Error: entry point not found!\n");
391                         bin->binLen = 0;
392                         return CE_PR_ERROR;
393                 }
394
395                 printf("Entry point: %p, address range: %p-%p\n",
396                         bin->eEntryPoint,
397                         bin->rtiPhysAddr,
398                         bin->rtiPhysAddr + bin->rtiPhysLen);
399
400                 return CE_PR_EOF;
401         }
402
403         /* Need more data */
404         bin->binLen += bin->dataLen;
405         return CE_PR_MORE;
406 }
407
408 static int ce_bin_load(void *image, int imglen)
409 {
410         ce_init_bin(&g_bin, image);
411         g_bin.dataLen = imglen;
412         if (ce_parse_bin(&g_bin) == CE_PR_EOF) {
413                 ce_prepare_run_bin(&g_bin);
414                 return 1;
415         }
416
417         return 0;
418 }
419
420 static void ce_run_bin(void (*entry)(void))
421 {
422         printf("Launching Windows CE ...\n");
423 #ifdef TEST_LAUNCH
424 return;
425 #endif
426         entry();
427 }
428
429 static int do_bootce(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
430 {
431         void *addr;
432         size_t image_size;
433         char *s;
434
435         if (argc > 1) {
436                 addr = (void *)simple_strtoul(argv[1], NULL, 16);
437                 image_size = INT_MAX;           /* actually we do not know the image size */
438         } else if (getenv("fileaddr") != NULL) {
439                 addr = (void *)getenv_ulong("fileaddr", 16, 0);
440                 image_size = getenv_ulong("filesize", 16, INT_MAX);
441         } else {
442                 printf ("Usage:\n%s\n", cmdtp->usage);
443                 return 1;
444         }
445
446         printf ("## Booting Windows CE Image from address %p ...\n", addr);
447
448         /* check if there is a valid windows CE image */
449         if (ce_is_bin_image(addr, image_size)) {
450                 if (!ce_bin_load(addr, image_size)) {
451                         /* Ops! Corrupted .BIN image! */
452                         /* Handle error here ...      */
453                         printf("corrupted .BIN image !!!\n");
454                         return 1;
455                 }
456                 if ((s = getenv("autostart")) != NULL) {
457                         if (*s != 'y') {
458                                 /*
459                                  * just use bootce to load the image to SDRAM;
460                                  * Do not start it automatically.
461                                  */
462                                 setenv_addr("fileaddr",
463                                         g_bin.eEntryPoint);
464                                 return 0;
465                         }
466                 }
467                 ce_run_bin(g_bin.eEntryPoint);          /* start the image */
468         } else {
469                 printf("Image does not seem to be a valid Windows CE image!\n");
470                 return 1;
471         }
472         return 1;       /* never reached - just to keep compiler happy */
473 }
474
475 U_BOOT_CMD(
476         bootce, 2,      0,      do_bootce,
477         "bootce\t- Boot a Windows CE image from memory \n",
478         "[args..]\n"
479         "\taddr\t\t-boot image from address addr\n"
480 );
481
482 static int ce_send_write_ack(ce_net *net)
483 {
484         int ret;
485         unsigned short wdata[2];
486         int retries = 0;
487
488         wdata[0] = htons(EDBG_CMD_WRITE_ACK);
489         wdata[1] = htons(net->blockNum);
490         net->dataLen = sizeof(wdata);
491         memcpy(net->data, wdata, net->dataLen);
492
493         do {
494                 ret = bootme_send_frame(net->data, net->dataLen);
495                 if (ret) {
496                         printf("Failed to send write ack %d; retries=%d\n",
497                                 ret, retries);
498                 }
499 debug("*");
500         } while (ret != 0 && retries-- > 0);
501         return ret;
502 }
503
504 static enum bootme_state ce_process_download(ce_net *net, ce_bin *bin)
505 {
506         int ret = net->state;
507
508         if (net->dataLen >= 4) {
509                 unsigned short command;
510                 unsigned short blknum;
511
512                 memcpy(&command, net->data, sizeof(command));
513                 command = ntohs(command);
514                 debug("command found: 0x%04X\n", command);
515
516                 if (net->state == BOOTME_DOWNLOAD) {
517                         unsigned short nxt = net->blockNum + 1;
518
519                         memcpy(&blknum, &net->data[2], sizeof(blknum));
520                         blknum = ntohs(blknum);
521                         if (blknum == nxt) {
522                                 net->blockNum = blknum;
523 debug("#");
524                         } else {
525                                 int rc = ce_send_write_ack(net);
526
527                                 printf("Dropping out of sequence packet with ID %d (expected %d)\n",
528                                         blknum, nxt);
529                                 if (rc != 0)
530                                         return rc;
531
532                                 return ret;
533                         }
534                 }
535
536                 switch (command) {
537                 case EDBG_CMD_WRITE_REQ:
538                         if (net->state == BOOTME_INIT) {
539                                 // Check file name for WRITE request
540                                 // CE EShell uses "boot.bin" file name
541 #if 0
542                                 printf(">>>>>>>> First Frame, IP: %s, port: %d\n",
543                                         inet_ntoa((in_addr_t *)&net->srvAddrRecv),
544                                         ntohs(net->srvAddrRecv.sin_port));
545 #endif
546                                 if (strncmp((char *)&net->data[2],
547                                                 "boot.bin", 8) == 0) {
548                                         // Some diag output
549                                         if (net->verbose) {
550                                                 printf("Locked Down download link, IP: %pI4\n",
551                                                         &NetServerIP);
552                                                 printf("Sending BOOTME request [%d] to %pI4\n",
553                                                         net->seqNum, &NetServerIP);
554                                         }
555
556                                         // Lock down EShell download link
557 //                                      net->link = 1;
558                                         ret = BOOTME_DOWNLOAD;
559                                 } else {
560                                         // Unknown link
561                                         printf("Unknown link\n");
562                                 }
563
564                                 if (ret == BOOTME_DOWNLOAD) {
565                                         int rc = ce_send_write_ack(net);
566                                         if (rc != 0)
567                                                 return rc;
568                                 }
569                         }
570                         break;
571
572                 case EDBG_CMD_WRITE:
573                         /* Fixup data len */
574                         bin->dataLen = net->dataLen - 4;
575                         ret = ce_parse_bin(bin);
576                         if (ret != CE_PR_ERROR) {
577                                 int rc = ce_send_write_ack(net);
578                                 if (rc)
579                                         return rc;
580                                 if (ret == CE_PR_EOF)
581                                         ret = BOOTME_DONE;
582                         } else {
583                                 ret = BOOTME_ERROR;
584                         }
585                         break;
586
587                 case EDBG_CMD_READ_REQ:
588                         printf("Ignoring EDBG_CMD_READ_REQ\n");
589                         /* Read requests are not supported
590                          * Do nothing ...
591                          */
592                         break;
593
594                 case EDBG_CMD_ERROR:
595                         printf("Error: unknown error on the host side\n");
596
597                         bin->binLen = 0;
598                         ret = BOOTME_ERROR;
599                         break;
600
601                 default:
602                         printf("unknown command 0x%04X\n", command);
603                         net->state = BOOTME_ERROR;
604                 }
605         }
606         return ret;
607 }
608
609 static enum bootme_state ce_process_edbg(ce_net *net, ce_bin *bin)
610 {
611         enum bootme_state ret = net->state;
612         eth_dbg_hdr header;
613
614 debug("%s: received packet of %u byte @ %p\n", __func__, net->dataLen, net->data);
615         if (net->dataLen < sizeof(header)) {
616                 /* Bad packet */
617                 printf("Invalid packet size %u\n", net->dataLen);
618                 net->dataLen = 0;
619                 return ret;
620         }
621 debug("%s@%d: Copying header from %p..%p to %p\n", __func__, __LINE__,
622         net->data, net->data + sizeof(header) - 1, &header);
623         memcpy(&header, net->data, sizeof(header));
624         if (header.id != EDBG_ID) {
625                 /* Bad packet */
626                 printf("Bad EDBG ID %08x\n", header.id);
627                 net->dataLen = 0;
628                 return ret;
629         }
630
631 debug("%s@%d\n", __func__, __LINE__);
632         if (header.service != EDBG_SVC_ADMIN) {
633                 /* Unknown service */
634                 printf("Bad EDBG service %02x\n", header.service);
635                 net->dataLen = 0;
636                 return ret;
637         }
638
639 debug("%s@%d\n", __func__, __LINE__);
640         if (net->state == BOOTME_INIT) {
641                 /* Some diag output */
642                 if (net->verbose) {
643                         printf("Locked Down EDBG service link, IP: %pI4\n",
644                                 &NetServerIP);
645                 }
646
647                 /* Lock down EDBG link */
648 //              net->link = 1;
649                 net->state = BOOTME_DEBUG;
650         }
651
652 debug("%s@%d\n", __func__, __LINE__);
653         switch (header.cmd) {
654         case EDBG_CMD_JUMPIMG:
655 debug("%s@%d\n", __func__, __LINE__);
656                 net->gotJumpingRequest = 1;
657
658                 if (net->verbose) {
659                         printf("Received JUMPING command\n");
660                 }
661                 /* Just pass through and copy CONFIG structure */
662         case EDBG_CMD_OS_CONFIG:
663 debug("%s@%d\n", __func__, __LINE__);
664                 /* Copy config structure */
665                 memcpy(&bin->edbgConfig, header.data,
666                         sizeof(edbg_os_config_data));
667                 if (net->verbose) {
668                         printf("Received CONFIG command\n");
669                         if (bin->edbgConfig.flags & EDBG_FL_DBGMSG) {
670                                 printf("--> Enabling DBGMSG service, IP: %d.%d.%d.%d, port: %d\n",
671                                         (bin->edbgConfig.dbgMsgIPAddr >> 0) & 0xFF,
672                                         (bin->edbgConfig.dbgMsgIPAddr >> 8) & 0xFF,
673                                         (bin->edbgConfig.dbgMsgIPAddr >> 16) & 0xFF,
674                                         (bin->edbgConfig.dbgMsgIPAddr >> 24) & 0xFF,
675                                         ntohs(bin->edbgConfig.dbgMsgPort));
676                         }
677
678                         if (bin->edbgConfig.flags & EDBG_FL_PPSH) {
679                                 printf("--> Enabling PPSH service, IP: %d.%d.%d.%d, port: %d\n",
680                                         (bin->edbgConfig.ppshIPAddr >> 0) & 0xFF,
681                                         (bin->edbgConfig.ppshIPAddr >> 8) & 0xFF,
682                                         (bin->edbgConfig.ppshIPAddr >> 16) & 0xFF,
683                                         (bin->edbgConfig.ppshIPAddr >> 24) & 0xFF,
684                                         ntohs(bin->edbgConfig.ppshPort));
685                         }
686
687                         if (bin->edbgConfig.flags & EDBG_FL_KDBG) {
688                                 printf("--> Enabling KDBG service, IP: %d.%d.%d.%d, port: %d\n",
689                                         (bin->edbgConfig.kdbgIPAddr >> 0) & 0xFF,
690                                         (bin->edbgConfig.kdbgIPAddr >> 8) & 0xFF,
691                                         (bin->edbgConfig.kdbgIPAddr >> 16) & 0xFF,
692                                         (bin->edbgConfig.kdbgIPAddr >> 24) & 0xFF,
693                                         ntohs(bin->edbgConfig.kdbgPort));
694                         }
695
696                         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
697                                 printf("--> Force clean boot\n");
698                         }
699                 }
700                 ret = BOOTME_DEBUG;
701                 break;
702
703         default:
704                 if (net->verbose) {
705                         printf("Received unknown command: %08X\n", header.cmd);
706                 }
707                 return BOOTME_ERROR;
708         }
709
710         /* Respond with ack */
711         header.flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK;
712         net->dataLen = EDBG_DATA_OFFSET;
713 debug("%s@%d: sending packet %p len %u\n", __func__, __LINE__,
714         net->data, net->dataLen);
715         bootme_send_frame(net->data, net->dataLen);
716         return ret;
717 }
718
719 static enum bootme_state ce_edbg_handler(const void *buf, size_t len)
720 {
721         enum bootme_state ret;
722
723         if (len == 0) {
724                 _debug("%s: EOF\n", __func__);
725                 return BOOTME_DONE;
726         }
727 #if 0
728         if (len > sizeof(g_net.data)) {
729                 debug("Dropping oversized packet of %u bytes (max. size %u)\n",
730                         len, sizeof(g_net.data));
731                 return g_net.state;
732         }
733         debug("Copying network packet of %u bytes from %p to %p\n",
734                 len, buf, g_net.data);
735         memcpy(g_net.data, buf, len);
736         g_net.dataLen = len;
737 #else
738         g_net.data = (void *)buf;
739         g_net.dataLen = len;
740 #endif
741         ret = ce_process_edbg(&g_net, &g_bin);
742         return ret;
743 }
744
745 static void ce_init_edbg_link(ce_net *net)
746 {
747         /* Initialize EDBG link for commands */
748         net->state = BOOTME_INIT;
749 }
750
751 static enum bootme_state ce_download_handler(const void *buf, size_t len)
752 {
753 #if 0
754         if (len > sizeof(g_net.data)) {
755                 debug("Dropping oversized packet of %u bytes (max. size %u)\n",
756                         len, sizeof(g_net.data));
757                 return g_net.state;
758         }
759         debug("Copying network packet of %u bytes from %p to %p\n",
760                 len, buf, g_net.data);
761         memcpy(g_net.data, buf, len);
762         g_net.dataLen = len;
763 #else
764         g_net.data = (void *)buf;
765         g_net.dataLen = len;
766 #endif
767         g_net.state = ce_process_download(&g_net, &g_bin);
768         return g_net.state;
769 }
770
771 static int ce_send_bootme(ce_net *net)
772 {
773         eth_dbg_hdr *header;
774         edbg_bootme_data *data;
775         unsigned char txbuf[PKTSIZE_ALIGN];
776 #ifdef DEBUG_
777         int     i;
778         unsigned char   *pkt;
779 #endif
780         /* Fill out BOOTME packet */
781 net->data = txbuf;
782 assert(net->data != NULL);
783         memset(net->data, 0, PKTSIZE);
784         header = (eth_dbg_hdr *)net->data;
785         data = (edbg_bootme_data *)header->data;
786
787         header->id = EDBG_ID;
788         header->service = EDBG_SVC_ADMIN;
789         header->flags = EDBG_FL_FROM_DEV;
790         header->seqNum = net->seqNum++;
791         header->cmd = EDBG_CMD_BOOTME;
792
793         data->versionMajor = 0;
794         data->versionMinor = 0;
795         data->cpuId = EDBG_CPU_TYPE_ARM;
796         data->bootmeVer = EDBG_CURRENT_BOOTME_VERSION;
797         data->bootFlags = 0;
798         data->downloadPort = 0;
799         data->svcPort = 0;
800
801         /* MAC address from environment*/
802         if (!eth_getenv_enetaddr("ethaddr", data->macAddr)) {
803                 printf("'ethaddr' is not set or invalid\n");
804                 memset(data->macAddr, 0, sizeof(data->macAddr));
805         }
806
807         /* IP address from active config */
808         NetCopyIP(&data->ipAddr, &NetOurIP);
809
810         // Device name string (NULL terminated). Should include
811         // platform and number based on Ether address (e.g. Odo42, CEPCLS2346, etc)
812
813         // We will use lower MAC address segment to create device name
814         // eg. MAC '00-0C-C6-69-09-05', device name 'Triton05'
815
816         strncpy(data->platformId, "Triton", sizeof(data->platformId));
817         snprintf(data->deviceName, sizeof(data->deviceName), "%s%02X",
818                 data->platformId, data->macAddr[5]);
819
820 #ifdef DEBUG_
821         printf("header->id: %08X\r\n", header->id);
822         printf("header->service: %08X\r\n", header->service);
823         printf("header->flags: %08X\r\n", header->flags);
824         printf("header->seqNum: %08X\r\n", header->seqNum);
825         printf("header->cmd: %08X\r\n\r\n", header->cmd);
826
827         printf("data->versionMajor: %08X\r\n", data->versionMajor);
828         printf("data->versionMinor: %08X\r\n", data->versionMinor);
829         printf("data->cpuId: %08X\r\n", data->cpuId);
830         printf("data->bootmeVer: %08X\r\n", data->bootmeVer);
831         printf("data->bootFlags: %08X\r\n", data->bootFlags);
832         printf("data->svcPort: %08X\r\n\r\n", ntohs(data->svcPort));
833
834         printf("data->macAddr: %02X-%02X-%02X-%02X-%02X-%02X\r\n",
835                 data->macAddr[0], data->macAddr[1],
836                 data->macAddr[2], data->macAddr[3],
837                 data->macAddr[4], data->macAddr[5]);
838
839         printf("data->ipAddr: %d.%d.%d.%d\r\n",
840                 (data->ipAddr >> 0) & 0xFF,
841                 (data->ipAddr >> 8) & 0xFF,
842                 (data->ipAddr >> 16) & 0xFF,
843                 (data->ipAddr >> 24) & 0xFF);
844
845         printf("data->platformId: %s\r\n", data->platformId);
846
847         printf("data->deviceName: %s\r\n", data->deviceName);
848 #endif
849         // Some diag output ...
850         if (net->verbose) {
851                 printf("Sending BOOTME request [%d] to %pI4\n", net->seqNum,
852                         &server_ip);
853         }
854
855         net->dataLen = BOOTME_PKT_SIZE;
856 //      net->status = CE_PR_MORE;
857         net->state = BOOTME_INIT;
858 #ifdef DEBUG_
859         debug("Start of buffer:      %p\n", net->data);
860         debug("Start of ethernet buffer:   %p\n", net->data);
861         debug("Start of CE header:         %p\n", header);
862         debug("Start of CE data:           %p\n", data);
863
864         pkt = net->data;
865         debug("packet to send (ceconnect): \n");
866         for (i = 0; i < net->dataLen; i++) {
867                 debug("0x%02X ", pkt[i]);
868                 if (!((i + 1) % 16))
869                         debug("\n");
870         }
871         debug("\n");
872 #endif
873         return BootMeRequest(server_ip, net->data, net->dataLen, 1);
874 }
875
876 static inline int ce_init_download_link(ce_net *net, ce_bin *bin, int verbose)
877 {
878         if (!eth_get_dev()) {
879                 printf("No network interface available\n");
880                 return -ENODEV;
881         }
882         printf("Using device '%s'\n", eth_get_name());
883
884         /* Initialize EDBG link for download */
885         memset(net, 0, sizeof(*net));
886
887         net->verbose = verbose;
888
889         ce_init_bin(bin, NULL);//&net->data[4]);
890         return 0;
891 }
892
893 #define UINT_MAX ~0UL
894
895 static inline int ce_download_file(ce_net *net, ulong timeout)
896 {
897         ulong start = get_timer_masked();
898
899         while (net->state == BOOTME_INIT) {
900                 int ret;
901
902                 if (timeout && get_timer(start) > timeout) {
903                         printf("CELOAD - Canceled, timeout\n");
904                         return 1;
905                 }
906
907                 if (ctrlc()) {
908                         printf("CELOAD - canceled by user\n");
909                         return 1;
910                 }
911
912                 if (ce_send_bootme(&g_net)) {
913                         printf("CELOAD - error while sending BOOTME request\n");
914                         return 1;
915                 }
916                 if (net->verbose) {
917                         if (timeout) {
918                                 printf("Waiting for connection, timeout %lu sec\n",
919                                         DIV_ROUND_UP(timeout - get_timer(start),
920                                                 CONFIG_SYS_HZ));
921                         } else {
922                                 printf("Waiting for connection, enter ^C to abort\n");
923                         }
924                 }
925
926                 ret = BootMeDownload(ce_download_handler);
927                 printf("BootMeDownload() returned %d\n", ret);
928                 if (ret == BOOTME_ERROR) {
929                         printf("CELOAD - aborted\n");
930                         return 1;
931                 }
932         }
933         return 0;
934 }
935
936 static void ce_disconnect(void)
937 {
938         net_set_udp_handler(NULL);
939         eth_halt();
940 }
941
942 static int do_ceconnect(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
943 {
944         int verbose = 0;
945         ulong timeout = 0;
946         int ret = 1;
947         int i;
948
949         server_ip = 0;
950
951         for (i = 1; i < argc; i++){
952                 if (*argv[i] != '-')
953                         break;
954                 if (argv[i][1] == 'v') {
955                         verbose = 1;
956                 } else if (argv[i][1] == 't') {
957                         i++;
958                         if (argc > i) {
959                                 timeout = simple_strtoul(argv[i],
960                                                         NULL, 10);
961                                 if (timeout >= UINT_MAX / CONFIG_SYS_HZ) {
962                                         printf("Timeout value %lu out of range (max.: %lu)\n",
963                                                 timeout, UINT_MAX / CONFIG_SYS_HZ - 1);
964                                         return 1;
965                                 }
966                                 timeout *= CONFIG_SYS_HZ;
967                         } else {
968                                 printf("Option requires an argument - t\n");
969                                 return 1;
970                         }
971                 } else if (argv[i][1] == 'h') {
972                         i++;
973                         if (argc > i) {
974                                 server_ip = string_to_ip(argv[i]);
975                                 printf("Using server %pI4\n", &server_ip);
976                         } else {
977                                 printf("Option requires an argument - t\n");
978                                 return 1;
979                         }
980                 }
981         }
982 #ifndef TEST_LAUNCH
983         if (ce_init_download_link(&g_net, &g_bin, verbose) != 0)
984                 goto err;
985
986         if (ce_download_file(&g_net, timeout))
987                 goto err;
988 #else
989 g_bin.binLen = 1;
990 #endif
991         if (g_bin.binLen) {
992                 // Try to receive edbg commands from host
993 _debug("%s@%d: \n", __func__, __LINE__);
994                 ce_init_edbg_link(&g_net);
995 _debug("%s@%d: \n", __func__, __LINE__);
996                 if (verbose)
997                         printf("Waiting for EDBG commands ...\n");
998
999 _debug("%s@%d: \n", __func__, __LINE__);
1000                 ret = BootMeDebugStart(ce_edbg_handler);
1001 _debug("%s@%d: ret=%d\n", __func__, __LINE__, ret);
1002                 if (ret != BOOTME_DONE)
1003                         goto err;
1004 _debug("%s@%d: \n", __func__, __LINE__);
1005
1006                 // Prepare WinCE image for execution
1007                 ce_prepare_run_bin(&g_bin);
1008 _debug("%s@%d: \n", __func__, __LINE__);
1009
1010                 // Launch WinCE, if necessary
1011                 if (g_net.gotJumpingRequest)
1012                         ce_run_bin(g_bin.eEntryPoint);
1013 _debug("%s@%d: \n", __func__, __LINE__);
1014         }
1015         ret = 0;
1016 err:
1017         ce_disconnect();
1018         return ret;
1019 }
1020
1021 U_BOOT_CMD(
1022         ceconnect,      4,      1,      do_ceconnect,
1023         "ceconnect    - Set up a connection to the CE host PC over TCP/IP and download the run-time image\n",
1024         "ceconnect [-v] [-t <timeout>]\n"
1025         "  -v verbose operation\n"
1026         "  -t <timeout> - max wait time (#sec) for the connection\n"
1027 );