]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - common/cmd_bootce.c
applied patches from Freescale and Ka-Ro
[karo-tx-uboot.git] / common / cmd_bootce.c
1 #include <common.h>
2 #include <command.h>
3 #include <net.h>
4 #include <wince.h>
5
6 DECLARE_GLOBAL_DATA_PTR;        /* defines global data structure pointer */
7
8
9 /*/////////////////////////////////////////////////////////////////////////////////////////////*/
10 /* Local macro */
11
12 /* Memory macro */
13
14 /* #define CE_RAM_BASE                  0x80100000 */
15 /* #define CE_WINCE_VRAM_BASE   0x80000000 */
16 /* #define CE_FIX_ADDRESS(a)            (((a) - CE_WINCE_VRAM_BASE) + CE_RAM_BASE) */
17 #define CE_FIX_ADDRESS(a)               (a)
18
19 /* Bin image parse states */
20
21 #define CE_PS_RTI_ADDR                  0
22 #define CE_PS_RTI_LEN                   1
23 #define CE_PS_E_ADDR                    2
24 #define CE_PS_E_LEN                             3
25 #define CE_PS_E_CHKSUM                  4
26 #define CE_PS_E_DATA                    5
27
28 /* Min/max */
29
30 #define CE_MIN(a, b)                    (((a) < (b)) ? (a) : (b))
31 #define CE_MAX(a, b)                    (((a) > (b)) ? (a) : (b))
32
33 // Macro string
34
35 #define _STRMAC(s)                              #s
36 #define STRMAC(s)                               _STRMAC(s)
37
38
39
40
41
42
43
44 ///////////////////////////////////////////////////////////////////////////////////////////////
45 // Global data
46
47 static ce_bin __attribute__ ((aligned (32))) g_bin;
48 static ce_net __attribute__ ((aligned (32))) g_net;
49
50
51 ///////////////////////////////////////////////////////////////////////////////////////////////
52 // Local proto
53
54
55
56
57 ///////////////////////////////////////////////////////////////////////////////////////////////
58 // Implementation
59
60 int ce_bin_load(void* image, int imglen)
61 {
62         ce_init_bin(&g_bin, image);
63
64         g_bin.dataLen = imglen;
65
66         if (ce_parse_bin(&g_bin) == CE_PR_EOF)
67         {
68                 ce_prepare_run_bin(&g_bin);
69                 return 1;
70         }
71
72         return 0;
73 }
74
75 int ce_is_bin_image(void* image, int imglen)
76 {
77         if (imglen < CE_BIN_SIGN_LEN)
78         {
79                 return 0;
80         }
81
82         return (memcmp(image, CE_BIN_SIGN, CE_BIN_SIGN_LEN) == 0);
83 }
84
85 void ce_bin_init_parser(void)
86 {
87         // No buffer address by now, will be specified
88         // latter by the ce_bin_parse_next routine
89
90         ce_init_bin(&g_bin, NULL);
91 }
92
93 int ce_bin_parse_next(void* parseBuffer, int len)
94 {
95         int rc;
96
97         g_bin.data = (unsigned char*)parseBuffer;
98         g_bin.dataLen = len;
99         rc = ce_parse_bin(&g_bin);
100
101         if (rc == CE_PR_EOF)
102         {
103                 ce_prepare_run_bin(&g_bin);
104         }
105
106         return rc;
107 }
108
109 void ce_init_bin(ce_bin* bin, unsigned char* dataBuffer)
110 {
111         memset(bin, 0, sizeof(ce_bin));
112
113         bin->data = dataBuffer;
114         bin->parseState = CE_PS_RTI_ADDR;
115         bin->parsePtr = (unsigned char*)&bin->rtiPhysAddr;
116 }
117
118 int ce_parse_bin(ce_bin* bin)
119 {
120         unsigned char* pbData = bin->data;
121         int pbLen = bin->dataLen;
122         int copyLen;
123
124         #ifdef DEBUG
125         printf("starting ce image parsing:\n\tbin->binLen: 0x%08X\n", bin->binLen);
126         printf("\tpbData: 0x%08X        pbLEN: 0x%08X\n", pbData, pbLen);
127         #endif
128
129         if (pbLen)
130         {
131                 if (bin->binLen == 0)
132                 {
133                         // Check for the .BIN signature first
134
135                         if (!ce_is_bin_image(pbData, pbLen))
136                         {
137                                 printf("Error: Invalid or corrupted .BIN image!\n");
138
139                                 return CE_PR_ERROR;
140                         }
141
142                         printf("Loading Windows CE .BIN image ...\n");
143
144                         // Skip signature
145
146                         pbLen -= CE_BIN_SIGN_LEN;
147                         pbData += CE_BIN_SIGN_LEN;
148                 }
149
150                 while (pbLen)
151                 {
152                         switch (bin->parseState)
153                         {
154                         case CE_PS_RTI_ADDR:
155                         case CE_PS_RTI_LEN:
156                         case CE_PS_E_ADDR:
157                         case CE_PS_E_LEN:
158                         case CE_PS_E_CHKSUM:
159
160                                 copyLen = CE_MIN(sizeof(unsigned int) - bin->parseLen, pbLen);
161
162                                 memcpy(&bin->parsePtr[ bin->parseLen ], pbData, copyLen);
163
164                                 bin->parseLen += copyLen;
165                                 pbLen -= copyLen;
166                                 pbData += copyLen;
167
168                                 if (bin->parseLen == sizeof(unsigned int))
169                                 {
170                                         if (bin->parseState == CE_PS_RTI_ADDR)
171                                         {
172                                                 bin->rtiPhysAddr = CE_FIX_ADDRESS(bin->rtiPhysAddr);
173                                         }
174                                         else if (bin->parseState == CE_PS_E_ADDR)
175                                         {
176                                                 if (bin->ePhysAddr)
177                                                 {
178                                                         bin->ePhysAddr = CE_FIX_ADDRESS(bin->ePhysAddr);
179                                                 }
180                                         }
181
182                                         bin->parseState ++;
183                                         bin->parseLen = 0;
184                                         bin->parsePtr += sizeof(unsigned int);
185
186                                         if (bin->parseState == CE_PS_E_DATA)
187                                         {
188                                                 if (bin->ePhysAddr)
189                                                 {
190                                                         bin->parsePtr = (unsigned char*)(bin->ePhysAddr);
191                                                         bin->parseChkSum = 0;
192                                                 }
193                                                 else
194                                                 {
195                                                         // EOF
196
197                                                         pbLen = 0;
198                                                         bin->endOfBin = 1;
199                                                 }
200                                         }
201                                 }
202
203                                 break;
204
205                         case CE_PS_E_DATA:
206
207                                 if (bin->ePhysAddr)
208                                 {
209                                         copyLen = CE_MIN(bin->ePhysLen - bin->parseLen, pbLen);
210                                         bin->parseLen += copyLen;
211                                         pbLen -= copyLen;
212
213                                         #ifdef DEBUG
214                                         printf("copy %d bytes from: 0x%08X    to:  0x%08X\n", copyLen, pbData, bin->parsePtr);
215                                         #endif
216                                         while (copyLen --)
217                                         {
218                                                 bin->parseChkSum += *pbData;
219                                                 *bin->parsePtr ++ = *pbData ++;
220                                         }
221
222                                         if (bin->parseLen == bin->ePhysLen)
223                                         {
224                                                 printf("Section [%02d]: address 0x%08X, size 0x%08X, checksum %s\n",
225                                                         bin->secion,
226                                                         bin->ePhysAddr,
227                                                         bin->ePhysLen,
228                                                         (bin->eChkSum == bin->parseChkSum) ? "ok" : "fail");
229
230                                                 if (bin->eChkSum != bin->parseChkSum)
231                                                 {
232                                                         // Checksum error!
233
234                                                         printf("Error: Checksum error, corrupted .BIN file!\n");
235
236                                                         bin->binLen = 0;
237
238                                                         return CE_PR_ERROR;
239                                                 }
240
241                                                 bin->secion ++;
242                                                 bin->parseState = CE_PS_E_ADDR;
243                                                 bin->parseLen = 0;
244                                                 bin->parsePtr = (unsigned char*)(&bin->ePhysAddr);
245                                         }
246                                 }
247                                 else
248                                 {
249                                         bin->parseLen = 0;
250                                         bin->endOfBin = 1;
251                                         pbLen = 0;
252                                 }
253
254                                 break;
255                         }
256                 }
257         }
258
259         if (bin->endOfBin)
260         {
261                 // Find entry point
262
263                 if (!ce_lookup_ep_bin(bin))
264                 {
265                         printf("Error: entry point not found!\n");
266
267                         bin->binLen = 0;
268
269                         return CE_PR_ERROR;
270                 }
271
272                 printf("Entry point: 0x%08X, address range: 0x%08X-0x%08X\n",
273                         bin->eEntryPoint,
274                         bin->rtiPhysAddr,
275                         bin->rtiPhysAddr + bin->rtiPhysLen);
276
277                 return CE_PR_EOF;
278         }
279
280         // Need more data
281
282         bin->binLen += bin->dataLen;
283
284         return CE_PR_MORE;
285 }
286
287
288
289
290
291
292
293 void ce_prepare_run_bin(ce_bin* bin)
294 {
295         ce_driver_globals* drv_glb;
296         char    *e, *s;
297         char    tmp[64];
298         int                             i;
299
300
301         // Clear os RAM area (if needed)
302
303         //if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT)
304         {
305                 #ifdef DEBUG
306                 printf("cleaning memory from 0x%08X to 0x%08X\n", bin->eRamStart, bin->eRamStart + bin->eRamLen);
307                 #endif
308                 printf("Preparing clean boot ... ");
309                 memset((void*)bin->eRamStart, 0, bin->eRamLen);
310                 printf("ok\n");
311         }
312
313         // Prepare driver globals (if needed)
314
315         if (bin->eDrvGlb)
316         {
317                 drv_glb = (ce_driver_globals*)bin->eDrvGlb;
318
319                 // Fill out driver globals
320
321                 memset(drv_glb, 0, sizeof(ce_driver_globals));
322
323                 // Signature
324
325                 drv_glb->signature = DRV_GLB_SIGNATURE;
326
327                 // No flags by now
328
329                 drv_glb->flags = 0;
330
331                 /* Local ethernet MAC address */
332                 i = getenv_r ("ethaddr", tmp, sizeof (tmp));
333                 s = (i > 0) ? tmp : 0;
334
335                 for (i = 0; i < 6; ++i) {
336                         drv_glb->macAddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
337                         if (s)
338                                 s = (*e) ? e + 1 : e;
339                 }
340
341
342                 #ifdef DEBUG
343                 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]);
344                 #endif
345
346                 /* Local IP address */
347                 drv_glb->ipAddr=(unsigned int)getenv_IPaddr("ipaddr");
348                 #ifdef DEBUG
349                 printf("got IP address ");
350                 print_IPaddr((IPaddr_t)drv_glb->ipAddr);
351                 printf(" from environment\n");
352                 #endif
353
354                 /* Subnet mask */
355                 drv_glb->ipMask=(unsigned long)getenv_IPaddr("netmask");
356                 #ifdef DEBUG
357                 printf("got IP mask ");
358                 print_IPaddr((IPaddr_t)drv_glb->ipMask);
359                 printf(" from environment\n");
360                 #endif
361
362                 /* Gateway config */
363                 drv_glb->ipGate=(unsigned long)getenv_IPaddr("gatewayip");
364                 #ifdef DEBUG
365                 printf("got gateway address ");
366                 print_IPaddr((IPaddr_t)drv_glb->ipGate);
367                 printf(" from environment\n");
368                 #endif
369
370
371
372
373
374                 // EDBG services config
375
376                 memcpy(&drv_glb->edbgConfig, &bin->edbgConfig, sizeof(bin->edbgConfig));
377
378
379
380
381         }
382
383 }
384
385
386 int ce_lookup_ep_bin(ce_bin* bin)
387 {
388         ce_rom_hdr* header;
389         ce_toc_entry* tentry;
390         e32_rom* e32;
391         unsigned int i;
392
393         // Check image Table Of Contents (TOC) signature
394
395         if (*(unsigned int*)(bin->rtiPhysAddr + ROM_SIGNATURE_OFFSET) != ROM_SIGNATURE)
396         {
397                 // Error: Did not find image TOC signature!
398
399                 return 0;
400         }
401
402
403         // Lookup entry point
404
405         header = (ce_rom_hdr*)CE_FIX_ADDRESS(*(unsigned int*)(bin->rtiPhysAddr + ROM_SIGNATURE_OFFSET + sizeof(unsigned int)));
406         tentry = (ce_toc_entry*)(header + 1);
407
408         for (i = 0; i < header->nummods; i ++)
409         {
410                 // Look for 'nk.exe' module
411
412                 if (strcmp((char*)CE_FIX_ADDRESS(tentry[ i ].fileName), "nk.exe") == 0)
413                 {
414                         // Save entry point and RAM addresses
415
416                         e32 = (e32_rom*)CE_FIX_ADDRESS(tentry[ i ].e32Offset);
417
418                         bin->eEntryPoint = CE_FIX_ADDRESS(tentry[ i ].loadOffset) + e32->e32_entryrva;
419                         bin->eRamStart = CE_FIX_ADDRESS(header->ramStart);
420                         bin->eRamLen = header->ramEnd - header->ramStart;
421
422                         // Save driver_globals address
423                         // Must follow RAM section in CE config.bib file
424                         //
425                         // eg.
426                         //
427                         // RAM          80900000        03200000        RAM
428                         // DRV_GLB      83B00000        00001000        RESERVED
429                         //
430
431                         bin->eDrvGlb = CE_FIX_ADDRESS(header->ramEnd);
432
433                         return 1;
434                 }
435         }
436
437         // Error: Did not find 'nk.exe' module
438
439         return 0;
440 }
441
442
443
444
445 typedef void (*CeEntryPointPtr)(void);
446
447
448
449 void ce_run_bin(ce_bin* bin)
450 {
451         CeEntryPointPtr EnrtryPoint;
452
453         printf("Launching Windows CE ...\n");
454
455
456         EnrtryPoint = (CeEntryPointPtr)bin->eEntryPoint;
457
458         EnrtryPoint();
459
460 }
461
462 int ce_boot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
463 {
464         unsigned long   addr;
465         unsigned long   image_size;
466         unsigned char   *s;
467
468
469         if (argc < 2) {
470                 printf ("myUsage:\n%s\n", cmdtp->usage);
471                 return 1;
472         }
473
474         addr = simple_strtoul(argv[1], NULL, 16);
475         image_size = 0x7fffffff;                /* actually we do not know the image size */
476
477         printf ("## Booting Windows CE Image from address 0x%08lX ...\n", addr);
478
479
480         /* check if there is a valid windows CE image */
481         if (ce_is_bin_image((void *)addr, image_size))
482         {
483                 if (!ce_bin_load((void*)addr, image_size))
484                 {
485                         /* Ops! Corrupted .BIN image! */
486                         /* Handle error here ...      */
487                         printf("corrupted .BIN image !!!\n");
488                         return 1;
489
490                 }
491                 if ((s = getenv("autostart")) != NULL) {
492                         if (*s == 'n') {
493                                 /*
494                                 * just use bootce to load the image to SDRAM;
495                                 * Do not start it automatically.
496                                 */
497                                 return 0;
498                         }
499                 }
500         ce_run_bin(&g_bin);             /* start the image */
501
502         } else {
503                 printf("Image seems to be no valid Windows CE image !\n");
504                 return 1;
505
506         }
507         return 1;       /* never reached - just to keep compiler happy */
508
509
510 }
511
512
513
514 U_BOOT_CMD(
515         bootce, 2,      0,      ce_boot,
516         "bootce\t- Boot a Windows CE image from memory \n",
517         "[args..]\n"
518         "\taddr\t\t-boot image from address addr\n"
519 );
520
521
522
523 #if 1
524 static void wince_handler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
525 {
526
527
528         NetState = NETLOOP_SUCCESS;     /* got input - quit net loop */
529         if(!memcmp(g_net.data + g_net.align_offset, gd->bd->bi_enetaddr, 6)) {
530                 g_net.got_packet_4me=1;
531                 g_net.dataLen=len;
532         } else {
533                 g_net.got_packet_4me=0;
534                 return;
535         }
536
537         if(1) {
538                 g_net.srvAddrRecv.sin_port = ntohs(*((unsigned short *)(g_net.data + ETHER_HDR_SIZE + IP_HDR_SIZE_NO_UDP + g_net.align_offset)));
539                 NetCopyIP(&g_net.srvAddrRecv.sin_addr, g_net.data + ETHER_HDR_SIZE + g_net.align_offset + 12);
540                 memcpy(NetServerEther, g_net.data + g_net.align_offset +6, 6);
541
542                 #if 0
543                 printf("received packet:   buffer 0x%08X   Laenge %d \n", (unsigned long) pkt, len);
544                 printf("from ");
545                 print_IPaddr(g_net.srvAddrRecv.sin_addr);
546                 printf(", port: %d\n", g_net.srvAddrRecv.sin_port);
547
548
549
550                 ce_dump_block(pkt, len);
551
552                 printf("Headers:\n");
553                 ce_dump_block(pkt - ETHER_HDR_SIZE - IP_HDR_SIZE, ETHER_HDR_SIZE + IP_HDR_SIZE);
554                 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))));
555                 #endif
556         }
557
558 }
559
560
561
562 /* returns packet lengt if successfull */
563 int ce_recv_packet(char *buf, int len, struct sockaddr_in *from, struct sockaddr_in *local, struct timeval *timeout){
564
565         int rxlength;
566         ulong time_started;
567
568
569
570         g_net.got_packet_4me=0;
571         time_started = get_timer(0);
572
573
574         NetRxPackets[0] = (uchar *)buf;
575         NetSetHandler(wince_handler);
576
577         while(1) {
578                 rxlength=eth_rx();
579                 if(g_net.got_packet_4me)
580                         return g_net.dataLen;
581                 /* check for timeout */
582                 if (get_timer(time_started) > timeout->tv_sec * CFG_HZ) {
583                         return -1;
584                 }
585         }
586 }
587
588
589
590 int ce_recv_frame(ce_net* net, int timeout)
591 {
592         struct timeval timeo;
593
594         // Setup timeout
595
596         timeo.tv_sec = timeout;
597         timeo.tv_usec = 0;
598
599         /* Receive UDP packet */
600
601         net->dataLen = ce_recv_packet(net->data+net->align_offset, sizeof(net->data)-net->align_offset, &net->srvAddrRecv, &net->locAddr, &timeo);
602
603         if (net->dataLen < 0)
604         {
605                 /* Error! No data available */
606
607                 net->dataLen = 0;
608         }
609
610         return net->dataLen;
611 }
612
613 int ce_process_download(ce_net* net, ce_bin* bin)
614 {
615         int ret = CE_PR_MORE;
616
617         if (net->dataLen >= 2)
618         {
619                 unsigned short command;
620
621                 command = ntohs(*(unsigned short*)(net->data+CE_DOFFSET));
622
623                 #ifdef DEBUG
624                 printf("command found: 0x%04X\n", command);
625                 #endif
626
627                 switch (command)
628                 {
629                 case EDBG_CMD_WRITE_REQ:
630
631                         if (!net->link)
632                         {
633                                 // Check file name for WRITE request
634                                 // CE EShell uses "boot.bin" file name
635
636                                 /*printf(">>>>>>>> First Frame, IP: %s, port: %d\n",
637                                                         inet_ntoa((in_addr_t *)&net->srvAddrRecv),
638                                                         net->srvAddrRecv.sin_port);*/
639
640                                 if (strncmp((char*)(net->data +CE_DOFFSET + 2), "boot.bin", 8) == 0)
641                                 {
642                                         // Some diag output
643
644                                         if (net->verbose)
645                                         {
646                                                 printf("Locked Down download link, IP: ");
647                                                 print_IPaddr(net->srvAddrRecv.sin_addr);
648                                                 printf(", port: %d\n", net->srvAddrRecv.sin_port);
649                                         }
650
651
652
653
654                                         if (net->verbose)
655                                                 {
656                                                 printf("Sending BOOTME request [%d] to ", (int)net->secNum);
657                                                 print_IPaddr(net->srvAddrSend.sin_addr);
658                                                 printf("\n");
659                                         }
660
661
662
663
664                                         // Lock down EShell download link
665
666                                         net->locAddr.sin_port = (EDBG_DOWNLOAD_PORT + 1);
667                                         net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
668                                         net->srvAddrSend.sin_addr = net->srvAddrRecv.sin_addr;
669                                         net->link = 1;
670                                 }
671                                 else
672                                 {
673                                         // Unknown link
674
675                                         net->srvAddrRecv.sin_port = 0;
676                                 }
677
678                                 // Return write ack
679
680                                 if (net->link)
681                                 {
682                                         ce_send_write_ack(net);
683                                 }
684
685                                 break;
686                         }
687
688                 case EDBG_CMD_WRITE:
689
690                         /* Fix data len */
691                         bin->dataLen = net->dataLen - 4;
692
693                         // Parse next block of .bin file
694
695                         ret = ce_parse_bin(bin);
696
697                         // Request next block
698
699                         if (ret != CE_PR_ERROR)
700                         {
701                                 net->blockNum ++;
702
703                                 ce_send_write_ack(net);
704                         }
705
706                         break;
707
708                 case EDBG_CMD_READ_REQ:
709
710                         // Read requests are not supported
711                         // Do nothing ...
712
713                         break;
714
715                 case EDBG_CMD_ERROR:
716
717                         // Error condition on the host side
718
719                         printf("Error: unknown error on the host side\n");
720
721                         bin->binLen = 0;
722                         ret = CE_PR_ERROR;
723
724                         break;
725                 default:
726                         printf("unknown command 0x%04X ????\n", command);
727                         while(1);
728                 }
729
730
731         }
732
733         return ret;
734 }
735
736
737
738 void ce_init_edbg_link(ce_net* net)
739 {
740         /* Initialize EDBG link for commands */
741
742         net->locAddr.sin_port = EDBG_DOWNLOAD_PORT;
743         net->srvAddrSend.sin_port = EDBG_DOWNLOAD_PORT;
744         net->srvAddrRecv.sin_port = 0;
745         net->link = 0;
746 }
747
748 void ce_process_edbg(ce_net* net, ce_bin* bin)
749 {
750         eth_dbg_hdr* header;
751
752
753
754         if (net->dataLen < sizeof(eth_dbg_hdr))
755         {
756                 /* Bad packet */
757
758                 net->srvAddrRecv.sin_port = 0;
759                 return;
760         }
761
762         header = (eth_dbg_hdr*)(net->data + net->align_offset + ETHER_HDR_SIZE + IP_HDR_SIZE);
763
764         if (header->id != EDBG_ID)
765         {
766                 /* Bad packet */
767
768                 net->srvAddrRecv.sin_port = 0;
769                 return;
770         }
771
772         if (header->service != EDBG_SVC_ADMIN)
773         {
774                 /* Unknown service */
775
776                 return;
777         }
778
779         if (!net->link)
780         {
781                 /* Some diag output */
782
783                 if (net->verbose)
784                 {
785                         printf("Locked Down EDBG service link, IP: ");
786                         print_IPaddr(net->srvAddrRecv.sin_addr);
787                         printf(", port: %d\n", net->srvAddrRecv.sin_port);
788                 }
789
790                 /* Lock down EDBG link */
791
792                 net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
793                 net->link = 1;
794         }
795
796         switch (header->cmd)
797         {
798         case EDBG_CMD_JUMPIMG:
799
800                 net->gotJumpingRequest = 1;
801
802                 if (net->verbose)
803                 {
804                         printf("Received JUMPING command\n");
805                 }
806
807                 /* Just pass through and copy CONFIG structure  */
808
809         case EDBG_CMD_OS_CONFIG:
810
811                 /* Copy config structure */
812
813                 memcpy(&bin->edbgConfig, header->data, sizeof(edbg_os_config_data));
814
815                 if (net->verbose)
816                 {
817                         printf("Received CONFIG command\n");
818
819                         if (bin->edbgConfig.flags & EDBG_FL_DBGMSG)
820                         {
821                                 printf("--> Enabling DBGMSG service, IP: %d.%d.%d.%d, port: %d\n",
822                                         (bin->edbgConfig.dbgMsgIPAddr >> 0) & 0xFF,
823                                         (bin->edbgConfig.dbgMsgIPAddr >> 8) & 0xFF,
824                                         (bin->edbgConfig.dbgMsgIPAddr >> 16) & 0xFF,
825                                         (bin->edbgConfig.dbgMsgIPAddr >> 24) & 0xFF,
826                                         (int)bin->edbgConfig.dbgMsgPort);
827                         }
828
829                         if (bin->edbgConfig.flags & EDBG_FL_PPSH)
830                         {
831                                 printf("--> Enabling PPSH service, IP: %d.%d.%d.%d, port: %d\n",
832                                         (bin->edbgConfig.ppshIPAddr >> 0) & 0xFF,
833                                         (bin->edbgConfig.ppshIPAddr >> 8) & 0xFF,
834                                         (bin->edbgConfig.ppshIPAddr >> 16) & 0xFF,
835                                         (bin->edbgConfig.ppshIPAddr >> 24) & 0xFF,
836                                         (int)bin->edbgConfig.ppshPort);
837                         }
838
839                         if (bin->edbgConfig.flags & EDBG_FL_KDBG)
840                         {
841                                 printf("--> Enabling KDBG service, IP: %d.%d.%d.%d, port: %d\n",
842                                         (bin->edbgConfig.kdbgIPAddr >> 0) & 0xFF,
843                                         (bin->edbgConfig.kdbgIPAddr >> 8) & 0xFF,
844                                         (bin->edbgConfig.kdbgIPAddr >> 16) & 0xFF,
845                                         (bin->edbgConfig.kdbgIPAddr >> 24) & 0xFF,
846                                         (int)bin->edbgConfig.kdbgPort);
847                         }
848
849                         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT)
850                         {
851                                 printf("--> Force clean boot\n");
852                         }
853                 }
854
855                 break;
856
857         default:
858                 if (net->verbose) {
859                         printf("Received unknown command: %08X\n", header->cmd);
860                 }
861                 return;
862         }
863
864         /* Respond with ack */
865         header->flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK;
866         net->dataLen = EDBG_DATA_OFFSET;
867         ce_send_frame(net);
868 }
869
870 int ce_send_write_ack(ce_net* net)
871 {
872         unsigned short* wdata;
873         unsigned long aligned_address;
874
875         aligned_address=(unsigned long)net->data+ETHER_HDR_SIZE+IP_HDR_SIZE+net->align_offset;
876
877         wdata = (unsigned short*)aligned_address;
878         wdata[ 0 ] = htons(EDBG_CMD_WRITE_ACK);
879         wdata[ 1 ] = htons(net->blockNum);
880
881         net->dataLen = 4;
882
883         return ce_send_frame(net);
884 }
885
886
887
888 int ce_send_frame(ce_net* net)
889 {
890         /* Send UDP packet */
891         NetTxPacket = (uchar *)net->data + net->align_offset;
892         return NetSendUDPPacket(NetServerEther, net->srvAddrSend.sin_addr, (int)net->srvAddrSend.sin_port, (int)net->locAddr.sin_port, net->dataLen);
893 }
894
895
896
897
898
899
900
901 int ce_send_bootme(ce_net* net)
902 {
903         eth_dbg_hdr* header;
904         edbg_bootme_data* data;
905
906         char    *e, *s;
907         int                             i;
908         unsigned char   tmp[64];
909         unsigned char   *macp;
910
911         #ifdef DEBUG
912         char    *pkt;
913         #endif
914
915
916         /* Fill out BOOTME packet */
917         memset(net->data, 0, PKTSIZE);
918         header = (eth_dbg_hdr*)(net->data +CE_DOFFSET);
919         data = (edbg_bootme_data*)header->data;
920
921         header->id=EDBG_ID;
922         header->service = EDBG_SVC_ADMIN;
923         header->flags = EDBG_FL_FROM_DEV;
924         header->seqNum = net->secNum ++;
925         header->cmd = EDBG_CMD_BOOTME;
926
927         data->versionMajor = 0;
928         data->versionMinor = 0;
929         data->cpuId = EDBG_CPU_TYPE_ARM;
930         data->bootmeVer = EDBG_CURRENT_BOOTME_VERSION;
931         data->bootFlags = 0;
932         data->downloadPort = 0;
933         data->svcPort = 0;
934
935         macp=(unsigned char     *)data->macAddr;
936         /* MAC address from environment*/
937         i = getenv_r ("ethaddr", tmp, sizeof (tmp));
938         s = (i > 0) ? tmp : 0;
939         for (i = 0; i < 6; ++i) {
940                 macp[i] = s ? simple_strtoul (s, &e, 16) : 0;
941                 if (s)
942                         s = (*e) ? e + 1 : e;
943         }
944
945         /* IP address from environment */
946         data->ipAddr = (unsigned int)getenv_IPaddr("ipaddr");
947
948         // Device name string (NULL terminated). Should include
949         // platform and number based on Ether address (e.g. Odo42, CEPCLS2346, etc)
950
951         // We will use lower MAC address segment to create device name
952         // eg. MAC '00-0C-C6-69-09-05', device name 'Triton05'
953
954         strcpy(data->platformId, "Triton");
955         sprintf(data->deviceName, "%s%02X", data->platformId, macp[5]);
956
957
958 #ifdef DEBUG
959
960         printf("header->id: %08X\r\n", header->id);
961         printf("header->service: %08X\r\n", header->service);
962         printf("header->flags: %08X\r\n", header->flags);
963         printf("header->seqNum: %08X\r\n", header->seqNum);
964         printf("header->cmd: %08X\r\n\r\n", header->cmd);
965
966         printf("data->versionMajor: %08X\r\n", data->versionMajor);
967         printf("data->versionMinor: %08X\r\n", data->versionMinor);
968         printf("data->cpuId: %08X\r\n", data->cpuId);
969         printf("data->bootmeVer: %08X\r\n", data->bootmeVer);
970         printf("data->bootFlags: %08X\r\n", data->bootFlags);
971         printf("data->svcPort: %08X\r\n\r\n", data->svcPort);
972
973         printf("data->macAddr: %02X-%02X-%02X-%02X-%02X-%02X\r\n",
974                 (data->macAddr[0] >> 0) & 0xFF,
975                 (data->macAddr[0] >> 8) & 0xFF,
976                 (data->macAddr[1] >> 0) & 0xFF,
977                 (data->macAddr[1] >> 8) & 0xFF,
978                 (data->macAddr[2] >> 0) & 0xFF,
979                 (data->macAddr[2] >> 8) & 0xFF);
980
981         printf("data->ipAddr: %d.%d.%d.%d\r\n",
982                 (data->ipAddr >> 0) & 0xFF,
983                 (data->ipAddr >> 8) & 0xFF,
984                 (data->ipAddr >> 16) & 0xFF,
985                 (data->ipAddr >> 24) & 0xFF);
986
987         printf("data->platformId: %s\r\n", data->platformId);
988
989         printf("data->deviceName: %s\r\n", data->deviceName);
990
991 #endif
992
993
994         // Some diag output ...
995
996         if (net->verbose)
997         {
998                 printf("Sending BOOTME request [%d] to ", (int)net->secNum);
999                 print_IPaddr(net->srvAddrSend.sin_addr);
1000                 printf("\n");
1001         }
1002
1003         // Send packet
1004
1005         net->dataLen = BOOTME_PKT_SIZE;
1006
1007
1008         #ifdef DEBUG
1009         printf("\n\n\nStart of buffer:      0x%08X\n", (unsigned long)net->data);
1010         printf("Start of ethernet buffer:   0x%08X\n", (unsigned long)net->data+net->align_offset);
1011         printf("Start of CE header:         0x%08X\n", (unsigned long)header);
1012         printf("Start of CE data:           0x%08X\n", (unsigned long)data);
1013
1014         pkt = (uchar *)net->data+net->align_offset;
1015         printf("\n\npacket to send (ceconnect): \n");
1016         for(i=0; i<(net->dataLen+ETHER_HDR_SIZE+IP_HDR_SIZE); i++) {
1017                 printf("0x%02X ", pkt[i]);
1018                 if(!((i+1)%16))
1019                         printf("\n");
1020         }
1021         printf("\n\n");
1022         #endif
1023
1024         memcpy(NetServerEther, NetBcastAddr, 6);
1025
1026         return ce_send_frame(net);
1027 }
1028
1029
1030
1031 void ce_dump_block(unsigned char *ptr, int length) {
1032
1033         int i;
1034         int j;
1035
1036         for(i=0; i<length; i++) {
1037                 if(!(i%16)) {
1038                         printf("\n0x%08X: ", (unsigned long)ptr + i);
1039                 }
1040
1041                 printf("0x%02X ", ptr[i]);
1042
1043                 if(!((i+1)%16)){
1044                         printf("      ");
1045                         for(j=i-15; j<i; j++){
1046                                 if((ptr[j]>0x1f) && (ptr[j]<0x7f)) {
1047                                         printf("%c", ptr[j]);
1048                                 } else {
1049                                         printf(".");
1050                                 }
1051                         }
1052                 }
1053
1054         }
1055
1056         printf("\n\n");
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068 void ce_init_download_link(ce_net* net, ce_bin* bin, struct sockaddr_in* host_addr, int verbose)
1069 {
1070         unsigned long aligned_address;
1071         /* Initialize EDBG link for download */
1072
1073
1074         memset(net, 0, sizeof(ce_net));
1075
1076         /* our buffer contains space for ethernet- ip- and udp- headers */
1077         /* calucalate an offset that our ce field is aligned to 4 bytes */
1078         aligned_address=(unsigned long)net->data;                       /* this is the start of our physical buffer */
1079         aligned_address += (ETHER_HDR_SIZE+IP_HDR_SIZE);        /* we need 42 bytes room for headers (14 Ethernet , 20 IPv4, 8 UDP) */
1080         net->align_offset =     4-(aligned_address%4);                  /* want CE header aligned to 4 Byte boundary */
1081         if(net->align_offset == 4) {
1082                 net->align_offset=0;
1083         }
1084
1085         net->locAddr.sin_family = AF_INET;
1086     net->locAddr.sin_addr = getenv_IPaddr("ipaddr");
1087     net->locAddr.sin_port = EDBG_DOWNLOAD_PORT;
1088
1089         net->srvAddrSend.sin_family = AF_INET;
1090     net->srvAddrSend.sin_port = EDBG_DOWNLOAD_PORT;
1091
1092         net->srvAddrRecv.sin_family = AF_INET;
1093     net->srvAddrRecv.sin_port = 0;
1094
1095         if (host_addr->sin_addr)
1096         {
1097                 /* Use specified host address ... */
1098
1099                 net->srvAddrSend.sin_addr = host_addr->sin_addr;
1100                 net->srvAddrRecv.sin_addr = host_addr->sin_addr;
1101         }
1102         else
1103         {
1104                 /* ... or use default server address */
1105
1106                 net->srvAddrSend.sin_addr = getenv_IPaddr("serverip");
1107                 net->srvAddrRecv.sin_addr = getenv_IPaddr("serverip");
1108         }
1109
1110         net->verbose =  verbose;
1111         /* Initialize .BIN parser */
1112         ce_init_bin(bin, net->data + CE_DOFFSET + 4);
1113
1114
1115
1116         eth_halt();
1117
1118 #ifdef CONFIG_NET_MULTI
1119         eth_set_current();
1120 #endif
1121         if (eth_init(gd->bd) < 0) {
1122                 #ifdef ET_DEBUG
1123                 puts("ceconnect: failed to init ethernet !\n");
1124                 #endif
1125                 eth_halt();
1126                 return;
1127         }
1128         #ifdef ET_DEBUG
1129         puts("ceconnect: init ethernet done!\n");
1130         #endif
1131
1132
1133         memcpy (NetOurEther, gd->bd->bi_enetaddr, 6);
1134         NetCopyIP(&NetOurIP, &gd->bd->bi_ip_addr);
1135         NetOurGatewayIP = getenv_IPaddr ("gatewayip");
1136         NetOurSubnetMask= getenv_IPaddr ("netmask");
1137         NetServerIP = getenv_IPaddr ("serverip");
1138
1139 }
1140
1141
1142 int ce_load(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1143 {
1144         int i;
1145         int verbose, use_timeout;
1146         int timeout, recv_timeout, ret;
1147         struct sockaddr_in host_ip_addr;
1148
1149         // -v verbose
1150
1151         verbose = 0;
1152         use_timeout = 0;
1153         timeout = 0;
1154
1155
1156         for(i=0;i<argc;i++){
1157                 if (strcmp(argv[i+1], "-v") == 0){
1158                         verbose = 1;
1159                 }
1160         }
1161
1162
1163         for(i=0;i<(argc-1);i++){
1164                 if (strcmp(argv[i+1], "-t") == 0){
1165                         use_timeout = 1;
1166                         timeout = simple_strtoul(argv[i+2], NULL, 10);
1167                 }
1168         }
1169
1170         #ifdef DEBUG
1171         printf("verbose=%d, use_timeout=%d, timeout=%d\n", verbose, use_timeout, timeout);
1172         #endif
1173
1174         // Check host IP address (if specified)
1175
1176         *((unsigned int *)&host_ip_addr) = 0xFFFFFFFF;
1177
1178
1179         // Initialize download link
1180
1181         ce_init_download_link(&g_net, &g_bin, &host_ip_addr, verbose);
1182
1183         // Download loop
1184
1185         while (1)
1186         {
1187                 if (g_net.link)
1188                 {
1189                         recv_timeout = 3;
1190                 }
1191                 else
1192                 {
1193                         recv_timeout = 1;
1194
1195                         if (use_timeout)
1196                         {
1197                                 if (timeout <= 0)
1198                                 {
1199                                         printf("CELOAD - Canceled, timeout\n");
1200                                         eth_halt();
1201                                         return 1;
1202                                 }
1203                         } else {
1204                                 /* Try to catch ^C */
1205                                 #ifdef DEBUG
1206                                 puts("try to catch ^C\n");
1207                                 #endif
1208                                 if (ctrlc())
1209                                 {
1210                                         printf("CELOAD - canceled by user\n");
1211                                         eth_halt();
1212                                         return 1;
1213                                 }
1214                         }
1215                         #ifdef DEBUG
1216                         puts("sending broadcast frame bootme\n");
1217                         #endif
1218
1219                         if (ce_send_bootme(&g_net))
1220                         {
1221                                 printf("CELOAD - error while sending BOOTME request\n");
1222                                 eth_halt();
1223                                 return 1;
1224                         }
1225                         printf("net state is: %d\n", NetState);
1226                         if (verbose)
1227                         {
1228                                 if (use_timeout)
1229                                 {
1230                                         printf("Waiting for connection, timeout %d sec\n", timeout);
1231                                 }
1232                                 else
1233                                 {
1234                                         printf("Waiting for connection, enter ^C to abort\n");
1235                                 }
1236                         }
1237                 }
1238
1239                 // Try to receive frame
1240
1241                 if (ce_recv_frame(&g_net, recv_timeout))
1242                 {
1243                         // Process received data
1244
1245                         ret = ce_process_download(&g_net, &g_bin);
1246
1247                         if (ret != CE_PR_MORE)
1248                         {
1249                                 break;
1250                         }
1251                 }
1252                 else if (use_timeout)
1253                 {
1254                         timeout -= recv_timeout;
1255                 }
1256         }
1257
1258         if (g_bin.binLen)
1259         {
1260                 // Try to receive edbg commands from host
1261
1262                 ce_init_edbg_link(&g_net);
1263
1264                 if (verbose)
1265                 {
1266                         printf("Waiting for EDBG commands ...\n");
1267                 }
1268
1269                 while (ce_recv_frame(&g_net, 3))
1270                 {
1271                         ce_process_edbg(&g_net, &g_bin);
1272                 }
1273
1274                 // Prepare WinCE image for execution
1275
1276                 ce_prepare_run_bin(&g_bin);
1277
1278                 // Launch WinCE, if necessary
1279
1280                 if (g_net.gotJumpingRequest)
1281                 {
1282                         ce_run_bin(&g_bin);
1283                 }
1284         }
1285         eth_halt();
1286         return 0;
1287 }
1288
1289
1290
1291
1292
1293
1294
1295 U_BOOT_CMD(
1296         ceconnect,      2,      1,      ce_load,
1297         "ceconnect    - Set up a connection to the CE host PC over TCP/IP and download the run-time image\n",
1298         "ceconnect [-v] [-t <timeout>]\n"
1299         "  -v verbose operation\n"
1300         "  -t <timeout> - max wait time (#sec) for the connection\n"
1301 );
1302
1303 #endif
1304
1305 /* CFG_CMD_WINCE */