unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / hal / common / v2_0 / src / hal_if.c
1 //=============================================================================
2 //
3 //              hal_if.c
4 //
5 //              ROM/RAM interfacing functions
6 //
7 //=============================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2003 Gary Thomas
13 // Copyright (C) 2003 Nick Garnett <nickg@calivar.com>
14 // Copyright (C) 2003 Jonathan Larmour <jlarmour@eCosCentric.com>
15 //
16 // eCos is free software; you can redistribute it and/or modify it under
17 // the terms of the GNU General Public License as published by the Free
18 // Software Foundation; either version 2 or (at your option) any later version.
19 //
20 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
21 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 // for more details.
24 //
25 // You should have received a copy of the GNU General Public License along
26 // with eCos; if not, write to the Free Software Foundation, Inc.,
27 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 //
29 // As a special exception, if other files instantiate templates or use macros
30 // or inline functions from this file, or you compile this file and link it
31 // with other works to produce a work based on this file, this file does not
32 // by itself cause the resulting work to be covered by the GNU General Public
33 // License. However the source code for this file must still be made available
34 // in accordance with section (3) of the GNU General Public License.
35 //
36 // This exception does not invalidate any other reasons why a work based on
37 // this file might be covered by the GNU General Public License.
38 //
39 // Alternative licenses for eCos may be arranged by contacting the copyright
40 // holders.
41 // -------------------------------------------
42 //####ECOSGPLCOPYRIGHTEND####
43 //=============================================================================
44 //#####DESCRIPTIONBEGIN####
45 //
46 // Author(s):   jskov
47 // Contributors:jskov, woehler
48 // Date:                2000-06-07
49 //
50 //####DESCRIPTIONEND####
51 //
52 //=============================================================================
53
54 #include <pkgconf/hal.h>
55
56 #ifdef CYGPKG_KERNEL
57 # include <pkgconf/kernel.h>
58 #endif
59
60 #include <cyg/infra/cyg_ass.h>                  // assertions
61
62 #include <cyg/hal/hal_arch.h>                   // set/restore GP
63
64 #include <cyg/hal/hal_io.h>                             // IO macros
65 #include <cyg/hal/hal_if.h>                             // our interface
66
67 #include <cyg/hal/hal_diag.h>                   // Diag IO
68 #include <cyg/hal/hal_misc.h>                   // User break
69
70 #include <cyg/hal/hal_stub.h>                   // stub functionality
71
72 #include <cyg/hal/hal_intr.h>                   // hal_vsr_table and others
73
74 #ifdef CYGPKG_REDBOOT
75 #include <pkgconf/redboot.h>
76 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
77 #include <redboot.h>
78 #include <flash_config.h>
79 #endif
80 #ifdef CYGOPT_REDBOOT_FIS
81 #include <fis.h>
82 #endif
83 #endif
84
85 //--------------------------------------------------------------------------
86
87 externC void patch_dbg_syscalls(void * vector);
88 externC void init_thread_syscall(void * vector);
89
90 //--------------------------------------------------------------------------
91 // Implementations and function wrappers for monitor services
92
93 // flash config state queries
94 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
95
96 static __call_if_flash_cfg_op_fn_t flash_config_op;
97
98 static cyg_bool
99 flash_config_op(int op, struct cyg_fconfig *fc)
100 {
101         cyg_bool res = false;
102
103         CYGARC_HAL_SAVE_GP();
104
105         switch (op) {
106         case CYGNUM_CALL_IF_FLASH_CFG_GET:
107                 res = flash_get_config(fc->key, fc->val, fc->type);
108                 break;
109         case CYGNUM_CALL_IF_FLASH_CFG_NEXT:
110                 res = flash_next_key(fc->key, fc->keylen, &fc->type, &fc->offset);
111                 break;
112         case CYGNUM_CALL_IF_FLASH_CFG_SET:
113                 res = flash_set_config(fc->key, fc->val, fc->type);
114                 break;
115         default:
116                 // nothing else supported yet - though it is expected that "set"
117                 // will fit the same set of arguments, potentially.
118                 break;
119         }
120
121         CYGARC_HAL_RESTORE_GP();
122         return res;
123 }
124 #endif
125
126 #ifdef CYGOPT_REDBOOT_FIS
127
128 static __call_if_flash_fis_op_fn_t flash_fis_op;
129
130 static cyg_bool
131 flash_fis_op( int op, char *name, void *val)
132 {
133         cyg_bool res = false;
134         struct fis_image_desc *fis;
135         int num;
136
137         CYGARC_HAL_SAVE_GP();
138         fis = fis_lookup(name, &num);
139         if (fis != NULL) {
140                 switch (op) {
141                 case CYGNUM_CALL_IF_FLASH_FIS_GET_FLASH_BASE:
142                         *(CYG_ADDRESS *)val = fis->flash_base;
143                         res = true;
144                         break;
145                 case CYGNUM_CALL_IF_FLASH_FIS_GET_SIZE:
146                         *(unsigned long *)val = fis->size;
147                         res = true;
148                         break;
149                 case CYGNUM_CALL_IF_FLASH_FIS_GET_MEM_BASE:
150                         *(CYG_ADDRESS *)val = fis->mem_base;
151                         res = true;
152                         break;
153                 case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY_POINT:
154                         *(CYG_ADDRESS *)val = fis->entry_point;
155                         res = true;
156                         break;
157                 case CYGNUM_CALL_IF_FLASH_FIS_GET_DATA_LENGTH:
158                         *(unsigned long *)val = fis->data_length;
159                         res = true;
160                         break;
161                 case CYGNUM_CALL_IF_FLASH_FIS_GET_DESC_CKSUM:
162                         *(unsigned long *)val = fis->desc_cksum;
163                         res = true;
164                         break;
165                 case CYGNUM_CALL_IF_FLASH_FIS_GET_FILE_CKSUM:
166                         *(unsigned long *)val = fis->file_cksum;
167                         res = true;
168                         break;
169                 }
170         }
171         CYGARC_HAL_RESTORE_GP();
172         return res;
173 }
174
175 #include <cyg/io/flash.h>
176
177 extern int __flash_init;
178 extern int fisdir_size;
179 extern int flash_block_size;
180 extern void* fis_addr;
181 #ifdef CYGOPT_REDBOOT_REDUNDANT_FIS
182 extern void* redundant_fis_addr;
183 #endif
184 extern void* fis_work_block;
185 extern int do_flash_init(void);
186 extern int fis_start_update_directory(int autolock);
187 extern int fis_update_directory(int autolock, int error);
188
189 static __call_if_flash_fis_op2_fn_t flash_fis_op2;
190
191 static int
192 flash_fis_op2( int op, unsigned int index, struct fis_table_entry *entry)
193 {
194    int res = 0;
195    CYGARC_HAL_SAVE_GP();
196    switch (op) {
197           case CYGNUM_CALL_IF_FLASH_FIS_GET_VERSION:
198                  res = CYG_REDBOOT_FIS_VERSION;
199                  break;
200           case CYGNUM_CALL_IF_FLASH_FIS_INIT:
201                  __flash_init=0;  //force reinitialization
202                  res = do_flash_init();
203                  break;
204           case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY_COUNT:
205                  res = fisdir_size / sizeof(struct fis_image_desc);
206                  break;
207           case CYGNUM_CALL_IF_FLASH_FIS_GET_ENTRY:
208                  {
209                         struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block;
210                         CYG_ASSERT(entry != NULL, "fis_table_entry == NULL!");
211                         memcpy(entry->name, img[index].u.name, 16);
212                         entry->flash_base=img[index].flash_base;
213                         entry->mem_base=img[index].mem_base;
214                         entry->size=img[index].size;
215                         entry->entry_point=img[index].entry_point;
216                         entry->data_length=img[index].data_length;
217                         entry->desc_cksum=img[index].desc_cksum;
218                         entry->file_cksum=img[index].file_cksum;
219                         res = 0;
220                  }
221                  break;
222           case CYGNUM_CALL_IF_FLASH_FIS_START_UPDATE:
223                  fis_start_update_directory(1);
224                  break;
225           case CYGNUM_CALL_IF_FLASH_FIS_FINISH_UPDATE:
226                  fis_update_directory(1, index);
227                  break;
228           case CYGNUM_CALL_IF_FLASH_FIS_MODIFY_ENTRY:
229                   res = 0;
230                   if (entry->name[0]!=0xff) {
231                           if ((entry->size == 0)
232                                   || ((entry->size % flash_block_size) !=0)
233                                   || (flash_verify_addr((void*)entry->flash_base)!=0)
234                                   || (flash_verify_addr((void*)(entry->flash_base+entry->size-1))!=0)
235                                   || (entry->size < entry->data_length))
236                                   res = -1;
237                   }
238
239                   if (res == 0) {
240                           struct fis_image_desc* img = (struct fis_image_desc *)fis_work_block;
241                           memcpy(img[index].u.name, entry->name, 16);
242                           img[index].flash_base=entry->flash_base;
243                           img[index].mem_base=entry->mem_base;
244                           img[index].size=entry->size;
245                           img[index].entry_point=entry->entry_point;
246                           img[index].data_length=entry->data_length;
247                           img[index].desc_cksum=entry->desc_cksum;
248                           img[index].file_cksum=entry->file_cksum;
249                  }
250                  break;
251    }
252    CYGARC_HAL_RESTORE_GP();
253    return res;
254 }
255 #endif
256
257 //----------------------------
258 // Delay uS
259 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DELAY_US
260
261 static __call_if_delay_us_t delay_us;
262
263 static void
264 delay_us(cyg_int32 usecs)
265 {
266         CYGARC_HAL_SAVE_GP();
267 #ifdef CYGPKG_KERNEL
268         {
269                 cyg_int32 start, elapsed, elapsed_usec;
270                 cyg_int32 slice;
271                 cyg_int32 usec_per_period = CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR/1000;
272                 cyg_int32 ticks_per_usec = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/usec_per_period;
273
274                 do {
275                         // Spin in slices of 1/2 the RTC period. Allows interrupts
276                         // time to run without messing up the algorithm. If we
277                         // spun for 1 period (or more) of the RTC, there would also
278                         // be problems figuring out when the timer wrapped.      We
279                         // may lose a tick or two for each cycle but it shouldn't
280                         // matter much.
281
282                         // The tests against CYGNUM_KERNEL_COUNTERS_RTC_PERIOD
283                         // check for a value that would cause a 32 bit signed
284                         // multiply to overflow. But this also implies that just
285                         // multiplying by ticks_per_usec will yield a good
286                         // approximation.  Otherwise we need to do the full
287                         // multiply+divide to get sufficient accuracy. Note that
288                         // this test is actually constant, so the compiler will
289                         // eliminate it and only compile the branch that is
290                         // selected.
291
292                         if( usecs > usec_per_period/2 )
293                                 slice = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/2;
294                         else if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD/2 >= 0x7FFFFFFF/usec_per_period )
295                                 slice = usecs * ticks_per_usec;
296                         else
297                         {
298                                 slice = usecs*CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
299                                 slice /= usec_per_period;
300                         }
301
302                         HAL_CLOCK_READ(&start);
303                         do {
304                                 HAL_CLOCK_READ(&elapsed);
305                                 elapsed = (elapsed - start); // counts up!
306                                 if (elapsed < 0)
307                                         elapsed += CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
308                         } while (elapsed < slice);
309
310                         // Adjust by elapsed, not slice, since an interrupt may
311                         // have been stalling us for some time.
312
313                         if( CYGNUM_KERNEL_COUNTERS_RTC_PERIOD >= 0x7FFFFFFF/usec_per_period )
314                                 elapsed_usec = elapsed / ticks_per_usec;
315                         else
316                         {
317                                 elapsed_usec = elapsed * usec_per_period;
318                                 elapsed_usec = elapsed_usec / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
319                         }
320
321                         // It is possible for elapsed_usec to end up zero in some
322                         // circumstances and we could end up looping indefinitely.
323                         // Avoid that by ensuring that we always decrement usec by
324                         // at least 1 each time.
325
326                         usecs -= elapsed_usec ? elapsed_usec : 1;
327
328                 } while (usecs > 0);
329         }
330 #else // CYGPKG_KERNEL
331 #ifdef HAL_DELAY_US
332         // Use a HAL feature if defined
333         HAL_DELAY_US(usecs);
334 #else
335         // If no accurate delay mechanism, just spin for a while. Having
336         // an inaccurate delay is much better than no delay at all. The
337         // count of 10 should mean the loop takes something resembling
338         // 1us on most CPUs running between 30-100MHz [depends on how many
339         // instructions this compiles to, how many dispatch units can be
340         // used for the simple loop, actual CPU frequency, etc]
341         while (usecs-- > 0) {
342                 int i;
343                 for (i = 0; i < 10; i++);
344         }
345 #endif // HAL_DELAY_US
346 #endif // CYGPKG_KERNEL
347         CYGARC_HAL_RESTORE_GP();
348 }
349 #endif // CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DELAY_US
350
351 // Reset functions
352 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_RESET
353
354 static __call_if_reset_t reset;
355
356 static void
357 reset(void)
358 {
359         CYGARC_HAL_SAVE_GP();
360         // With luck, the platform defines some magic that will cause a hardware
361         // reset.
362 #ifdef HAL_PLATFORM_RESET
363         HAL_PLATFORM_RESET();
364 #endif
365
366 #ifdef HAL_PLATFORM_RESET_ENTRY
367         // If that's not the case (above is an empty statement) there may
368         // be defined an address we can jump to - and effectively
369         // reinitialize the system. Not quite as good as a reset, but it
370         // is often enough.
371         goto *HAL_PLATFORM_RESET_ENTRY;
372
373 #else
374 #error " no RESET_ENTRY"
375 #endif
376         CYG_FAIL("Reset failed");
377         CYGARC_HAL_RESTORE_GP();
378 }
379
380 #endif
381
382 //------------------------------------
383 // NOP service
384 #if defined(CYGSEM_HAL_VIRTUAL_VECTOR_INIT_WHOLE_TABLE) || \
385         defined(CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_COMMS)
386 static int
387 nop_service(void)
388 {
389         // This is the default service. It always returns false (0), and
390         // _does not_ trigger any assertions. Clients must either cope
391         // with the service failure or assert.
392         return 0;
393 }
394 #endif
395
396 //----------------------------------
397 // Comm controls
398 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_COMMS
399
400 #ifdef CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS
401 #define CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS \
402   (CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS+CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS)
403 #else
404 #define CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS \
405   CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
406 #endif
407
408 static hal_virtual_comm_table_t comm_channels[CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS+1];
409
410 static int
411 set_debug_comm(int __comm_id)
412 {
413         static int __selected_id = CYGNUM_CALL_IF_SET_COMM_ID_EMPTY;
414         hal_virtual_comm_table_t* __chan;
415         int interrupt_state = 0;
416         int res = 1, update = 0;
417         CYGARC_HAL_SAVE_GP();
418
419         CYG_ASSERT(__comm_id >= CYGNUM_CALL_IF_SET_COMM_ID_MANGLER
420                            && __comm_id < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS,
421                            "Invalid channel");
422
423         switch (__comm_id) {
424         case CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT:
425                 if (__selected_id > 0)
426                         res = __selected_id-1;
427                 else if (__selected_id == 0)
428                         res = CYGNUM_CALL_IF_SET_COMM_ID_MANGLER;
429                 else
430                         res = __selected_id;
431                 break;
432
433         case CYGNUM_CALL_IF_SET_COMM_ID_EMPTY:
434                 CYGACC_CALL_IF_DEBUG_PROCS_SET(0);
435                 __selected_id = __comm_id;
436                 break;
437
438         case CYGNUM_CALL_IF_SET_COMM_ID_MANGLER:
439                 __comm_id = 0;
440                 update = 1;
441                 break;
442
443         default:
444                 __comm_id++;                                    // skip mangler entry
445                 update = 1;
446                 break;
447         }
448
449         if (update) {
450                 // Find the interrupt state of the channel.
451                 __chan = CYGACC_CALL_IF_DEBUG_PROCS();
452                 if (__chan)
453                         interrupt_state = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE);
454
455                 __selected_id = __comm_id;
456                 CYGACC_CALL_IF_DEBUG_PROCS_SET(comm_channels[__comm_id]);
457
458                 // Set interrupt state on the new channel.
459                 __chan = CYGACC_CALL_IF_DEBUG_PROCS();
460                 if (interrupt_state)
461                         CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_ENABLE);
462                 else
463                         CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE);
464         }
465
466         CYGARC_HAL_RESTORE_GP();
467         return res;
468 }
469
470 static int
471 set_console_comm(int __comm_id)
472 {
473         static int __selected_id = CYGNUM_CALL_IF_SET_COMM_ID_EMPTY;
474         int res = 1, update = 0;
475         CYGARC_HAL_SAVE_GP();
476
477         CYG_ASSERT(__comm_id >= CYGNUM_CALL_IF_SET_COMM_ID_MANGLER
478                            && __comm_id < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS,
479                            "Invalid channel");
480
481         switch (__comm_id) {
482         case CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT:
483                 if (__selected_id > 0)
484                         res = __selected_id-1;
485                 else if (__selected_id == 0)
486                         res = CYGNUM_CALL_IF_SET_COMM_ID_MANGLER;
487                 else
488                         res = __selected_id;
489                 break;
490
491         case CYGNUM_CALL_IF_SET_COMM_ID_EMPTY:
492                 CYGACC_CALL_IF_CONSOLE_PROCS_SET(0);
493                 __selected_id = __comm_id;
494                 break;
495
496         case CYGNUM_CALL_IF_SET_COMM_ID_MANGLER:
497                 __comm_id = 0;
498                 update = 1;
499                 break;
500
501         default:
502                 __comm_id++;                                    // skip mangler entry
503                 update = 1;
504                 break;
505         }
506
507         if (update) {
508                 __selected_id = __comm_id;
509
510                 CYGACC_CALL_IF_CONSOLE_PROCS_SET(comm_channels[__comm_id]);
511         }
512
513         CYGARC_HAL_RESTORE_GP();
514         return res;
515 }
516 #endif
517
518 //----------------------------------
519 // Cache functions
520 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_CACHE
521
522 static void
523 flush_icache(void *__p, int __nbytes)
524 {
525         CYGARC_HAL_SAVE_GP();
526 #ifdef HAL_ICACHE_FLUSH
527         HAL_ICACHE_FLUSH( __p , __nbytes );
528 #elif defined(HAL_ICACHE_INVALIDATE)
529         HAL_ICACHE_INVALIDATE();
530 #endif
531         CYGARC_HAL_RESTORE_GP();
532 }
533
534 static void
535 flush_dcache(void *__p, int __nbytes)
536 {
537         CYGARC_HAL_SAVE_GP();
538 #ifdef HAL_DCACHE_FLUSH
539         HAL_DCACHE_FLUSH( __p , __nbytes );
540 #elif defined(HAL_DCACHE_INVALIDATE)
541         HAL_DCACHE_INVALIDATE();
542 #endif
543         CYGARC_HAL_RESTORE_GP();
544 }
545 #endif
546
547 #if defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG)
548 //-----------------------------------------------------------------------------
549 // GDB console output mangler (O-packetizer)
550 // COMMS init function at end.
551
552 // This gets called via the virtual vector console comms entry and
553 // handles O-packetization. The debug comms entries are used for the
554 // actual device IO.
555 static cyg_uint8
556 cyg_hal_diag_mangler_gdb_getc(void* __ch_data)
557 {
558         cyg_uint8 __ch;
559         hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
560         CYGARC_HAL_SAVE_GP();
561
562         __ch = CYGACC_COMM_IF_GETC(*__chan);
563
564         CYGARC_HAL_RESTORE_GP();
565
566         return __ch;
567 }
568
569 static char __mangler_line[100];
570 static int      __mangler_pos = 0;
571
572 static void
573 cyg_hal_diag_mangler_gdb_flush(void* __ch_data)
574 {
575         CYG_INTERRUPT_STATE old;
576         hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
577 #if CYGNUM_HAL_DEBUG_GDB_PROTOCOL_RETRIES != 0
578         int tries = CYGNUM_HAL_DEBUG_GDB_PROTOCOL_RETRIES;
579 #endif
580
581
582         // Nothing to do if mangler buffer is empty.
583         if (__mangler_pos == 0)
584                 return;
585
586         // Disable interrupts. This prevents GDB trying to interrupt us
587         // while we are in the middle of sending a packet. The serial
588         // receive interrupt will be seen when we re-enable interrupts
589         // later.
590 #if defined(CYG_HAL_STARTUP_ROM) \
591         || !defined(CYG_HAL_GDB_ENTER_CRITICAL_IO_REGION)
592         HAL_DISABLE_INTERRUPTS(old);
593 #else
594         CYG_HAL_GDB_ENTER_CRITICAL_IO_REGION(old);
595 #endif
596
597 #if CYGNUM_HAL_DEBUG_GDB_PROTOCOL_RETRIES != 0
598         // Only wait 500ms for data to arrive - avoid "stuck" connections
599         CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_SET_TIMEOUT, CYGNUM_HAL_DEBUG_GDB_PROTOCOL_TIMEOUT);
600 #endif
601
602         while(1)
603         {
604         static const char hex[] = "0123456789ABCDEF";
605         cyg_uint8 csum = 0;
606         char c1;
607         int i;
608
609         CYGACC_COMM_IF_PUTC(*__chan, '$');
610         CYGACC_COMM_IF_PUTC(*__chan, 'O');
611         csum += 'O';
612         for( i = 0; i < __mangler_pos; i++ )
613                 {
614                 char ch = __mangler_line[i];
615                 char h = hex[(ch>>4)&0xF];
616                 char l = hex[ch&0xF];
617                 CYGACC_COMM_IF_PUTC(*__chan, h);
618                 CYGACC_COMM_IF_PUTC(*__chan, l);
619                 csum += h;
620                 csum += l;
621         }
622         CYGACC_COMM_IF_PUTC(*__chan, '#');
623         CYGACC_COMM_IF_PUTC(*__chan, hex[(csum>>4)&0xF]);
624         CYGACC_COMM_IF_PUTC(*__chan, hex[csum&0xF]);
625
626         nak:
627 #if CYGNUM_HAL_DEBUG_GDB_PROTOCOL_RETRIES != 0
628         if (CYGACC_COMM_IF_GETC_TIMEOUT(*__chan, &c1) == 0) {
629                 c1 = '-';
630                 if (tries && (--tries == 0)) c1 = '+';
631         }
632 #else
633         c1 = CYGACC_COMM_IF_GETC(*__chan);
634 #endif
635
636         if( c1 == '+' ) break;
637
638         if( cyg_hal_is_break( &c1 , 1 ) ) {
639                 // Caller's responsibility to react on this.
640                 CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(1);
641                 break;
642         }
643         if( c1 != '-' ) goto nak;
644         }
645
646         __mangler_pos = 0;
647         // And re-enable interrupts
648 #if defined(CYG_HAL_STARTUP_ROM) \
649         || !defined(CYG_HAL_GDB_ENTER_CRITICAL_IO_REGION)
650         HAL_RESTORE_INTERRUPTS(old);
651 #else
652         CYG_HAL_GDB_LEAVE_CRITICAL_IO_REGION(old);
653 #endif
654 }
655
656 static void
657 cyg_hal_diag_mangler_gdb_putc(void* __ch_data, cyg_uint8 c)
658 {
659         // No need to send CRs
660         if( c == '\r' ) return;
661
662         CYGARC_HAL_SAVE_GP();
663
664         __mangler_line[__mangler_pos++] = c;
665
666         if( c == '\n' || __mangler_pos == sizeof(__mangler_line) )
667         cyg_hal_diag_mangler_gdb_flush(__ch_data);
668
669         CYGARC_HAL_RESTORE_GP();
670 }
671
672 static void
673 cyg_hal_diag_mangler_gdb_write(void* __ch_data,
674                                                            const cyg_uint8* __buf, cyg_uint32 __len)
675 {
676         CYGARC_HAL_SAVE_GP();
677
678         while(__len-- > 0)
679                 cyg_hal_diag_mangler_gdb_putc(__ch_data, *__buf++);
680
681         CYGARC_HAL_RESTORE_GP();
682 }
683
684 static void
685 cyg_hal_diag_mangler_gdb_read(void* __ch_data,
686                                                           cyg_uint8* __buf, cyg_uint32 __len)
687 {
688         CYGARC_HAL_SAVE_GP();
689
690         while(__len-- > 0)
691                 *__buf++ = cyg_hal_diag_mangler_gdb_getc(__ch_data);
692
693         CYGARC_HAL_RESTORE_GP();
694 }
695
696 static int
697 cyg_hal_diag_mangler_gdb_control(void *__ch_data,
698                                                                  __comm_control_cmd_t __func, ...)
699 {
700         CYGARC_HAL_SAVE_GP();
701
702         if (__func == __COMMCTL_FLUSH_OUTPUT)
703         cyg_hal_diag_mangler_gdb_flush(__ch_data);
704
705         CYGARC_HAL_RESTORE_GP();
706         return 0;
707 }
708
709 // This is the COMMS init function. It gets called both by the stubs
710 // and diag init code to initialize the COMMS mangler channel table -
711 // that's all. The callers have to decide whether to actually use this
712 // channel.
713 void
714 cyg_hal_diag_mangler_gdb_init(void)
715 {
716         hal_virtual_comm_table_t* comm;
717         int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
718
719         // Initialize mangler procs
720         CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_MANGLER);
721         comm = CYGACC_CALL_IF_CONSOLE_PROCS();
722         CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_diag_mangler_gdb_write);
723         CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_diag_mangler_gdb_read);
724         CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_diag_mangler_gdb_putc);
725         CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_diag_mangler_gdb_getc);
726         CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_diag_mangler_gdb_control);
727
728         // Restore the original console channel.
729         CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
730 }
731
732 //-----------------------------------------------------------------------------
733 // Null console output mangler
734 // COMMS init function at end.
735
736 // This gets called via the virtual vector console comms entry and
737 // just forwards IO to the debug comms entries.
738 // This differs from setting the console channel to the same as the
739 // debug channel in that console output will go to the debug channel
740 // even if the debug channel is changed.
741 static cyg_uint8
742 cyg_hal_diag_mangler_null_getc(void* __ch_data)
743 {
744         cyg_uint8 __ch;
745         hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
746         CYGARC_HAL_SAVE_GP();
747
748         __ch = CYGACC_COMM_IF_GETC(*__chan);
749
750         CYGARC_HAL_RESTORE_GP();
751
752         return __ch;
753 }
754
755
756 static void
757 cyg_hal_diag_mangler_null_putc(void* __ch_data, cyg_uint8 c)
758 {
759         hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
760
761         CYGARC_HAL_SAVE_GP();
762
763         CYGACC_COMM_IF_PUTC(*__chan, c);
764
765         CYGARC_HAL_RESTORE_GP();
766 }
767
768 static void
769 cyg_hal_diag_mangler_null_write(void* __ch_data,
770                                                                 const cyg_uint8* __buf, cyg_uint32 __len)
771 {
772         CYGARC_HAL_SAVE_GP();
773
774         while(__len-- > 0)
775                 cyg_hal_diag_mangler_null_putc(__ch_data, *__buf++);
776
777         CYGARC_HAL_RESTORE_GP();
778 }
779
780 static void
781 cyg_hal_diag_mangler_null_read(void* __ch_data,
782                                                            cyg_uint8* __buf, cyg_uint32 __len)
783 {
784         CYGARC_HAL_SAVE_GP();
785
786         while(__len-- > 0)
787                 *__buf++ = cyg_hal_diag_mangler_null_getc(__ch_data);
788
789         CYGARC_HAL_RESTORE_GP();
790 }
791
792 static int
793 cyg_hal_diag_mangler_null_control(void *__ch_data,
794                                                                   __comm_control_cmd_t __func, ...)
795 {
796         // Do nothing (yet).
797         return 0;
798 }
799
800 // This is the COMMS init function. It gets called both by the stubs
801 // and diag init code to initialize the COMMS mangler channel table -
802 // that's all. The callers have to decide whether to actually use this
803 // channel.
804 void
805 cyg_hal_diag_mangler_null_init(void)
806 {
807         hal_virtual_comm_table_t* comm;
808         int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
809
810         // Initialize mangler procs
811         CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_MANGLER);
812         comm = CYGACC_CALL_IF_CONSOLE_PROCS();
813         CYGACC_COMM_IF_WRITE_SET(*comm, cyg_hal_diag_mangler_null_write);
814         CYGACC_COMM_IF_READ_SET(*comm, cyg_hal_diag_mangler_null_read);
815         CYGACC_COMM_IF_PUTC_SET(*comm, cyg_hal_diag_mangler_null_putc);
816         CYGACC_COMM_IF_GETC_SET(*comm, cyg_hal_diag_mangler_null_getc);
817         CYGACC_COMM_IF_CONTROL_SET(*comm, cyg_hal_diag_mangler_null_control);
818
819         // Restore the original console channel.
820         CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
821 }
822
823 //-----------------------------------------------------------------------------
824 // Console IO functions that adhere to the virtual vector table semantics in
825 // order to ensure proper debug agent mangling when required.
826 //
827 externC void cyg_hal_plf_comms_init(void);
828
829 void
830 hal_if_diag_init(void)
831 {
832         // This function may be called from various places and the code
833         // should only run once.
834         static cyg_uint8 called = 0;
835         if (called) return;
836         called = 1;
837
838 #ifndef CYGSEM_HAL_VIRTUAL_VECTOR_INHERIT_CONSOLE
839
840 #if defined(CYGDBG_HAL_DIAG_TO_DEBUG_CHAN)
841         // Use the mangler channel, which in turn uses the debug channel.
842         CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_MANGLER);
843
844         // Initialize the mangler channel.
845 #if defined(CYGSEM_HAL_DIAG_MANGLER_GDB)
846         cyg_hal_diag_mangler_gdb_init();
847 #elif defined(CYGSEM_HAL_DIAG_MANGLER_None)
848         cyg_hal_diag_mangler_null_init();
849 #endif
850
851 #else // CYGDBG_HAL_DIAG_TO_DEBUG_CHAN
852
853         // Use an actual (raw) IO channel
854         CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL);
855
856 #endif // CYGDBG_HAL_DIAG_TO_DEBUG_CHAN
857
858 #endif // CYGSEM_HAL_VIRTUAL_VECTOR_INHERIT_CONSOLE
859 }
860
861 void
862 hal_if_diag_write_char(char c)
863 {
864         hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
865
866         if (__chan)
867                 CYGACC_COMM_IF_PUTC(*__chan, c);
868         else {
869                 __chan = CYGACC_CALL_IF_DEBUG_PROCS();
870
871                 // FIXME: What should be done if assertions are not enabled?
872                 // This is a bad bad situation - we have no means for diag
873                 // output; we want to hit a breakpoint to alert the developer
874                 // or something like that.
875                 CYG_ASSERT(__chan, "No valid channel set");
876
877                 CYGACC_COMM_IF_PUTC(*__chan, c);
878         }
879
880         // Check interrupt flag
881         if (CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG()) {
882                 CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(0);
883                 cyg_hal_user_break(0);
884         }
885 }
886
887 void
888 hal_if_diag_read_char(char *c)
889 {
890         hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
891
892         if (__chan)
893                 *c = CYGACC_COMM_IF_GETC(*__chan);
894         else {
895                 __chan = CYGACC_CALL_IF_DEBUG_PROCS();
896
897                 // FIXME: What should be done if assertions are not enabled?
898                 // This is a bad bad situation - we have no means for diag
899                 // output; we want to hit a breakpoint to alert the developer
900                 // or something like that.
901                 CYG_ASSERT(__chan, "No valid channel set");
902
903                 *c = CYGACC_COMM_IF_GETC(*__chan);
904         }
905 }
906 #endif // CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
907
908 //=============================================================================
909 // CtrlC support
910 //=============================================================================
911
912 #if defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT) \
913         || defined(CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT)
914
915 struct Hal_SavedRegisters *hal_saved_interrupt_state;
916
917 void
918 hal_ctrlc_isr_init(void)
919 {
920         // A ROM monitor never enables the interrupt itself. This is left
921         // to the (RAM) application.
922 #ifndef CYGSEM_HAL_ROM_MONITOR
923         hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
924
925 #if 1 // Prevents crash on older stubs
926         int v_m;
927         // Allow only ctrl-c interrupt enabling when version in table is
928         // below legal max and above the necessary service, and _not_
929         // the value we set it to below.
930         v_m = CYGACC_CALL_IF_VERSION() & CYGNUM_CALL_IF_TABLE_VERSION_CALL_MASK;
931         if (v_m >= CYGNUM_CALL_IF_TABLE_VERSION_CALL_MAX
932                 || v_m < CYGNUM_CALL_IF_SET_DEBUG_COMM
933                 || v_m == CYGNUM_CALL_IF_TABLE_VERSION_CALL_HACK)
934                 return;
935
936         // Now trash that value - otherwise downloading an image with
937         // builtin stubs on a board with older stubs (which will cause the
938         // version to be set to VERSION_CALL) may cause all subsequent
939         // runs to (wrongly) fall through to the below code.  If there is
940         // a new stub on the board, it will reinitialize the version field
941         // on reset.  Yes, this is a gross hack!
942         CYGACC_CALL_IF_VERSION_SET(CYGNUM_CALL_IF_TABLE_VERSION_CALL_HACK);
943 #endif
944
945         // We can only enable interrupts on a valid debug channel.
946         if (__chan)
947                 CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_ENABLE);
948 #endif
949 }
950
951 cyg_uint32
952 hal_ctrlc_isr(CYG_ADDRWORD vector, CYG_ADDRWORD data)
953 {
954         hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
955         int isr_ret = 0, ctrlc = 0;
956
957         if (__chan) {
958                 isr_ret = CYGACC_COMM_IF_DBG_ISR(*__chan, &ctrlc, vector, data);
959                 if (ctrlc)
960                         cyg_hal_user_break( (CYG_ADDRWORD *)hal_saved_interrupt_state );
961         }
962         return isr_ret;
963 }
964
965 cyg_bool
966 hal_ctrlc_check(CYG_ADDRWORD vector, CYG_ADDRWORD data)
967 {
968         hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_DEBUG_PROCS();
969         int gdb_vector = vector-1;
970         int isr_ret, ctrlc = 0;
971
972         // This check only to avoid crash on older stubs in case of unhandled
973         // interrupts. It is a bit messy, but required in a transition period.
974         if (__chan &&
975                 (CYGNUM_CALL_IF_TABLE_VERSION_CALL_HACK ==
976                  (CYGACC_CALL_IF_VERSION() & CYGNUM_CALL_IF_TABLE_VERSION_CALL_MASK))){
977                 gdb_vector = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_DBG_ISR_VECTOR);
978         }
979         if (vector == gdb_vector) {
980                 isr_ret = CYGACC_COMM_IF_DBG_ISR(*__chan, &ctrlc, vector, data);
981                 if (ctrlc) {
982                         cyg_hal_user_break( (CYG_ADDRWORD *)hal_saved_interrupt_state );
983                         return true;
984                 }
985         }
986         return false;
987 }
988 #endif // CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT || CYGDBG_HAL_DEBUG_GDB_CTRLC_SUPPORT
989
990 //--------------------------------------------------------------------------
991 // Init function. It should be called from the platform initialization code.
992 // For monitor configurations it will initialize the calling interface table,
993 // for client configurations it will patch the existing table as per
994 // configuration.
995 void
996 hal_if_init(void)
997 {
998         //**********************************************************************
999         //
1000         // Note that if your RAM application is configured to initialize
1001         // the whole table _or_ the communication channels, you _cannot_
1002         // step through this function with the debugger. If your channel
1003         // configurations are set to the default, you should be able to
1004         // simply step over this function though (or use 'finish' once you
1005         // have entered this function if that GDB command works).
1006         //
1007         // If you really do need to debug this code, the best approach is
1008         // to have a working RedBoot / GDB stub in ROM and then change the
1009         // hal_virtual_vector_table to reside at some other address in the
1010         // RAM configuration than that used by the ROM monitor. Then
1011         // you'll be able to use the ROM monitor to debug the below code
1012         // and check that it does the right thing.
1013         //
1014         // Note that if you have a ROM monitor in ROM/flash which does
1015         // support virtual vectors, you should be able to disable the
1016         // option CYGSEM_HAL_VIRTUAL_VECTOR_INIT_WHOLE_TABLE. On some
1017         // targets (which predate the introduction of virtual vectors)
1018         // that option is enabled per default and needs to be explicitly
1019         // disabled when you have an updated ROM monitor.
1020         //
1021         //**********************************************************************
1022
1023 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_INIT_WHOLE_TABLE
1024         {
1025                 int i;
1026
1027                 // Initialize tables with the NOP service.
1028                 // This should only be done for service routine entries - data
1029                 // pointers should be NULLed.
1030                 for (i = 0; i < CYGNUM_CALL_IF_TABLE_SIZE; i++)
1031                         hal_virtual_vector_table[i] = (CYG_ADDRWORD) &nop_service;
1032
1033                 // Version number
1034                 CYGACC_CALL_IF_VERSION_SET(CYGNUM_CALL_IF_TABLE_VERSION_CALL
1035                         |((CYG_ADDRWORD)CYGNUM_CALL_IF_TABLE_VERSION_COMM<<CYGNUM_CALL_IF_TABLE_VERSION_COMM_shift));
1036         }
1037 #endif
1038
1039         // Miscellaneous services with wrappers in this file.
1040 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_RESET
1041         CYGACC_CALL_IF_RESET_SET(reset);
1042 #endif
1043 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DELAY_US
1044         CYGACC_CALL_IF_DELAY_US_SET(delay_us);
1045 #endif
1046
1047 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_CACHE
1048         // Cache functions
1049         CYGACC_CALL_IF_FLUSH_ICACHE_SET(flush_icache);
1050         CYGACC_CALL_IF_FLUSH_DCACHE_SET(flush_dcache);
1051 #endif
1052
1053 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
1054         CYGACC_CALL_IF_FLASH_CFG_OP_SET(flash_config_op);
1055 #endif
1056
1057 #ifdef CYGOPT_REDBOOT_FIS
1058         CYGACC_CALL_IF_FLASH_FIS_OP_SET(flash_fis_op);
1059         CYGACC_CALL_IF_FLASH_FIS_OP2_SET(flash_fis_op2);
1060 #endif
1061
1062         // Data entries not currently supported in eCos
1063 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_DATA
1064         CYGACC_CALL_IF_DBG_DATA_SET(0);
1065 #endif
1066
1067 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_VERSION
1068         CYGACC_CALL_IF_MONITOR_VERSION_SET(0);
1069 #endif
1070
1071         // Comm controls
1072 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_COMMS
1073         {
1074                 int i, j;
1075
1076                 // Clear out tables with safe dummy function.
1077                 for (j = 0; j < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS+1; j++)
1078                         for (i = 0; i < CYGNUM_COMM_IF_TABLE_SIZE; i++)
1079                                 comm_channels[j][i] = (CYG_ADDRWORD) &nop_service;
1080
1081                 // Set accessor functions
1082                 CYGACC_CALL_IF_SET_DEBUG_COMM_SET(set_debug_comm);
1083                 CYGACC_CALL_IF_SET_CONSOLE_COMM_SET(set_console_comm);
1084
1085                 // Initialize console/debug procs. Note that these _must_
1086                 // be set to empty before the comms init call.
1087                 set_debug_comm(CYGNUM_CALL_IF_SET_COMM_ID_EMPTY);
1088                 set_console_comm(CYGNUM_CALL_IF_SET_COMM_ID_EMPTY);
1089
1090                 // Initialize channels. This used to be done in
1091                 // hal_diag_init() and the stub initHardware() functions, but
1092                 // it makes more sense to have here.
1093                 cyg_hal_plf_comms_init();
1094
1095                 // Always set the debug channel. If stubs are included, it is
1096                 // necessary. If no stubs are included it does not hurt and is
1097                 // likely to be required by the hal_if_diag_init code anyway
1098                 // as it may rely on it if using a mangler.
1099                 set_debug_comm(CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL);
1100                 // Set console channel to a safe default. hal_if_diag_init
1101                 // will override with console channel or mangler if necessary.
1102                 set_console_comm(CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL);
1103         }
1104
1105         // Reset console interrupt flag.
1106         CYGACC_CALL_IF_CONSOLE_INTERRUPT_FLAG_SET(0);
1107 #endif
1108
1109         // Set up services provided by clients
1110 #if defined(CYGFUN_HAL_COMMON_KERNEL_SUPPORT)   &&      \
1111         ( defined(CYGSEM_HAL_USE_ROM_MONITOR_GDB_stubs) \
1112           || defined(CYGSEM_HAL_USE_ROM_MONITOR_CygMon))
1113
1114         patch_dbg_syscalls( (void *)(hal_virtual_vector_table) );
1115 #endif
1116
1117         // Init client services
1118 #if !defined(CYGPKG_KERNEL) && defined(CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT)
1119         // Only include this code if we do not have a kernel. Otherwise
1120         // the kernel supplies the functionality for the app we are linked
1121         // with.
1122
1123         // Prepare for application installation of thread info function in
1124         // vector table.
1125         init_thread_syscall( (void *)&hal_virtual_vector_table[CYGNUM_CALL_IF_DBG_SYSCALL] );
1126 #endif
1127
1128         // Finally, install async breakpoint handler if it is configured in.
1129         // FIXME: this should probably check for STUBS instead (but code is
1130         //                conditional on BREAK for now)
1131 #if defined(CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT)
1132         // Install async breakpoint handler into vector table.
1133         CYGACC_CALL_IF_INSTALL_BPT_FN_SET(&cyg_hal_gdb_interrupt);
1134 #endif
1135
1136 #if 0 != CYGINT_HAL_PLF_IF_INIT
1137         // Call platform specific initializations - should only be used
1138         // to augment what has already been set up, etc.
1139         plf_if_init();
1140 #endif
1141 }