source: SVN/cambria/redboot/packages/redboot/current/src/syscall.c @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 19.0 KB
Line 
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 */
69typedef 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
90static __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
98typedef unsigned int    newlib_mode_t _ST_INT32;
99typedef short           newlib_dev_t;
100typedef unsigned short  newlib_ino_t;
101typedef unsigned short  newlib_nlink_t;
102typedef long            newlib_off_t;
103typedef unsigned short  newlib_uid_t;
104typedef unsigned short  newlib_gid_t;
105typedef long            newlib_time_t;
106typedef long            newlib_long_t;
107
108struct 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
137static 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
151static 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
163static 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
175static cyg_handle_t  sys_timer_handle;
176static cyg_interrupt sys_timer_interrupt;
177static cyg_uint64    sys_timer_ticks = 0;
178
179#ifdef CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
180
181static unsigned int set_period = CYGNUM_HAL_RTC_PERIOD; // The default
182
183typedef void *callback_func( char *pc, char *sp );
184static callback_func *timer_callback = 0;
185
186#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
187
188static void
189sys_timer_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
190{
191    // do nothing
192}
193
194
195static cyg_uint32
196sys_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
231static 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.
257static int
258sys_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//
278static int
279sys_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//
302static int
303sys_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//
311static int
312sys_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//
321static int
322sys_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
335static unsigned int set_freq   = TICKS_PER_SEC; // The default
336#endif // CYGSEM_REDBOOT_BSP_SYSCALLS_GPROF
337static int
338sys_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
360static 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
371static 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
418void 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//
434CYG_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
Note: See TracBrowser for help on using the repository browser.