]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/wince.c
23cda480f96b085161542f090025f230a67462e6
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / wince.c
1 #include <redboot.h>
2 #include <cyg/io/flash.h>
3 #include <net/net.h>
4 #include CYGHWR_MEMORY_LAYOUT_H
5 #include <wince.h>
6 #include <winceinc.h>
7
8 cmd_fun do_go;
9
10 ///////////////////////////////////////////////////////////////////////////////////////////////
11 // Local macro
12
13 // Memory macro
14 #define CE_RAM_BASE                     CYGMEM_REGION_ram
15 #define CE_RAM_SIZE                     CYGMEM_REGION_ram_SIZE
16 #define CE_RAM_END                      (CE_RAM_BASE + CE_RAM_SIZE)
17 #define CE_WINCE_VRAM_BASE              0x80000000
18 #define CE_FIX_ADDRESS(a)               (((a) - CE_WINCE_VRAM_BASE) + CE_RAM_BASE)
19
20 #ifdef CYGHWR_REDBOOT_FLASH_CONFIG_MEDIA_FLASH
21 extern void *flash_start, *flash_end;
22
23 static inline int is_rom_addr(void *addr)
24 {
25         return addr >= flash_start && addr <= flash_end;
26 }
27 #else
28 #define is_rom_addr(p)          0
29 #endif
30
31 static inline int is_ram_addr(unsigned long addr)
32 {
33         return addr >= CE_RAM_BASE && addr < CE_RAM_END;
34 }
35
36 // Bin image parse states
37 #define CE_PS_RTI_ADDR                  0
38 #define CE_PS_RTI_LEN                   1
39 #define CE_PS_E_ADDR                    2
40 #define CE_PS_E_LEN                     3
41 #define CE_PS_E_CHKSUM                  4
42 #define CE_PS_E_DATA                    5
43
44 // Min/max
45 #define CE_MIN(a, b)                    (((a) < (b)) ? (a) : (b))
46 #define CE_MAX(a, b)                    (((a) > (b)) ? (a) : (b))
47
48 // Macro string
49 #define _STRMAC(s)                      #s
50 #define STRMAC(s)                       _STRMAC(s)
51
52 ///////////////////////////////////////////////////////////////////////////////////////////////
53 // Local types
54 typedef struct {
55         unsigned long rtiPhysAddr;
56         unsigned long rtiPhysLen;
57         unsigned long ePhysAddr;
58         unsigned long ePhysLen;
59         unsigned long eChkSum;
60
61         unsigned long eEntryPoint;
62         unsigned long eRamStart;
63         unsigned long eRamLen;
64         unsigned long eDrvGlb;
65
66         unsigned char parseState;
67         unsigned long parseChkSum;
68         int parseLen;
69         unsigned char *parsePtr;
70         int section;
71
72         int dataLen;
73         unsigned char *data;
74
75         int binLen;
76         int endOfBin;
77
78         edbg_os_config_data edbgConfig;
79 } ce_bin;
80
81 typedef struct {
82         bool verbose;
83         bool link;
84         struct sockaddr_in locAddr;
85         struct sockaddr_in srvAddrSend;
86         struct sockaddr_in srvAddrRecv;
87         bool gotJumpingRequest;
88         unsigned char secNum;
89         unsigned short blockNum;
90         int dataLen;
91         unsigned char data[516];
92 } ce_net;
93
94 ///////////////////////////////////////////////////////////////////////////////////////////////
95 // Global data
96 #ifdef CYGPKG_REDBOOT_NETWORKING
97 static ce_net g_net;
98 #endif
99 static ce_bin g_bin;
100
101 // Equotip3 specific
102 #ifdef CYGPKG_HAL_ARM_XSCALE_TRITON270_EQT32
103 #include <cyg/hal/hal_triton270.h>
104 extern EEDAT eedat;
105 #endif
106
107 ///////////////////////////////////////////////////////////////////////////////////////////////
108 // Local proto
109
110 void ce_init_bin(ce_bin *bin, unsigned char *dataBuffer);
111 int ce_parse_bin(ce_bin *bin);
112 bool ce_lookup_ep_bin(ce_bin *bin);
113 void ce_prepare_run_bin(ce_bin *bin);
114 void ce_run_bin(ce_bin *bin);
115
116 #ifdef CYGPKG_REDBOOT_NETWORKING
117 // Redboot network based routines
118 void ce_shell(int argc, char *argv[]);
119 void ce_init_download_link(ce_net *net, ce_bin *bin, struct sockaddr_in *host_addr, bool verbose);
120 void ce_init_edbg_link(ce_net *net);
121 int ce_send_frame(ce_net *net);
122 int ce_recv_frame(ce_net *net, int timeout);
123 int ce_send_bootme(ce_net *net);
124 int ce_send_write_ack(ce_net *net);
125 int ce_process_download(ce_net *net, ce_bin *bin);
126 void ce_process_edbg(ce_net *net, ce_bin *bin);
127
128 #endif
129
130 ///////////////////////////////////////////////////////////////////////////////////////////////
131 // RedBoot commands
132
133 #ifdef CYGPKG_REDBOOT_NETWORKING
134 // Redboot network based commands
135 RedBoot_cmd(
136             "ceconnect",
137             "Set up a connection to the CE host PC over TCP/IP and download the run-time image",
138             "[-v] [-t <timeout>] [-h <host>]",
139             ce_load
140             );
141 #endif
142
143 ///////////////////////////////////////////////////////////////////////////////////////////////
144 // Implementation
145
146 bool ce_bin_load(void *image, int imglen)
147 {
148         ce_init_bin(&g_bin, image);
149
150         g_bin.dataLen = imglen;
151
152         if (ce_parse_bin(&g_bin) == CE_PR_EOF) {
153                 ce_prepare_run_bin(&g_bin);
154                 return true;
155         }
156
157         return false;
158 }
159
160 bool ce_is_bin_image(void *image, int imglen)
161 {
162         if (imglen < CE_BIN_SIGN_LEN) {
163                 diag_printf("Not a valid CE image: image size %u shorter than minimum %u\n",
164                             imglen, CE_BIN_SIGN_LEN);
165                 return 0;
166         }
167         if (is_rom_addr(image)) {
168                 unsigned char sign_buf[CE_BIN_SIGN_LEN];
169                 void *err_addr;
170
171                 if (flash_read(image, sign_buf,
172                                CE_BIN_SIGN_LEN, &err_addr) != FLASH_ERR_OK) {
173                         return 0;
174                 }
175                 return memcmp(sign_buf, CE_BIN_SIGN, CE_BIN_SIGN_LEN) == 0;
176         }
177         return memcmp(image, CE_BIN_SIGN, CE_BIN_SIGN_LEN) == 0;
178 }
179
180 void ce_bin_init_parser()
181 {
182         // No buffer address by now, will be specified
183         // later by the ce_bin_parse_next routine
184         ce_init_bin(&g_bin, NULL);
185 }
186
187 int ce_bin_parse_next(void *parseBuffer, int len)
188 {
189         int rc;
190
191         g_bin.data = (unsigned char*)parseBuffer;
192         g_bin.dataLen = len;
193         rc = ce_parse_bin(&g_bin);
194
195         if (rc == CE_PR_EOF) {
196                 ce_prepare_run_bin(&g_bin);
197         }
198
199         return rc;
200 }
201
202 void ce_init_bin(ce_bin *bin, unsigned char *dataBuffer)
203 {
204         memset(bin, 0, sizeof(ce_bin));
205
206         bin->data = dataBuffer;
207         bin->parseState = CE_PS_RTI_ADDR;
208         bin->parsePtr = (unsigned char*)&bin->rtiPhysAddr;
209 }
210
211 int ce_parse_bin(ce_bin *bin)
212 {
213         unsigned char *pbData = bin->data;
214         int pbLen = bin->dataLen;
215         int copyLen;
216
217         if (pbLen) {
218                 if (bin->binLen == 0) {
219                         // Check for the .BIN signature first
220                         if (!ce_is_bin_image(pbData, pbLen)) {
221                                 diag_printf("** Error: Invalid or corrupted .BIN image!\n");
222
223                                 return CE_PR_ERROR;
224                         }
225
226                         diag_printf("Loading Windows CE .BIN image ...\n");
227
228                         // Skip signature
229                         pbLen -= CE_BIN_SIGN_LEN;
230                         pbData += CE_BIN_SIGN_LEN;
231                 }
232
233                 while (pbLen) {
234                         switch (bin->parseState) {
235                         case CE_PS_RTI_ADDR:
236                         case CE_PS_RTI_LEN:
237                         case CE_PS_E_ADDR:
238                         case CE_PS_E_LEN:
239                         case CE_PS_E_CHKSUM:
240
241                                 copyLen = CE_MIN(sizeof(unsigned int) - bin->parseLen, pbLen);
242
243                                 if (is_rom_addr(pbData)) {
244                                         void *err_addr;
245
246                                         if (flash_read(pbData, &bin->parsePtr[bin->parseLen],
247                                                        copyLen, &err_addr) != FLASH_ERR_OK) {
248                                                 return CE_PR_ERROR;
249                                         }
250                                 } else {
251                                         memcpy(&bin->parsePtr[bin->parseLen], pbData, copyLen);
252                                 }
253                                 bin->parseLen += copyLen;
254                                 pbLen -= copyLen;
255                                 pbData += copyLen;
256
257                                 if (bin->parseLen == sizeof(unsigned int)) {
258                                         if (bin->parseState == CE_PS_RTI_ADDR) {
259                                                 bin->rtiPhysAddr = CE_FIX_ADDRESS(bin->rtiPhysAddr);
260                                                 if (!is_ram_addr(bin->rtiPhysAddr)) {
261                                                         diag_printf("Invalid address %08lx in CE_PS_RTI_ADDR section\n",
262                                                                     bin->rtiPhysAddr);
263                                                         return CE_PR_ERROR;
264                                                 }
265                                         } else if (bin->parseState == CE_PS_E_ADDR) {
266                                                 if (bin->ePhysAddr) {
267                                                         bin->ePhysAddr = CE_FIX_ADDRESS(bin->ePhysAddr);
268                                                         if (!is_ram_addr(bin->ePhysAddr)) {
269                                                                 diag_printf("Invalid address %08lx in CE_PS_E_ADDR section\n",
270                                                                             bin->ePhysAddr);
271                                                                 return CE_PR_ERROR;
272                                                         }
273                                                 }
274                                         }
275
276                                         bin->parseState ++;
277                                         bin->parseLen = 0;
278                                         bin->parsePtr += sizeof(unsigned int);
279                                         if (bin->parseState == CE_PS_E_DATA) {
280                                                 if (bin->ePhysAddr) {
281                                                         bin->parsePtr = (unsigned char*)(bin->ePhysAddr);
282                                                         bin->parseChkSum = 0;
283                                                 } else {
284                                                         // EOF
285                                                         pbLen = 0;
286                                                         bin->endOfBin = 1;
287                                                 }
288                                         }
289                                 }
290
291                                 break;
292
293                         case CE_PS_E_DATA:
294                                 if (bin->ePhysAddr) {
295                                         copyLen = CE_MIN(bin->ePhysLen - bin->parseLen, pbLen);
296                                         bin->parseLen += copyLen;
297                                         pbLen -= copyLen;
298                                         if (is_rom_addr(pbData)) {
299                                                 void *err_addr;
300
301                                                 if (flash_read(pbData, bin->parsePtr,
302                                                                copyLen, &err_addr) != FLASH_ERR_OK) {
303                                                         return CE_PR_ERROR;
304                                                 }
305                                                 pbData += copyLen;
306                                                 while (copyLen--) {
307                                                         bin->parseChkSum += *bin->parsePtr++;
308                                                 }
309                                         } else {
310                                                 while (copyLen--) {
311                                                         bin->parseChkSum += *pbData;
312                                                         *bin->parsePtr ++ = *pbData ++;
313                                                 }
314                                         }
315                                         if (bin->parseLen == bin->ePhysLen) {
316                                                 diag_printf("Section [%02d]: address 0x%08lX, size 0x%08lX, checksum %s\n",
317                                                         bin->section,
318                                                         bin->ePhysAddr,
319                                                         bin->ePhysLen,
320                                                         (bin->eChkSum == bin->parseChkSum) ? "ok" : "fail");
321
322                                                 if (bin->eChkSum != bin->parseChkSum) {
323                                                         // Checksum error!
324
325                                                         diag_printf("Error: Checksum error, corrupted .BIN file!\n");
326
327                                                         bin->binLen = 0;
328
329                                                         return CE_PR_ERROR;
330                                                 }
331
332                                                 bin->section ++;
333                                                 bin->parseState = CE_PS_E_ADDR;
334                                                 bin->parseLen = 0;
335                                                 bin->parsePtr = (unsigned char*)(&bin->ePhysAddr);
336                                         }
337                                 } else {
338                                         bin->parseLen = 0;
339                                         bin->endOfBin = 1;
340                                         pbLen = 0;
341                                 }
342
343                                 break;
344                         }
345                 }
346         }
347
348         if (bin->endOfBin) {
349                 // Find entry point
350
351                 if (!ce_lookup_ep_bin(bin)) {
352                         diag_printf("** Error: entry point not found!\n");
353
354                         bin->binLen = 0;
355
356                         return CE_PR_ERROR;
357                 }
358
359                 diag_printf("Entry point: 0x%08lX, address range: 0x%08lX-0x%08lX\n",
360                         bin->eEntryPoint,
361                         bin->rtiPhysAddr,
362                         bin->rtiPhysAddr + bin->rtiPhysLen);
363
364                 return CE_PR_EOF;
365         }
366
367         // Need more data
368
369         bin->binLen += bin->dataLen;
370
371         return CE_PR_MORE;
372 }
373
374 bool ce_lookup_ep_bin(ce_bin *bin)
375 {
376         ce_rom_hdr *header;
377         ce_toc_entry *tentry;
378         e32_rom *e32;
379         unsigned int i;
380
381         // Check image Table Of Contents (TOC) signature
382         if (*(unsigned int*)(bin->rtiPhysAddr + ROM_SIGNATURE_OFFSET) != ROM_SIGNATURE) {
383                 // Error: Did not find image TOC signature!
384
385                 return 0;
386         }
387
388
389         // Lookup entry point
390         header = (ce_rom_hdr*)CE_FIX_ADDRESS(*(unsigned int*)(bin->rtiPhysAddr +
391                                                               ROM_SIGNATURE_OFFSET +
392                                                               sizeof(unsigned int)));
393         tentry = (ce_toc_entry*)(header + 1);
394
395         for (i = 0; i < header->nummods; i ++) {
396                 // Look for 'nk.exe' module
397                 if (strcmp((char*)CE_FIX_ADDRESS(tentry[ i ].fileName), "nk.exe") == 0) {
398                         // Save entry point and RAM addresses
399
400                         e32 = (e32_rom*)CE_FIX_ADDRESS(tentry[ i ].e32Offset);
401
402                         bin->eEntryPoint = CE_FIX_ADDRESS(tentry[ i ].loadOffset) +
403                                 e32->e32_entryrva;
404                         bin->eRamStart = CE_FIX_ADDRESS(header->ramStart);
405                         bin->eRamLen = header->ramEnd - header->ramStart;
406
407                         // Save driver_globals address
408                         // Must follow RAM section in CE config.bib file
409                         //
410                         // eg.
411                         //
412                         // RAM          80900000        03200000        RAM
413                         // DRV_GLB      83B00000        00001000        RESERVED
414                         //
415
416                         bin->eDrvGlb = CE_FIX_ADDRESS(header->ramEnd) -
417                                 sizeof(ce_driver_globals);
418                         return 1;
419                 }
420         }
421
422         // Error: Did not find 'nk.exe' module
423
424         return 0;
425 }
426
427 void setup_drv_globals(ce_driver_globals *drv_glb)
428 {
429         diag_printf("%s %p\n", __FUNCTION__, drv_glb);
430
431         // Fill out driver globals
432         memset(drv_glb, 0, sizeof(ce_driver_globals));
433
434         // Signature
435         drv_glb->signature = DRV_GLB_SIGNATURE;
436
437         // No flags by now
438         drv_glb->flags = 0;
439
440 #ifdef CYGPKG_REDBOOT_NETWORKING
441         // Local ethernet MAC address
442         memcpy(drv_glb->macAddr, __local_enet_addr, sizeof(__local_enet_addr));
443
444         // Local IP address
445         memcpy(&drv_glb->ipAddr, __local_ip_addr, sizeof(__local_ip_addr));
446
447         // Subnet mask
448         memcpy(&drv_glb->ipMask, __local_ip_mask, sizeof(__local_ip_mask));
449
450         // Gateway config
451 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
452         // Getway IP address
453         memcpy(&drv_glb->ipGate, __local_ip_gate, sizeof(__local_ip_gate));
454 #endif
455 #endif
456 }
457
458 #if WINCE_ALTERNATE_ARG_BASE
459 void setup_alt_drv_globals(ce_alt_driver_globals *alt_drv_glb)
460 {
461         diag_printf("%s %p\n", __FUNCTION__, alt_drv_glb);
462         // Fill out driver globals
463         memset(alt_drv_glb, 0, sizeof(ce_alt_driver_globals));
464
465         alt_drv_glb->header.signature = ALT_DRV_GLB_SIGNATURE;
466         alt_drv_glb->header.oalVersion = 1;
467         alt_drv_glb->header.bspVersion = 1;
468
469         alt_drv_glb->kitl.flags = 0;
470         diag_sprintf(alt_drv_glb->deviceId, "Triton");          
471
472 #ifdef CYGPKG_REDBOOT_NETWORKING
473         memcpy(&alt_drv_glb->kitl.mac[0], __local_enet_addr, sizeof(__local_enet_addr));
474         diag_sprintf(alt_drv_glb->deviceId, "Triton%02X", __local_enet_addr[5]);
475
476         // Local IP address
477         memcpy(&alt_drv_glb->kitl.ipAddress, __local_ip_addr, sizeof(__local_ip_addr));
478
479         // Subnet mask
480         memcpy(&alt_drv_glb->kitl.ipMask, __local_ip_mask, sizeof(__local_ip_mask));
481
482         // Gateway config
483 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
484         // Getway IP address
485         memcpy(&alt_drv_glb->kitl.ipRoute, __local_ip_gate, sizeof(__local_ip_gate));
486 #endif
487 #endif
488 }
489 #else
490 #define setup_alt_drv_globals(x)        CYG_EMPTY_STATEMENT
491 #endif
492
493 void ce_prepare_run_bin(ce_bin *bin)
494 {
495         ce_driver_globals *drv_glb;
496
497         diag_printf("%s\n", __FUNCTION__);
498
499 #if WINCE_ALTERNATE_ARG_BASE
500         ce_alt_driver_globals *alt_drv_glb = &_KARO_CECFG_START;
501         char *karo_magic = &_KARO_MAGIC[0];
502         unsigned long *karo_structure_size = &_KARO_STRUCT_SIZE;
503
504         memcpy(karo_magic, "KARO_CE6", sizeof(_KARO_MAGIC));
505         *karo_structure_size = sizeof(ce_alt_driver_globals);
506 #endif
507         // Clear os RAM area (if needed)
508         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
509                 diag_printf("Preparing clean boot ... ");
510                 memset((void *)bin->eRamStart, 0, bin->eRamLen);
511                 diag_printf("ok\n");
512         }
513
514         // Prepare driver globals (if needed)
515         if (bin->eDrvGlb) {
516                 drv_glb = (ce_driver_globals *)bin->eDrvGlb;
517
518                 setup_drv_globals(drv_glb);
519                 setup_alt_drv_globals(alt_drv_glb);
520
521                 // EDBG services config
522                 memcpy(&drv_glb->edbgConfig, &bin->edbgConfig, sizeof(bin->edbgConfig));
523         }
524
525         // Update global RedBoot entry point address
526         // to use with go/run commands
527         entry_address = bin->eEntryPoint;
528 }
529
530 void ce_run_bin(ce_bin *bin)
531 {
532         char *argv[] = { "go" };
533
534         diag_printf("Launching Windows CE ...\n");
535
536         // Call GO command direcly
537         do_go(1, argv);
538 }
539
540 // Extract version from CYGDAT_REDBOOT_CUSTOM_VERSION macro
541 // Works with versions like 'v2', 'v2.1', '2', '2.1', '2a', '2.1a'
542
543 void ce_redboot_version(unsigned int *vhigh, unsigned int *vlow)
544 {
545         char *pver = ""STRMAC(CYGDAT_REDBOOT_CUSTOM_VERSION);
546         char *p;
547         unsigned int *ver;
548         int len, pow;
549
550         *vhigh = *vlow = 0;
551         len = strlen(pver);
552         ver = vhigh;
553         pow = 1;
554         p = pver + strlen(pver) - 1;
555
556         while (len--) {
557                 if (*p >= '0' && *p <= '9') {
558                         *ver += ((*p - '0') * pow);
559                         pow *= 10;
560                 } else if (*p == '.') {
561                         if (ver == vhigh) {
562                                 *vlow = *vhigh;
563                                 *ver = 0;
564                                 pow = 1;
565                         } else {
566                                 break;
567                         }
568                 }
569                 p--;
570         }
571 }
572
573 ///////////////////////////////////////////////////////////////////////////////////////////////
574 // Redboot network based routines
575
576 #ifdef CYGPKG_REDBOOT_NETWORKING
577 void ce_load(int argc, char *argv[])
578 {
579         struct option_info opts[3];
580         bool verbose, use_timeout;
581         int timeout, recv_timeout, ret;
582         char *host_name;
583         char ctemp;
584         struct sockaddr_in host_ip_addr;
585
586         // Prepare for command line scan
587
588         verbose = false;
589         init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG, (void *)&verbose, NULL,
590                   "verbose operation");
591
592         timeout = 0;
593         init_opts(&opts[1], 't', true, OPTION_ARG_TYPE_NUM, (void *)&timeout, &use_timeout,
594                   "<timeout> - max wait time (#sec) for the connection");
595
596         host_name = NULL;
597         init_opts(&opts[2], 'h', true, OPTION_ARG_TYPE_STR, (void *)&host_name, NULL,
598                   "<host> - host name or IP address");
599
600         if (!scan_opts(argc, argv, 1, opts, 3, NULL, 0, "")) {
601                 diag_printf("CELOAD - Invalid option specified\n");
602                 return;
603         }
604
605         // Check host IP address (if specified)
606         memset(&host_ip_addr, 0, sizeof(host_ip_addr));
607         if (host_name) {
608                 if (!_gethostbyname(host_name, (in_addr_t*)&host_ip_addr)) {
609                         diag_printf("CELOAD - Invalid host name: %s\n", host_name);
610                         return;
611                 }
612         }
613
614         // Initialize download link
615
616         ce_init_download_link(&g_net, &g_bin, &host_ip_addr, verbose);
617
618         // Download loop
619
620         while (1) {
621                 if (g_net.link) {
622                         recv_timeout = 3;
623                 } else {
624                         recv_timeout = 1;
625
626                         if (use_timeout) {
627                                 if (timeout <= 0) {
628                                         diag_printf("CELOAD - Canceled, timeout\n");
629                                         return;
630                                 }
631                         } else {
632                                 // Try to catch ^C
633                                 if (_rb_gets(&ctemp, 1, 1) == _GETS_CTRLC) {
634                                         diag_printf("CELOAD - canceled by user\n");
635                                         return;
636                                 }
637                         }
638
639                         if (ce_send_bootme(&g_net)) {
640                                 diag_printf("CELOAD - error while sending BOOTME request\n");
641                                 return;
642                         }
643
644                         if (verbose) {
645                                 if (use_timeout) {
646                                         diag_printf("Waiting for connection, timeout %d sec\n",
647                                                     timeout);
648                                 } else {
649                                         diag_printf("Waiting for connection, enter ^C to abort\n");
650                                 }
651                         }
652                 }
653
654                 // Try to receive frame
655
656                 if (ce_recv_frame(&g_net, recv_timeout)) {
657                         // Process received data
658
659                         ret = ce_process_download(&g_net, &g_bin);
660
661                         if (ret != CE_PR_MORE) {
662                                 break;
663                         }
664                 } else if (use_timeout) {
665                         timeout -= recv_timeout;
666                 }
667         }
668
669         if (g_bin.binLen) {
670                 // Try to receive edbg commands from host
671                 ce_init_edbg_link(&g_net);
672
673                 if (verbose) {
674                         diag_printf("Waiting for EDBG commands ...\n");
675                 }
676
677                 while (ce_recv_frame(&g_net, 3)) {
678                         ce_process_edbg(&g_net, &g_bin);
679                 }
680
681                 // Prepare WinCE image for execution
682                 ce_prepare_run_bin(&g_bin);
683
684                 // Launch WinCE, if necessary
685                 if (g_net.gotJumpingRequest) {
686                         ce_run_bin(&g_bin);
687                 }
688         }
689 }
690
691 void ce_init_download_link(ce_net *net, ce_bin *bin, struct sockaddr_in *host_addr, bool verbose)
692 {
693         // Initialize EDBG link for download
694
695         memset(net, 0, sizeof(ce_net));
696
697         net->locAddr.sin_family = AF_INET;
698         memcpy(&net->locAddr.sin_addr, __local_ip_addr, sizeof(__local_ip_addr));
699         net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT);
700
701         net->srvAddrSend.sin_family = AF_INET;
702         net->srvAddrSend.sin_port = htons(EDBG_DOWNLOAD_PORT);
703
704         net->srvAddrRecv.sin_family = AF_INET;
705         net->srvAddrRecv.sin_port = 0;
706
707         if (host_addr->sin_addr.s_addr) {
708                 // Use specified host address ...
709
710                 net->srvAddrSend.sin_addr = host_addr->sin_addr;
711                 net->srvAddrRecv.sin_addr = host_addr->sin_addr;
712         } else {
713                 // ... or use default server address
714
715                 net->srvAddrSend.sin_addr = my_bootp_info.bp_siaddr;
716                 net->srvAddrRecv.sin_addr = my_bootp_info.bp_siaddr;
717         }
718
719         net->verbose = verbose;
720
721         // Initialize .BIN parser
722
723         // net->data + 0 -> Command
724         // net->data + 2 -> Block number
725         // net->data + 4 -> Block data
726
727         ce_init_bin(bin, net->data + 4);
728 }
729
730 void ce_init_edbg_link(ce_net *net)
731 {
732         // Initialize EDBG link for commands
733
734         net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT);
735         net->srvAddrSend.sin_port = htons(EDBG_DOWNLOAD_PORT);
736         net->srvAddrRecv.sin_port = 0;
737         net->link = false;
738 }
739
740 int ce_send_frame(ce_net *net)
741 {
742         // Send UDP packet
743
744         return __udp_sendto(net->data, net->dataLen, &net->srvAddrSend, &net->locAddr);
745 }
746
747 int ce_recv_frame(ce_net *net, int timeout)
748 {
749         struct timeval timeo;
750
751         // Setup timeout
752
753         timeo.tv_sec = timeout;
754         timeo.tv_usec = 0;
755
756         // Receive UDP packet
757
758         net->dataLen = __udp_recvfrom(net->data, sizeof(net->data), &net->srvAddrRecv,
759                                       &net->locAddr, &timeo);
760
761         if (net->dataLen < 0) {
762                 // Error! No data available
763
764                 net->dataLen = 0;
765         }
766         return net->dataLen;
767 }
768
769 int ce_send_bootme(ce_net *net)
770 {
771         eth_dbg_hdr *header;
772         edbg_bootme_data *data;
773         unsigned int verHigh, verLow;
774
775         // Fill out BOOTME packet
776         memset(net->data, 0, BOOTME_PKT_SIZE);
777
778         header = (eth_dbg_hdr*)net->data;
779         data = (edbg_bootme_data*)header->data;
780
781         header->id = EDBG_ID;
782         header->service = EDBG_SVC_ADMIN;
783         header->flags = EDBG_FL_FROM_DEV;
784         header->seqNum = net->secNum ++;
785         header->cmd = EDBG_CMD_BOOTME;
786
787         // Get RedBoot version
788         ce_redboot_version(&verHigh, &verLow);
789
790         data->versionMajor = verHigh;
791         data->versionMinor = verLow;
792         data->cpuId = EDBG_CPU_TYPE_ARM;
793         data->bootmeVer = EDBG_CURRENT_BOOTME_VERSION;
794         data->bootFlags = 0;
795         data->downloadPort = 0;
796         data->svcPort = 0;
797
798         memcpy(data->macAddr, __local_enet_addr, sizeof(__local_enet_addr));
799         memcpy(&data->ipAddr, __local_ip_addr, sizeof(__local_ip_addr));
800
801         // Device name string (NULL terminated). Should include
802         // platform and number based on Ether address (e.g. Odo42, CEPCLS2346, etc)
803
804         // We will use lower MAC address segment to create device name
805         // eg. MAC '00-0C-C6-69-09-05', device name 'Triton05'
806
807         strcpy(data->platformId, "Triton");
808         diag_sprintf(data->deviceName, "%s%02X", data->platformId, __local_enet_addr[5]);
809 #if 0
810         diag_printf("header->id: %08X\r\n", header->id);
811         diag_printf("header->service: %08X\r\n", header->service);
812         diag_printf("header->flags: %08X\r\n", header->flags);
813         diag_printf("header->seqNum: %08X\r\n", header->seqNum);
814         diag_printf("header->cmd: %08X\r\n\r\n", header->cmd);
815
816         diag_printf("data->versionMajor: %08X\r\n", data->versionMajor);
817         diag_printf("data->versionMinor: %08X\r\n", data->versionMinor);
818         diag_printf("data->cpuId: %08X\r\n", data->cpuId);
819         diag_printf("data->bootmeVer: %08X\r\n", data->bootmeVer);
820         diag_printf("data->bootFlags: %08X\r\n", data->bootFlags);
821         diag_printf("data->svcPort: %08X\r\n\r\n", data->svcPort);
822
823         diag_printf("data->macAddr: %02X-%02X-%02X-%02X-%02X-%02X-%02X\r\n",
824                 (data->macAddr[0] >> 0) & 0xFF,
825                 (data->macAddr[0] >> 8) & 0xFF,
826                 (data->macAddr[1] >> 0) & 0xFF,
827                 (data->macAddr[1] >> 8) & 0xFF,
828                 (data->macAddr[2] >> 0) & 0xFF,
829                 (data->macAddr[2] >> 8) & 0xFF);
830
831         diag_printf("data->ipAddr: %d.%d.%d.%d\r\n",
832                 (data->ipAddr >> 0) & 0xFF,
833                 (data->ipAddr >> 8) & 0xFF,
834                 (data->ipAddr >> 16) & 0xFF,
835                 (data->ipAddr >> 24) & 0xFF);
836
837         diag_printf("data->platformId: %s\r\n", data->platformId);
838         diag_printf("data->deviceName: %s\r\n", data->deviceName);
839 #endif
840         // Some diag output ...
841         if (net->verbose) {
842                 diag_printf("Sending BOOTME request [%d] to %s\n",
843                             net->secNum,
844                             inet_ntoa((in_addr_t *)&net->srvAddrSend));
845         }
846
847         // Send packet
848         net->dataLen = BOOTME_PKT_SIZE;
849
850         return ce_send_frame(net);
851 }
852
853 int ce_send_write_ack(ce_net *net)
854 {
855         unsigned short *wdata = (unsigned short*)net->data;
856
857         wdata[ 0 ] = htons(EDBG_CMD_WRITE_ACK);
858         wdata[ 1 ] = htons(net->blockNum);
859
860         net->dataLen = 4;
861
862         return ce_send_frame(net);
863 }
864
865 int ce_process_download(ce_net *net, ce_bin *bin)
866 {
867         int ret = CE_PR_MORE;
868
869         if (net->dataLen >= 2) {
870                 switch (ntohs(*(unsigned short*)net->data)) {
871                 case EDBG_CMD_WRITE_REQ:
872                         if (!net->link) {
873                                 // Check file name for WRITE request
874                                 // CE EShell uses "boot.bin" file name
875
876                                 /*diag_printf(">>>>>>>> First Frame, IP: %s, port: %d\n",
877                                                         inet_ntoa((in_addr_t *)&net->srvAddrRecv),
878                                                         net->srvAddrRecv.sin_port);*/
879                                 if (strncmp((char*)(net->data + 2), "boot.bin", 8) == 0) {
880                                         // Some diag output
881                                         if (net->verbose) {
882                                                 diag_printf("Locked Down download link, IP: %s, port: %d\n",
883                                                             inet_ntoa((in_addr_t *)&net->srvAddrRecv),
884                                                             net->srvAddrRecv.sin_port);
885                                         }
886
887                                         // Lock down EShell download link
888                                         net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT + 1);
889                                         net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
890                                         net->srvAddrSend.sin_addr = net->srvAddrRecv.sin_addr;
891                                         net->link = true;
892                                 } else {
893                                         // Unknown link
894                                         net->srvAddrRecv.sin_port = 0;
895                                 }
896
897                                 // Return write ack
898                                 if (net->link) {
899                                         ce_send_write_ack(net);
900                                 }
901                                 break;
902                         }
903                         // LW: is it really intended to fall thru in case of net->link != 0 ?
904                 case EDBG_CMD_WRITE:
905                         // Fix data len
906                         bin->dataLen = net->dataLen - 4;
907
908                         // Parse next block of .bin file
909                         ret = ce_parse_bin(bin);
910
911                         // Request next block
912                         if (ret != CE_PR_ERROR) {
913                                 net->blockNum ++;
914
915                                 ce_send_write_ack(net);
916                         }
917                         break;
918                 case EDBG_CMD_READ_REQ:
919                         // Read requests are not supported
920                         // Do nothing ...
921                         break;
922                 case EDBG_CMD_ERROR:
923                         // Error condition on the host side
924                         diag_printf("Error: unknown error on the host side\n");
925
926                         bin->binLen = 0;
927                         ret = CE_PR_ERROR;
928                         break;
929                 }
930         }
931
932         return ret;
933 }
934
935 void ce_process_edbg(ce_net *net, ce_bin *bin)
936 {
937         eth_dbg_hdr *header;
938
939         if (net->dataLen < sizeof(eth_dbg_hdr)) {
940                 // Bad packet
941
942                 net->srvAddrRecv.sin_port = 0;
943                 return;
944         }
945
946         header = (eth_dbg_hdr*)net->data;
947
948         if (header->id != EDBG_ID) {
949                 // Bad packet
950
951                 net->srvAddrRecv.sin_port = 0;
952                 return;
953         }
954
955         if (header->service != EDBG_SVC_ADMIN) {
956                 // Unknown service
957
958                 return;
959         }
960
961         if (!net->link) {
962                 // Some diag output
963
964                 if (net->verbose) {
965                         diag_printf("Locked Down EDBG service link, IP: %s, port: %d\n",
966                                 inet_ntoa((in_addr_t *)&net->srvAddrRecv),
967                                 net->srvAddrRecv.sin_port);
968                 }
969
970                 // Lock down EDBG link
971
972                 net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
973                 net->link = true;
974         }
975
976         switch (header->cmd) {
977         case EDBG_CMD_JUMPIMG:
978                 net->gotJumpingRequest = true;
979
980                 if (net->verbose) {
981                         diag_printf("Received JUMPING command\n");
982                 }
983                 // Just pass through and copy CONFIG structure
984         case EDBG_CMD_OS_CONFIG:
985                 // Copy config structure
986                 memcpy(&bin->edbgConfig, header->data, sizeof(edbg_os_config_data));
987                 if (net->verbose) {
988                         diag_printf("Received CONFIG command\n");
989                         if (bin->edbgConfig.flags & EDBG_FL_DBGMSG) {
990                                 diag_printf("--> Enabling DBGMSG service, IP: %d.%d.%d.%d, port: %d\n",
991                                         (bin->edbgConfig.dbgMsgIPAddr >> 0) & 0xFF,
992                                         (bin->edbgConfig.dbgMsgIPAddr >> 8) & 0xFF,
993                                         (bin->edbgConfig.dbgMsgIPAddr >> 16) & 0xFF,
994                                         (bin->edbgConfig.dbgMsgIPAddr >> 24) & 0xFF,
995                                         (int)bin->edbgConfig.dbgMsgPort);
996                         }
997                         if (bin->edbgConfig.flags & EDBG_FL_PPSH) {
998                                 diag_printf("--> Enabling PPSH service, IP: %d.%d.%d.%d, port: %d\n",
999                                         (bin->edbgConfig.ppshIPAddr >> 0) & 0xFF,
1000                                         (bin->edbgConfig.ppshIPAddr >> 8) & 0xFF,
1001                                         (bin->edbgConfig.ppshIPAddr >> 16) & 0xFF,
1002                                         (bin->edbgConfig.ppshIPAddr >> 24) & 0xFF,
1003                                         (int)bin->edbgConfig.ppshPort);
1004                         }
1005                         if (bin->edbgConfig.flags & EDBG_FL_KDBG) {
1006                                 diag_printf("--> Enabling KDBG service, IP: %d.%d.%d.%d, port: %d\n",
1007                                         (bin->edbgConfig.kdbgIPAddr >> 0) & 0xFF,
1008                                         (bin->edbgConfig.kdbgIPAddr >> 8) & 0xFF,
1009                                         (bin->edbgConfig.kdbgIPAddr >> 16) & 0xFF,
1010                                         (bin->edbgConfig.kdbgIPAddr >> 24) & 0xFF,
1011                                         (int)bin->edbgConfig.kdbgPort);
1012                         }
1013                         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
1014                                 diag_printf("--> Force clean boot\n");
1015                         }
1016                 }
1017                 break;
1018         default:
1019                 if (net->verbose) {
1020                         diag_printf("Received unknown command: %08X\n", header->cmd);
1021                 }
1022                 return;
1023         }
1024
1025         // Respond with ack
1026         header->flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK;
1027         net->dataLen = EDBG_DATA_OFFSET;
1028
1029         ce_send_frame(net);
1030 }
1031 #endif
1032