5d91d83e3e3c3da8965f618afb068204eaf1660e
[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                                                         diag_printf("Error: Checksum error, corrupted .BIN file!\n");
325                                                         diag_printf("checksum calculated: 0x%08lx from file: 0x%08lx\n",
326                                                                                 bin->parseChkSum, bin->eChkSum);
327                                                         bin->binLen = 0;
328                                                         return CE_PR_ERROR;
329                                                 }
330
331                                                 bin->section++;
332                                                 bin->parseState = CE_PS_E_ADDR;
333                                                 bin->parseLen = 0;
334                                                 bin->parsePtr = (unsigned char*)(&bin->ePhysAddr);
335                                         }
336                                 } else {
337                                         bin->parseLen = 0;
338                                         bin->endOfBin = 1;
339                                         pbLen = 0;
340                                 }
341
342                                 break;
343                         }
344                 }
345         }
346
347         if (bin->endOfBin) {
348                 // Find entry point
349
350                 if (!ce_lookup_ep_bin(bin)) {
351                         diag_printf("** Error: entry point not found!\n");
352
353                         bin->binLen = 0;
354
355                         return CE_PR_ERROR;
356                 }
357
358                 diag_printf("Entry point: 0x%08lX, address range: 0x%08lX-0x%08lX\n",
359                         bin->eEntryPoint,
360                         bin->rtiPhysAddr,
361                         bin->rtiPhysAddr + bin->rtiPhysLen);
362
363                 return CE_PR_EOF;
364         }
365
366         // Need more data
367
368         bin->binLen += bin->dataLen;
369
370         return CE_PR_MORE;
371 }
372
373 bool ce_lookup_ep_bin(ce_bin *bin)
374 {
375         ce_rom_hdr *header;
376         ce_toc_entry *tentry;
377         e32_rom *e32;
378         unsigned int i;
379
380         // Check image Table Of Contents (TOC) signature
381         if (*(unsigned int*)(bin->rtiPhysAddr + ROM_SIGNATURE_OFFSET) != ROM_SIGNATURE) {
382                 // Error: Did not find image TOC signature!
383
384                 return 0;
385         }
386
387
388         // Lookup entry point
389         header = (ce_rom_hdr*)CE_FIX_ADDRESS(*(unsigned int*)(bin->rtiPhysAddr +
390                                                               ROM_SIGNATURE_OFFSET +
391                                                               sizeof(unsigned int)));
392         tentry = (ce_toc_entry*)(header + 1);
393
394         for (i = 0; i < header->nummods; i++) {
395                 // Look for 'nk.exe' module
396                 if (strcmp((char*)CE_FIX_ADDRESS(tentry[ i ].fileName), "nk.exe") == 0) {
397                         // Save entry point and RAM addresses
398
399                         e32 = (e32_rom*)CE_FIX_ADDRESS(tentry[ i ].e32Offset);
400
401                         bin->eEntryPoint = CE_FIX_ADDRESS(tentry[ i ].loadOffset) +
402                                 e32->e32_entryrva;
403                         bin->eRamStart = CE_FIX_ADDRESS(header->ramStart);
404                         bin->eRamLen = header->ramEnd - header->ramStart;
405
406                         // Save driver_globals address
407                         // Must follow RAM section in CE config.bib file
408                         //
409                         // eg.
410                         //
411                         // RAM          80900000        03200000        RAM
412                         // DRV_GLB      83B00000        00001000        RESERVED
413                         //
414
415                         bin->eDrvGlb = CE_FIX_ADDRESS(header->ramEnd) -
416                                 sizeof(ce_driver_globals);
417                         return 1;
418                 }
419         }
420
421         // Error: Did not find 'nk.exe' module
422
423         return 0;
424 }
425
426 void setup_drv_globals(ce_driver_globals *drv_glb)
427 {
428         diag_printf("%s %p\n", __FUNCTION__, drv_glb);
429
430         // Fill out driver globals
431         memset(drv_glb, 0, sizeof(ce_driver_globals));
432
433         // Signature
434         drv_glb->signature = DRV_GLB_SIGNATURE;
435
436         // No flags by now
437         drv_glb->flags = 0;
438
439 #ifdef CYGPKG_REDBOOT_NETWORKING
440         // Local ethernet MAC address
441         memcpy(drv_glb->macAddr, __local_enet_addr, sizeof(__local_enet_addr));
442
443         // Local IP address
444         memcpy(&drv_glb->ipAddr, __local_ip_addr, sizeof(__local_ip_addr));
445
446         // Subnet mask
447         memcpy(&drv_glb->ipMask, __local_ip_mask, sizeof(__local_ip_mask));
448
449         // Gateway config
450 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
451         // Getway IP address
452         memcpy(&drv_glb->ipGate, __local_ip_gate, sizeof(__local_ip_gate));
453 #endif
454 #endif
455 }
456
457 #if WINCE_ALTERNATE_ARG_BASE
458 void setup_alt_drv_globals(ce_alt_driver_globals *alt_drv_glb)
459 {
460         diag_printf("%s %p\n", __FUNCTION__, alt_drv_glb);
461         // Fill out driver globals
462         memset(alt_drv_glb, 0, sizeof(ce_alt_driver_globals));
463
464         alt_drv_glb->header.signature = ALT_DRV_GLB_SIGNATURE;
465         alt_drv_glb->header.oalVersion = 1;
466         alt_drv_glb->header.bspVersion = 1;
467
468         alt_drv_glb->kitl.flags = 0;
469         diag_sprintf(alt_drv_glb->deviceId, "Triton");          
470
471 #ifdef CYGPKG_REDBOOT_NETWORKING
472         memcpy(&alt_drv_glb->kitl.mac[0], __local_enet_addr, sizeof(__local_enet_addr));
473         diag_sprintf(alt_drv_glb->deviceId, "Triton%02X", __local_enet_addr[5]);
474
475         // Local IP address
476         memcpy(&alt_drv_glb->kitl.ipAddress, __local_ip_addr, sizeof(__local_ip_addr));
477
478         // Subnet mask
479         memcpy(&alt_drv_glb->kitl.ipMask, __local_ip_mask, sizeof(__local_ip_mask));
480
481         // Gateway config
482 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
483         // Getway IP address
484         memcpy(&alt_drv_glb->kitl.ipRoute, __local_ip_gate, sizeof(__local_ip_gate));
485 #endif
486 #endif
487 }
488 #else
489 #define setup_alt_drv_globals(x)        CYG_EMPTY_STATEMENT
490 #endif
491
492 void ce_prepare_run_bin(ce_bin *bin)
493 {
494         ce_driver_globals *drv_glb;
495
496         diag_printf("%s\n", __FUNCTION__);
497
498 #if WINCE_ALTERNATE_ARG_BASE
499         ce_alt_driver_globals *alt_drv_glb = &_KARO_CECFG_START;
500         char *karo_magic = &_KARO_MAGIC[0];
501         unsigned long *karo_structure_size = &_KARO_STRUCT_SIZE;
502
503         memcpy(karo_magic, "KARO_CE6", sizeof(_KARO_MAGIC));
504         *karo_structure_size = sizeof(ce_alt_driver_globals);
505 #endif
506         // Clear os RAM area (if needed)
507         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
508                 diag_printf("Preparing clean boot ... ");
509                 memset((void *)bin->eRamStart, 0, bin->eRamLen);
510                 diag_printf("ok\n");
511         }
512
513         // Prepare driver globals (if needed)
514         if (bin->eDrvGlb) {
515                 drv_glb = (ce_driver_globals *)bin->eDrvGlb;
516
517                 setup_drv_globals(drv_glb);
518                 setup_alt_drv_globals(alt_drv_glb);
519
520                 // EDBG services config
521                 memcpy(&drv_glb->edbgConfig, &bin->edbgConfig, sizeof(bin->edbgConfig));
522         }
523
524         // Update global RedBoot entry point address
525         // to use with go/run commands
526         entry_address = bin->eEntryPoint;
527 }
528
529 void ce_run_bin(ce_bin *bin)
530 {
531         char *argv[] = { "go" };
532
533         diag_printf("Launching Windows CE ...\n");
534
535         // Call GO command direcly
536         do_go(1, argv);
537 }
538
539 // Extract version from CYGDAT_REDBOOT_CUSTOM_VERSION macro
540 // Works with versions like 'v2', 'v2.1', '2', '2.1', '2a', '2.1a'
541
542 void ce_redboot_version(unsigned int *vhigh, unsigned int *vlow)
543 {
544         char *pver = ""STRMAC(CYGDAT_REDBOOT_CUSTOM_VERSION);
545         char *p;
546         unsigned int *ver;
547         int len, pow;
548
549         *vhigh = *vlow = 0;
550         len = strlen(pver);
551         ver = vhigh;
552         pow = 1;
553         p = pver + strlen(pver) - 1;
554
555         while (len--) {
556                 if (*p >= '0' && *p <= '9') {
557                         *ver += ((*p - '0') * pow);
558                         pow *= 10;
559                 } else if (*p == '.') {
560                         if (ver == vhigh) {
561                                 *vlow = *vhigh;
562                                 *ver = 0;
563                                 pow = 1;
564                         } else {
565                                 break;
566                         }
567                 }
568                 p--;
569         }
570 }
571
572 ///////////////////////////////////////////////////////////////////////////////////////////////
573 // Redboot network based routines
574
575 #ifdef CYGPKG_REDBOOT_NETWORKING
576 void ce_load(int argc, char *argv[])
577 {
578         struct option_info opts[3];
579         bool verbose, use_timeout;
580         int timeout, recv_timeout, ret;
581         char *host_name;
582         char ctemp;
583         struct sockaddr_in host_ip_addr;
584
585         // Prepare for command line scan
586
587         verbose = false;
588         init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG, (void *)&verbose, NULL,
589                   "verbose operation");
590
591         timeout = 0;
592         init_opts(&opts[1], 't', true, OPTION_ARG_TYPE_NUM, (void *)&timeout, &use_timeout,
593                   "<timeout> - max wait time (#sec) for the connection");
594
595         host_name = NULL;
596         init_opts(&opts[2], 'h', true, OPTION_ARG_TYPE_STR, (void *)&host_name, NULL,
597                   "<host> - host name or IP address");
598
599         if (!scan_opts(argc, argv, 1, opts, 3, NULL, 0, "")) {
600                 diag_printf("CELOAD - Invalid option specified\n");
601                 return;
602         }
603
604         // Check host IP address (if specified)
605         memset(&host_ip_addr, 0, sizeof(host_ip_addr));
606         if (host_name) {
607                 if (!_gethostbyname(host_name, (in_addr_t*)&host_ip_addr)) {
608                         diag_printf("CELOAD - Invalid host name: %s\n", host_name);
609                         return;
610                 }
611         }
612
613         // Initialize download link
614
615         ce_init_download_link(&g_net, &g_bin, &host_ip_addr, verbose);
616
617         // Download loop
618
619         while (1) {
620                 if (g_net.link) {
621                         recv_timeout = 3;
622                 } else {
623                         recv_timeout = 1;
624
625                         if (use_timeout) {
626                                 if (timeout <= 0) {
627                                         diag_printf("CELOAD - Canceled, timeout\n");
628                                         return;
629                                 }
630                         } else {
631                                 // Try to catch ^C
632                                 if (_rb_gets(&ctemp, 1, 1) == _GETS_CTRLC) {
633                                         diag_printf("CELOAD - canceled by user\n");
634                                         return;
635                                 }
636                         }
637
638                         if (ce_send_bootme(&g_net)) {
639                                 diag_printf("CELOAD - error while sending BOOTME request\n");
640                                 return;
641                         }
642
643                         if (verbose) {
644                                 if (use_timeout) {
645                                         diag_printf("Waiting for connection, timeout %d sec\n",
646                                                     timeout);
647                                 } else {
648                                         diag_printf("Waiting for connection, enter ^C to abort\n");
649                                 }
650                         }
651                 }
652
653                 // Try to receive frame
654
655                 if (ce_recv_frame(&g_net, recv_timeout)) {
656                         // Process received data
657
658                         ret = ce_process_download(&g_net, &g_bin);
659
660                         if (ret != CE_PR_MORE) {
661                                 break;
662                         }
663                 } else if (use_timeout) {
664                         timeout -= recv_timeout;
665                 }
666         }
667
668         if (g_bin.binLen) {
669                 // Try to receive edbg commands from host
670                 ce_init_edbg_link(&g_net);
671
672                 if (verbose) {
673                         diag_printf("Waiting for EDBG commands ...\n");
674                 }
675
676                 while (ce_recv_frame(&g_net, 3)) {
677                         ce_process_edbg(&g_net, &g_bin);
678                 }
679
680                 // Prepare WinCE image for execution
681                 ce_prepare_run_bin(&g_bin);
682
683                 // Launch WinCE, if necessary
684                 if (g_net.gotJumpingRequest) {
685                         ce_run_bin(&g_bin);
686                 }
687         }
688 }
689
690 void ce_init_download_link(ce_net *net, ce_bin *bin, struct sockaddr_in *host_addr, bool verbose)
691 {
692         // Initialize EDBG link for download
693
694         memset(net, 0, sizeof(ce_net));
695
696         net->locAddr.sin_family = AF_INET;
697         memcpy(&net->locAddr.sin_addr, __local_ip_addr, sizeof(__local_ip_addr));
698         net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT);
699
700         net->srvAddrSend.sin_family = AF_INET;
701         net->srvAddrSend.sin_port = htons(EDBG_DOWNLOAD_PORT);
702
703         net->srvAddrRecv.sin_family = AF_INET;
704         net->srvAddrRecv.sin_port = 0;
705
706         if (host_addr->sin_addr.s_addr) {
707                 // Use specified host address ...
708
709                 net->srvAddrSend.sin_addr = host_addr->sin_addr;
710                 net->srvAddrRecv.sin_addr = host_addr->sin_addr;
711         } else {
712                 // ... or use default server address
713
714                 net->srvAddrSend.sin_addr = my_bootp_info.bp_siaddr;
715                 net->srvAddrRecv.sin_addr = my_bootp_info.bp_siaddr;
716         }
717
718         net->verbose = verbose;
719
720         // Initialize .BIN parser
721
722         // net->data + 0 -> Command
723         // net->data + 2 -> Block number
724         // net->data + 4 -> Block data
725
726         ce_init_bin(bin, net->data + 4);
727 }
728
729 void ce_init_edbg_link(ce_net *net)
730 {
731         // Initialize EDBG link for commands
732
733         net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT);
734         net->srvAddrSend.sin_port = htons(EDBG_DOWNLOAD_PORT);
735         net->srvAddrRecv.sin_port = 0;
736         net->link = false;
737 }
738
739 int ce_send_frame(ce_net *net)
740 {
741         // Send UDP packet
742
743         return __udp_sendto(net->data, net->dataLen, &net->srvAddrSend, &net->locAddr);
744 }
745
746 int ce_recv_frame(ce_net *net, int timeout)
747 {
748         struct timeval timeo;
749
750         // Setup timeout
751
752         timeo.tv_sec = timeout;
753         timeo.tv_usec = 0;
754
755         // Receive UDP packet
756
757         net->dataLen = __udp_recvfrom(net->data, sizeof(net->data), &net->srvAddrRecv,
758                                       &net->locAddr, &timeo);
759
760         if (net->dataLen < 0) {
761                 // Error! No data available
762
763                 net->dataLen = 0;
764         }
765         return net->dataLen;
766 }
767
768 int ce_send_bootme(ce_net *net)
769 {
770         eth_dbg_hdr *header;
771         edbg_bootme_data *data;
772         unsigned int verHigh, verLow;
773
774         // Fill out BOOTME packet
775         memset(net->data, 0, BOOTME_PKT_SIZE);
776
777         header = (eth_dbg_hdr*)net->data;
778         data = (edbg_bootme_data*)header->data;
779
780         header->id = EDBG_ID;
781         header->service = EDBG_SVC_ADMIN;
782         header->flags = EDBG_FL_FROM_DEV;
783         header->seqNum = net->secNum++;
784         header->cmd = EDBG_CMD_BOOTME;
785
786         // Get RedBoot version
787         ce_redboot_version(&verHigh, &verLow);
788
789         data->versionMajor = verHigh;
790         data->versionMinor = verLow;
791         data->cpuId = EDBG_CPU_TYPE_ARM;
792         data->bootmeVer = EDBG_CURRENT_BOOTME_VERSION;
793         data->bootFlags = 0;
794         data->downloadPort = 0;
795         data->svcPort = 0;
796
797         memcpy(data->macAddr, __local_enet_addr, sizeof(__local_enet_addr));
798         memcpy(&data->ipAddr, __local_ip_addr, sizeof(__local_ip_addr));
799
800         // Device name string (NULL terminated). Should include
801         // platform and number based on Ether address (e.g. Odo42, CEPCLS2346, etc)
802
803         // We will use lower MAC address segment to create device name
804         // eg. MAC '00-0C-C6-69-09-05', device name 'Triton05'
805
806         strcpy(data->platformId, "Triton");
807         diag_sprintf(data->deviceName, "%s%02X", data->platformId, __local_enet_addr[5]);
808 #if 0
809         diag_printf("header->id: %08X\r\n", header->id);
810         diag_printf("header->service: %08X\r\n", header->service);
811         diag_printf("header->flags: %08X\r\n", header->flags);
812         diag_printf("header->seqNum: %08X\r\n", header->seqNum);
813         diag_printf("header->cmd: %08X\r\n\r\n", header->cmd);
814
815         diag_printf("data->versionMajor: %08X\r\n", data->versionMajor);
816         diag_printf("data->versionMinor: %08X\r\n", data->versionMinor);
817         diag_printf("data->cpuId: %08X\r\n", data->cpuId);
818         diag_printf("data->bootmeVer: %08X\r\n", data->bootmeVer);
819         diag_printf("data->bootFlags: %08X\r\n", data->bootFlags);
820         diag_printf("data->svcPort: %08X\r\n\r\n", data->svcPort);
821
822         diag_printf("data->macAddr: %02X-%02X-%02X-%02X-%02X-%02X-%02X\r\n",
823                 (data->macAddr[0] >> 0) & 0xFF,
824                 (data->macAddr[0] >> 8) & 0xFF,
825                 (data->macAddr[1] >> 0) & 0xFF,
826                 (data->macAddr[1] >> 8) & 0xFF,
827                 (data->macAddr[2] >> 0) & 0xFF,
828                 (data->macAddr[2] >> 8) & 0xFF);
829
830         diag_printf("data->ipAddr: %d.%d.%d.%d\r\n",
831                 (data->ipAddr >> 0) & 0xFF,
832                 (data->ipAddr >> 8) & 0xFF,
833                 (data->ipAddr >> 16) & 0xFF,
834                 (data->ipAddr >> 24) & 0xFF);
835
836         diag_printf("data->platformId: %s\r\n", data->platformId);
837         diag_printf("data->deviceName: %s\r\n", data->deviceName);
838 #endif
839         // Some diag output ...
840         if (net->verbose) {
841                 diag_printf("Sending BOOTME request [%d] to %s\n",
842                             net->secNum,
843                             inet_ntoa((in_addr_t *)&net->srvAddrSend));
844         }
845
846         // Send packet
847         net->dataLen = BOOTME_PKT_SIZE;
848
849         return ce_send_frame(net);
850 }
851
852 int ce_send_write_ack(ce_net *net)
853 {
854         unsigned short *wdata = (unsigned short*)net->data;
855
856         wdata[ 0 ] = htons(EDBG_CMD_WRITE_ACK);
857         wdata[ 1 ] = htons(net->blockNum);
858
859         net->dataLen = 4;
860
861         return ce_send_frame(net);
862 }
863
864 int ce_process_download(ce_net *net, ce_bin *bin)
865 {
866         int ret = CE_PR_MORE;
867
868         if (net->dataLen >= 2) {
869                 switch (ntohs(*(unsigned short*)net->data)) {
870                 case EDBG_CMD_WRITE_REQ:
871                         if (!net->link) {
872                                 // Check file name for WRITE request
873                                 // CE EShell uses "boot.bin" file name
874
875                                 /*diag_printf(">>>>>>>> First Frame, IP: %s, port: %d\n",
876                                                         inet_ntoa((in_addr_t *)&net->srvAddrRecv),
877                                                         net->srvAddrRecv.sin_port);*/
878                                 if (strncmp((char*)(net->data + 2), "boot.bin", 8) == 0) {
879                                         // Some diag output
880                                         if (net->verbose) {
881                                                 diag_printf("Locked Down download link, IP: %s, port: %d\n",
882                                                             inet_ntoa((in_addr_t *)&net->srvAddrRecv),
883                                                             net->srvAddrRecv.sin_port);
884                                         }
885
886                                         // Lock down EShell download link
887                                         net->locAddr.sin_port = htons(EDBG_DOWNLOAD_PORT + 1);
888                                         net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
889                                         net->srvAddrSend.sin_addr = net->srvAddrRecv.sin_addr;
890                                         net->link = true;
891                                 } else {
892                                         // Unknown link
893                                         net->srvAddrRecv.sin_port = 0;
894                                 }
895
896                                 // Return write ack
897                                 if (net->link) {
898                                         ce_send_write_ack(net);
899                                 }
900                                 break;
901                         }
902                         // LW: is it really intended to fall thru in case of net->link != 0 ?
903                 case EDBG_CMD_WRITE:
904                         // Fix data len
905                         bin->dataLen = net->dataLen - 4;
906
907                         // Parse next block of .bin file
908                         ret = ce_parse_bin(bin);
909
910                         // Request next block
911                         if (ret != CE_PR_ERROR) {
912                                 net->blockNum++;
913
914                                 ce_send_write_ack(net);
915                         }
916                         break;
917                 case EDBG_CMD_READ_REQ:
918                         // Read requests are not supported
919                         // Do nothing ...
920                         break;
921                 case EDBG_CMD_ERROR:
922                         // Error condition on the host side
923                         diag_printf("Error: unknown error on the host side\n");
924
925                         bin->binLen = 0;
926                         ret = CE_PR_ERROR;
927                         break;
928                 }
929         }
930
931         return ret;
932 }
933
934 void ce_process_edbg(ce_net *net, ce_bin *bin)
935 {
936         eth_dbg_hdr *header;
937
938         if (net->dataLen < sizeof(eth_dbg_hdr)) {
939                 // Bad packet
940
941                 net->srvAddrRecv.sin_port = 0;
942                 return;
943         }
944
945         header = (eth_dbg_hdr*)net->data;
946
947         if (header->id != EDBG_ID) {
948                 // Bad packet
949
950                 net->srvAddrRecv.sin_port = 0;
951                 return;
952         }
953
954         if (header->service != EDBG_SVC_ADMIN) {
955                 // Unknown service
956
957                 return;
958         }
959
960         if (!net->link) {
961                 // Some diag output
962
963                 if (net->verbose) {
964                         diag_printf("Locked Down EDBG service link, IP: %s, port: %d\n",
965                                 inet_ntoa((in_addr_t *)&net->srvAddrRecv),
966                                 net->srvAddrRecv.sin_port);
967                 }
968
969                 // Lock down EDBG link
970
971                 net->srvAddrSend.sin_port = net->srvAddrRecv.sin_port;
972                 net->link = true;
973         }
974
975         switch (header->cmd) {
976         case EDBG_CMD_JUMPIMG:
977                 net->gotJumpingRequest = true;
978
979                 if (net->verbose) {
980                         diag_printf("Received JUMPING command\n");
981                 }
982                 // Just pass through and copy CONFIG structure
983         case EDBG_CMD_OS_CONFIG:
984                 // Copy config structure
985                 memcpy(&bin->edbgConfig, header->data, sizeof(edbg_os_config_data));
986                 if (net->verbose) {
987                         diag_printf("Received CONFIG command\n");
988                         if (bin->edbgConfig.flags & EDBG_FL_DBGMSG) {
989                                 diag_printf("--> Enabling DBGMSG service, IP: %d.%d.%d.%d, port: %d\n",
990                                         (bin->edbgConfig.dbgMsgIPAddr >> 0) & 0xFF,
991                                         (bin->edbgConfig.dbgMsgIPAddr >> 8) & 0xFF,
992                                         (bin->edbgConfig.dbgMsgIPAddr >> 16) & 0xFF,
993                                         (bin->edbgConfig.dbgMsgIPAddr >> 24) & 0xFF,
994                                         (int)bin->edbgConfig.dbgMsgPort);
995                         }
996                         if (bin->edbgConfig.flags & EDBG_FL_PPSH) {
997                                 diag_printf("--> Enabling PPSH service, IP: %d.%d.%d.%d, port: %d\n",
998                                         (bin->edbgConfig.ppshIPAddr >> 0) & 0xFF,
999                                         (bin->edbgConfig.ppshIPAddr >> 8) & 0xFF,
1000                                         (bin->edbgConfig.ppshIPAddr >> 16) & 0xFF,
1001                                         (bin->edbgConfig.ppshIPAddr >> 24) & 0xFF,
1002                                         (int)bin->edbgConfig.ppshPort);
1003                         }
1004                         if (bin->edbgConfig.flags & EDBG_FL_KDBG) {
1005                                 diag_printf("--> Enabling KDBG service, IP: %d.%d.%d.%d, port: %d\n",
1006                                         (bin->edbgConfig.kdbgIPAddr >> 0) & 0xFF,
1007                                         (bin->edbgConfig.kdbgIPAddr >> 8) & 0xFF,
1008                                         (bin->edbgConfig.kdbgIPAddr >> 16) & 0xFF,
1009                                         (bin->edbgConfig.kdbgIPAddr >> 24) & 0xFF,
1010                                         (int)bin->edbgConfig.kdbgPort);
1011                         }
1012                         if (bin->edbgConfig.flags & EDBG_FL_CLEANBOOT) {
1013                                 diag_printf("--> Force clean boot\n");
1014                         }
1015                 }
1016                 break;
1017         default:
1018                 if (net->verbose) {
1019                         diag_printf("Received unknown command: %08X\n", header->cmd);
1020                 }
1021                 return;
1022         }
1023
1024         // Respond with ack
1025         header->flags = EDBG_FL_FROM_DEV | EDBG_FL_ACK;
1026         net->dataLen = EDBG_DATA_OFFSET;
1027
1028         ce_send_frame(net);
1029 }
1030 #endif
1031