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