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