]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/syscall.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / syscall.c
1 /*==========================================================================
2 //
3 //      syscall.c
4 //
5 //      Redboot syscall handling for GNUPro bsp support
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, 2003 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    msalter
44 // Contributors: msalter
45 // Date:         1999-02-20
46 // Purpose:      Temporary support for gnupro bsp
47 //
48 //####DESCRIPTIONEND####
49 //
50 //=========================================================================*/
51
52 #include <redboot.h>
53 #include <cyg/hal/hal_intr.h>
54 #include <cyg/hal/drv_api.h>
55 #include <cyg/hal/hal_stub.h>
56
57 #ifdef CYGSEM_REDBOOT_BSP_SYSCALLS
58
59 #define NEWLIB_EIO 5              /* I/O error */
60 #define NEWLIB_ENOSYS 88          /* Syscall not supported */
61
62 /*
63  * Clients of this BSP will need to have access to BSP functions and
64  * data structures. Because, the client and the BSP may not be linked
65  * together, a structure of vectors is used to gain this access. A
66  * pointer to this structure can be gotten via a syscall. This syscall
67  * is made automatically from within the crt0.o file.
68  */
69 typedef struct {
70     int         version;        /* version number for future expansion */
71     const void **__ictrl_table;
72     void **__exc_table;
73     void *__dbg_vector;
74     void *__kill_vector;
75     void *__console_procs;
76     void *__debug_procs;
77     void (*__flush_dcache)(void *__p, int __nbytes);
78     void (*__flush_icache)(void *__p, int __nbytes);
79     void *__cpu_data;
80     void *__board_data;
81     void *__sysinfo;
82     int  (*__set_debug_comm)(int __comm_id);
83     int  (*__set_console_comm)(int __comm_id);
84     int  (*__set_serial_baud)(int __comm_id, int baud);
85     void *__dbg_data;
86     void (*__reset)(void);
87     int  __console_interrupt_flag;
88 } __shared_t;
89
90 static __shared_t __shared_data = { 2 };
91
92 // this is used by newlib's mode_t so we should match it
93 #ifdef __GNUC__
94 #define _ST_INT32 __attribute__ ((__mode__ (__SI__)))
95 #else
96 #define _ST_INT32
97 #endif
98 typedef unsigned int    newlib_mode_t _ST_INT32;
99 typedef short           newlib_dev_t;
100 typedef unsigned short  newlib_ino_t;
101 typedef unsigned short  newlib_nlink_t;
102 typedef long            newlib_off_t;
103 typedef unsigned short  newlib_uid_t;
104 typedef unsigned short  newlib_gid_t;
105 typedef long            newlib_time_t;
106 typedef long            newlib_long_t;
107
108 struct newlib_stat 
109 {
110     newlib_dev_t     st_dev;
111     newlib_ino_t     st_ino;
112     newlib_mode_t    st_mode;
113     newlib_nlink_t   st_nlink;
114     newlib_uid_t     st_uid;
115     newlib_gid_t     st_gid;
116     newlib_dev_t     st_rdev;
117     newlib_off_t     st_size;
118     // We assume we've been compiled with the same flags as newlib here
119 #if defined(__svr4__) && !defined(__PPC__) && !defined(__sun__)
120     newlib_time_t    st_atime;
121     newlib_time_t    st_mtime;
122     newlib_time_t    st_ctime;
123 #else
124     newlib_time_t    st_atime;
125     newlib_long_t    st_spare1;
126     newlib_time_t    st_mtime;
127     newlib_long_t    st_spare2;
128     newlib_time_t    st_ctime;
129     newlib_long_t    st_spare3;
130     newlib_long_t    st_blksize;
131     newlib_long_t    st_blocks;
132     newlib_long_t    st_spare4[2];
133 #endif
134 };
135 #define NEWLIB_S_IFCHR 0020000 // character special file
136
137 static inline char __getc(void)
138 {
139     char c;
140     hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
141     
142     if (__chan)
143         c = CYGACC_COMM_IF_GETC(*__chan);
144     else {
145         __chan = CYGACC_CALL_IF_DEBUG_PROCS();
146         c = CYGACC_COMM_IF_GETC(*__chan);
147     }
148     return c;
149 }
150
151 static inline void __putc(char c)
152 {
153     hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
154     if (__chan)
155         CYGACC_COMM_IF_PUTC(*__chan, c);
156     else {
157         __chan = CYGACC_CALL_IF_DEBUG_PROCS();
158         CYGACC_COMM_IF_PUTC(*__chan, c);
159     }
160 }
161
162
163 static inline void __flush(void)
164 {
165     hal_virtual_comm_table_t* __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
166
167     if (__chan == NULL)
168         __chan = CYGACC_CALL_IF_DEBUG_PROCS();
169
170     CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_FLUSH_OUTPUT);
171 }
172
173 // Timer support
174
175 static cyg_handle_t  sys_timer_handle;
176 static cyg_interrupt sys_timer_interrupt;
177 static cyg_uint64    sys_timer_ticks = 0;
178
179 #ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
180
181 static unsigned int set_period = CYGNUM_HAL_RTC_PERIOD; // The default
182
183 typedef void *callback_func( char *pc, char *sp );
184 static callback_func *timer_callback = 0;
185
186 #endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
187
188 static void
189 sys_timer_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
190 {
191     // do nothing
192 }
193
194
195 static cyg_uint32
196 sys_timer_isr(cyg_vector_t vector, cyg_addrword_t data)
197 {
198     ++sys_timer_ticks;
199
200 #ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
201     HAL_CLOCK_RESET(CYGNUM_HAL_INTERRUPT_RTC, set_period);
202 #else
203     HAL_CLOCK_RESET(CYGNUM_HAL_INTERRUPT_RTC, CYGNUM_HAL_RTC_PERIOD);
204 #endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
205
206     cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_RTC);
207
208 #ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
209     if ( timer_callback ) {
210         char *intrpc = (char *)0;
211         char *intrsp = (char *)0;
212
213         // There may be a number of ways to get the PC and (optional) SP
214         // information out of the HAL.  Hence this is conditioned.  In some
215         // configurations, a register-set pointer is available as
216         // (invisible) argument 3 to this ISR call.
217
218 #ifdef HAL_GET_PROFILE_INFO
219         HAL_GET_PROFILE_INFO( intrpc, intrsp );
220 #endif // HAL_GET_PROFILE_INFO available
221
222         CYGARC_HAL_SAVE_GP();
223         timer_callback( intrpc, intrsp );
224         CYGARC_HAL_RESTORE_GP();
225     }
226 #endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
227     return CYG_ISR_HANDLED;
228 }
229
230
231 static void sys_timer_init(void)
232 {
233 #ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
234     HAL_CLOCK_INITIALIZE(set_period);
235 #else
236     HAL_CLOCK_INITIALIZE(CYGNUM_HAL_RTC_PERIOD);
237 #endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
238     
239     cyg_drv_interrupt_create(
240         CYGNUM_HAL_INTERRUPT_RTC,
241         0,                      // Priority - unused
242         (CYG_ADDRWORD)0,        // Data item passed to ISR & DSR
243         sys_timer_isr,          // ISR
244         sys_timer_dsr,          // DSR
245         &sys_timer_handle,      // handle to intr obj
246         &sys_timer_interrupt ); // space for int obj
247
248     cyg_drv_interrupt_attach(sys_timer_handle);
249
250     cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_RTC);
251 }
252
253
254 //
255 // read  -- read bytes from the serial port. Ignore fd, since
256 //          we only have stdin.
257 static int
258 sys_read(int fd, char *buf, int nbytes)
259 {
260     int i = 0;
261
262     for (i = 0; i < nbytes; i++) {
263         *(buf + i) = __getc();
264         if ((*(buf + i) == '\n') || (*(buf + i) == '\r')) {
265             (*(buf + i + 1)) = 0;
266             break;
267         }
268     }
269     return (i);
270 }
271
272
273 //
274 // write -- write bytes to the serial port. Ignore fd, since
275 //          stdout and stderr are the same. Since we have no filesystem,
276 //          open will only return an error.
277 //
278 static int
279 sys_write(int fd, char *buf, int nbytes)
280 {
281 #define WBUFSIZE  256
282     int  tosend;
283
284     tosend = nbytes;
285
286     while (tosend > 0) {
287         if (*buf == '\n')
288             __putc('\r');
289         __putc(*buf++);
290         tosend--;
291     }
292     __flush();
293
294     return (nbytes);
295 }
296
297
298 //
299 // open -- open a file descriptor. We don't have a filesystem, so
300 //         we return an error.
301 //
302 static int
303 sys_open (const char *buf, int flags, int mode)
304 {
305     return (-NEWLIB_EIO);
306 }
307
308 //
309 // close -- We don't need to do anything, but pretend we did.
310 //
311 static int
312 sys_close(int fd)
313 {
314     return (0);
315 }
316
317
318 //
319 // lseek --  Since a serial port is non-seekable, we return an error.
320 //
321 static int
322 sys_lseek(int fd,  int offset, int whence)
323 {
324     return (-NEWLIB_EIO);
325 }
326
327
328 #define NS_PER_TICK    (CYGNUM_HAL_RTC_NUMERATOR/CYGNUM_HAL_RTC_DENOMINATOR)
329 #define TICKS_PER_SEC  (1000000000ULL / NS_PER_TICK)
330
331 // This needs to match newlib HZ which is normally 60.
332 #define HZ (60ULL)
333
334 #ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
335 static unsigned int set_freq   = TICKS_PER_SEC; // The default
336 #endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
337 static int
338 sys_times(unsigned long *p)
339 {
340     static int inited = 0;
341
342     if (!inited) {
343         inited = 1;
344         sys_timer_init();
345     }
346
347     /* target clock runs at CLOCKS_PER_SEC. Convert to HZ */
348     if (p)
349 #ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
350         *p = (sys_timer_ticks * HZ) / (cyg_uint64)set_freq;
351 #else
352         *p = (sys_timer_ticks * HZ) / TICKS_PER_SEC;
353 #endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
354
355     return 0;
356 }
357
358 #ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
359
360 static void sys_profile_call_back( char *func, char **previous_call_back )
361 {
362     if ( previous_call_back )
363         *previous_call_back = (char *)timer_callback;
364
365     timer_callback = (callback_func *)func;
366
367     // Ensure the timer is started
368     (void)sys_times( (unsigned long *)0 );
369
370
371 static void sys_profile_frequency( int freq, int *previous_freq )
372 {
373 // Requested HZ:
374 // 0         => tell me the current value (no change, IMPLEMENTED HERE)
375 // - 1       => tell me the slowest (no change)
376 // - 2       => tell me the default (no change, IMPLEMENTED HERE)
377 // -nnn      => tell me what you would choose for nnn (no change)
378 // MIN_INT   => tell me the fastest (no change)
379 //        
380 // 1         => tell me the slowest (sets the clock)
381 // MAX_INT   => tell me the fastest (sets the clock)
382
383     // Ensure the timer is started
384     (void)sys_times( (unsigned long *)0 );
385
386     if ( -2 == freq )
387         freq = TICKS_PER_SEC; // default value
388     else if ( 0 == freq )
389         freq = set_freq; // collect current value
390     else {
391         int do_set_freq = (freq > 0);
392         unsigned int period = CYGNUM_HAL_RTC_PERIOD;
393
394         if ( 0 == (freq ^ -freq) ) // Then it's MIN_INT in local size
395             freq++; // just so that it will negate correctly
396
397         // Then set the timer to that fast - or pass on the enquiry
398 #ifdef HAL_CLOCK_REINITIALIZE
399         // Give the HAL enough info to do the division sum relative to
400         // the default setup, in period and TICKS_PER_SEC.
401         HAL_CLOCK_REINITIALIZE( freq, period, TICKS_PER_SEC );
402 #else
403         freq = TICKS_PER_SEC; // the only choice
404 #endif
405         if ( do_set_freq ) { // update the global variables
406             unsigned int orig = set_freq;
407             set_freq = freq;
408             set_period = period;
409             // We must "correct" sys_timer_ticks for the new scale factor.
410             sys_timer_ticks = sys_timer_ticks * set_freq / orig;
411         }
412     }
413
414     if ( previous_freq ) // Return the current value (new value)
415         *previous_freq = freq;
416 }
417
418 void sys_profile_reset( void )
419 {
420     timer_callback = NULL;
421 // Want to preserve the frequency between runs, for clever GDB users!
422 //    sys_profile_frequency( TICKS_PER_SEC, NULL );
423 }
424
425 #endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
426
427 //
428 //  Generic syscall handler.
429 //
430 //  Returns 0 if syscall number is not handled by this
431 //  module, 1 otherwise. This allows applications to
432 //  extend the syscall handler by using exception chaining.
433 //
434 CYG_ADDRWORD
435 __do_syscall(CYG_ADDRWORD func,                 // syscall function number
436              CYG_ADDRWORD arg1, CYG_ADDRWORD arg2,      // up to four args.
437              CYG_ADDRWORD arg3, CYG_ADDRWORD arg4,
438              CYG_ADDRWORD *retval, CYG_ADDRWORD *sig)   // syscall return value
439 {
440     int err = 0;
441     *sig = 0;
442
443     switch (func) {
444
445       case SYS_open:
446       {
447 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
448           __externC int cyg_hal_gdbfileio_open( const char *name, int flags, 
449                                                 int mode, int *sig );
450           if (gdb_active)
451               err = cyg_hal_gdbfileio_open((const char *)arg1, (int)arg2, (int)arg3,
452                                            (int *)sig);
453           else
454 #endif
455               err = sys_open((const char *)arg1, (int)arg2, (int)arg3);
456           break;
457       }
458       case SYS_read:
459       {
460 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
461           __externC int cyg_hal_gdbfileio_read( int fd, void *buf, size_t count,
462                                                 int *sig );
463           if (gdb_active)
464               err = cyg_hal_gdbfileio_read((int)arg1, (void *)arg2, (size_t)arg3,
465                                            (int *)sig);
466           else
467 #endif
468               err = sys_read((int)arg1, (char *)arg2, (int)arg3);
469           break;
470       }
471       case SYS_write:
472       {
473 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
474           __externC int cyg_hal_gdbfileio_write( int fd, const void *buf,
475                                                  size_t count, int *sig );
476           if (gdb_active)
477               err = cyg_hal_gdbfileio_write((int)arg1, (const void *)arg2,
478                                             (size_t)arg3, (int *)sig);
479           else
480 #endif
481               err = sys_write((int)arg1, (char *)arg2, (int)arg3);
482           break;
483       }
484       case SYS_close:
485       {
486 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
487           __externC int cyg_hal_gdbfileio_close( int fd, int *sig );
488           if (gdb_active)
489               err = cyg_hal_gdbfileio_close((int)arg1, (int *)sig);
490           else
491 #endif
492               err = sys_close((int)arg1);
493           break;
494       }
495       case SYS_lseek:
496       {
497 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
498           __externC int cyg_hal_gdbfileio_lseek( int fd, long offset,
499                                                  int whence, int *sig );
500           if (gdb_active)
501               err = cyg_hal_gdbfileio_lseek((int)arg1, (long)arg2, (int)arg3,
502                                             (int *)sig);
503           else
504 #endif
505               err = sys_lseek((int)arg1, (int)arg2, (int)arg3);
506           break;
507       }
508       case SYS_stat:
509       {
510 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
511           __externC int cyg_hal_gdbfileio_stat( const char *pathname,
512                                                 void *statbuf, int *sig );
513           if (gdb_active)
514               err = cyg_hal_gdbfileio_stat((const char *)arg1, (void *)arg2,
515                                            (int *)sig);
516           else
517 #endif
518               err = -NEWLIB_ENOSYS;
519           break;
520       }
521       case SYS_fstat:
522       {
523 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
524           __externC int cyg_hal_gdbfileio_fstat( int fd, void *statbuf,
525                                                  int *sig );
526           if (gdb_active)
527               err = cyg_hal_gdbfileio_fstat((int)arg1, (void *)arg2,
528                                             (int *)sig);
529           else
530 #endif
531           {
532               struct newlib_stat *st = (struct newlib_stat *)arg2;
533               st->st_mode = NEWLIB_S_IFCHR;
534               st->st_blksize = 4096;
535               err = 0;
536           }
537           break;
538       }
539       case SYS_rename:
540       {
541 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
542           __externC int cyg_hal_gdbfileio_rename( const char *oldpath,
543                                                   const char *newpath,
544                                                   int *sig );
545           if (gdb_active)
546               err = cyg_hal_gdbfileio_rename((const char *)arg1, (const char *)arg2,
547                                              (int *)sig);
548           else
549 #endif
550               err = -NEWLIB_ENOSYS;
551           break;
552       }
553       case SYS_unlink:
554       {
555 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
556           __externC int cyg_hal_gdbfileio_unlink( const char *pathname,
557                                                   int *sig );
558           if (gdb_active)
559               err = cyg_hal_gdbfileio_unlink((const char *)arg1, (int *)sig);
560           else
561 #endif
562               err = -NEWLIB_ENOSYS;
563           break;
564       }
565       case SYS_isatty:
566       {
567 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
568           __externC int cyg_hal_gdbfileio_isatty( int fd, int *sig );
569           if (gdb_active)
570               err = cyg_hal_gdbfileio_isatty((int)arg1, (int *)sig);
571           else
572 #endif
573               err = 1;
574           break;
575       }
576       case SYS_system:
577       {
578 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
579           __externC int cyg_hal_gdbfileio_system( const char *command,
580                                                   int *sig );
581           if (gdb_active)
582               err = cyg_hal_gdbfileio_system((const char *)arg1, (int *)sig);
583           else
584 #endif
585               err = -1;
586           break;
587       }
588       case SYS_gettimeofday:
589       {
590 #ifdef CYGPKG_HAL_GDB_FILEIO // File I/O over the GDB remote protocol
591           __externC int cyg_hal_gdbfileio_gettimeofday( void *tv, void *tz,
592                                                         int *sig );
593           if (gdb_active)
594               err = cyg_hal_gdbfileio_gettimeofday((void *)arg1, (void *)arg2,
595                                                    (int *)sig);
596           else
597 #endif
598               err = 0;
599           break;
600       }
601       case SYS_utime:
602         // FIXME. Some libglosses depend on this behavior.
603         err = sys_times((unsigned long *)arg1);
604         break;
605
606       case SYS_times:
607         err = sys_times((unsigned long *)arg1);
608         break;
609
610       case SYS_meminfo:
611         err = 1;
612         *(unsigned long *)arg1 = (unsigned long)(ram_end-ram_start);
613         *(unsigned long *)arg2 = (unsigned long)ram_end;
614         break;
615 #ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
616     case SYS_timer_call_back:
617         sys_profile_call_back( (char *)arg1, (char **)arg2 );
618         break;
619
620     case SYS_timer_frequency:
621         sys_profile_frequency( (int)arg1, (unsigned int *)arg2 );
622         break;
623
624     case SYS_timer_reset:
625         sys_profile_reset();
626         break;
627
628 #endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
629       case __GET_SHARED:
630         *(__shared_t **)arg1 = &__shared_data;
631         break;
632
633       case SYS_exit:
634         *sig = -1;    // signal exit
635         err = arg1;
636
637         if (gdb_active) {
638 #ifdef CYGOPT_REDBOOT_BSP_SYSCALLS_EXIT_WITHOUT_TRAP
639             __send_exit_status((int)arg1);
640 #else
641             *sig = SIGTRAP;
642             err = func;
643 #endif // CYGOPT_REDBOOT_BSP_SYSCALLS_EXIT_WITHOUT_TRAP
644         }
645         break;
646
647       default:
648         return 0;
649     }    
650
651     *retval = err;
652     return 1;
653 }
654
655 #endif