source: rtems/cpukit/score/cpu/unix/cpu.c @ 88d594a

4.104.114.84.95
Last change on this file since 88d594a was 88d594a, checked in by Joel Sherrill <joel.sherrill@…>, on May 24, 1995 at 9:39:42 PM

Fully tested on all in-house targets

  • Property mode set to 100644
File size: 12.2 KB
Line 
1/*
2 *  HP PA-RISC CPU Dependent Source
3 *
4 *
5 *  To anyone who acknowledges that this file is provided "AS IS"
6 *  without any express or implied warranty:
7 *      permission to use, copy, modify, and distribute this file
8 *      for any purpose is hereby granted without fee, provided that
9 *      the above copyright notice and this notice appears in all
10 *      copies, and that the name of Division Incorporated not be
11 *      used in advertising or publicity pertaining to distribution
12 *      of the software without specific, written prior permission.
13 *      Division Incorporated makes no representations about the
14 *      suitability of this software for any purpose.
15 *
16 *  $Id$
17 */
18
19#include <rtems/system.h>
20#include <rtems/fatal.h>
21#include <rtems/isr.h>
22#include <rtems/wkspace.h>
23/*
24 *  In order to get the types and prototypes used in this file under
25 *  Solaris 2.3, it is necessary to pull the following magic.
26 */ 
27
28#if defined(solaris)
29#warning "Ignore the undefining __STDC__ warning"
30#undef __STDC__
31#define __STDC__ 0
32#undef  _POSIX_C_SOURCE
33#endif
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <signal.h>
39#include <time.h>
40
41extern void           set_vector(proc_ptr, int, int);
42extern void           _Thread_Dispatch(void);
43
44extern unsigned32 _Thread_Dispatch_disable_level;
45extern unsigned32 _SYSTEM_ID;
46extern boolean    _Context_Switch_necessary;
47
48
49rtems_status_code signal_initialize(void);
50void         Stray_signal(int);
51void         signal_enable(unsigned32);
52void         signal_disable(unsigned32);
53void         interrupt_handler();
54
55sigset_t   UNIX_SIGNAL_MASK;
56jmp_buf    default_context;
57
58/*
59 * Which cpu are we? Used by libcpu and libbsp.
60 */
61
62int cpu_number;
63
64/*  _CPU_Initialize
65 *
66 *  This routine performs processor dependent initialization.
67 *
68 *  INPUT PARAMETERS:
69 *    cpu_table       - CPU table to initialize
70 *    thread_dispatch - address of disptaching routine
71 */
72
73
74void _CPU_Initialize(
75  rtems_cpu_table  *cpu_table,
76  void      (*thread_dispatch)      /* ignored on this CPU */
77)
78{
79  unsigned32  i;
80
81  if ( cpu_table == NULL )
82    rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED );
83
84  /*
85   *  The thread_dispatch argument is the address of the entry point
86   *  for the routine called at the end of an ISR once it has been
87   *  decided a context switch is necessary.  On some compilation
88   *  systems it is difficult to call a high-level language routine
89   *  from assembly.  This allows us to trick these systems.
90   *
91   *  If you encounter this problem save the entry point in a CPU
92   *  dependent variable.
93   */
94
95  _CPU_Thread_dispatch_pointer = thread_dispatch;
96
97  /*
98   * XXX; If there is not an easy way to initialize the FP context
99   *      during Context_Initialize, then it is usually easier to
100   *      save an "uninitialized" FP context here and copy it to
101   *      the task's during Context_Initialize.
102   */
103
104  /* XXX: FP context initialization support */
105
106  _CPU_Table = *cpu_table;
107
108#if defined(hppa1_1) && defined(RTEMS_UNIXLIB)
109    /*
110     * HACK - set the _SYSTEM_ID to 0x20c so that setjmp/longjmp
111     * will handle the full 32 floating point registers.
112     *
113     *  NOTE:  Is this a bug in HPUX9?
114     */
115
116    _SYSTEM_ID = 0x20c;
117#endif
118
119  /*
120   *  get default values to use in _CPU_Context_Initialize()
121   */
122
123   setjmp(default_context);
124
125  /*
126   * Block all the signals except SIGTRAP for the debugger
127   * and SIGABRT for fatal errors.
128   */
129
130  _CPU_ISR_Set_signal_level(1);
131
132  sigfillset(&UNIX_SIGNAL_MASK);
133  sigdelset(&UNIX_SIGNAL_MASK, SIGTRAP);
134  sigdelset(&UNIX_SIGNAL_MASK, SIGABRT);
135  sigdelset(&UNIX_SIGNAL_MASK, SIGIOT);
136  sigdelset(&UNIX_SIGNAL_MASK, SIGCONT);
137
138  sigprocmask(SIG_BLOCK, &UNIX_SIGNAL_MASK, 0);
139
140  /*
141   * Set the handler for all signals to be signal_handler
142   * which will then vector out to the correct handler
143   * for whichever signal actually happened. Initially
144   * set the vectors to the stray signal handler.
145   */
146
147  for (i = 0; i < 32; i++)
148      (void)set_vector(Stray_signal, i, 1);
149
150  signal_initialize();
151}
152
153/*  _CPU_ISR_install_vector
154 *
155 *  This kernel routine installs the RTEMS handler for the
156 *  specified vector.
157 *
158 *  Input parameters:
159 *    vector      - interrupt vector number
160 *    old_handler - former ISR for this vector number
161 *    new_handler - replacement ISR for this vector number
162 *
163 *  Output parameters:  NONE
164 *
165 */
166
167
168void _CPU_ISR_install_vector(
169  unsigned32  vector,
170  proc_ptr    new_handler,
171  proc_ptr   *old_handler
172)
173{
174   *old_handler = _ISR_Vector_table[ vector ];
175
176   /*
177    *  If the interrupt vector table is a table of pointer to isr entry
178    *  points, then we need to install the appropriate RTEMS interrupt
179    *  handler for this vector number.
180    */
181
182   /*
183    *  We put the actual user ISR address in '_ISR_vector_table'.  This will
184    *  be used by the _ISR_Handler so the user gets control.
185    */
186
187    _ISR_Vector_table[ vector ] = new_handler;
188}
189
190/*PAGE
191 *
192 *  _CPU_Install_interrupt_stack
193 */
194
195void _CPU_Install_interrupt_stack( void )
196{
197}
198
199/*PAGE
200 *
201 *  _CPU_Internal_threads_Idle_thread_body
202 *
203 *  NOTES:
204 *
205 *  1. This is the same as the regular CPU independent algorithm.
206 *
207 *  2. If you implement this using a "halt", "idle", or "shutdown"
208 *     instruction, then don't forget to put it in an infinite loop.
209 *
210 *  3. Be warned. Some processors with onboard DMA have been known
211 *     to stop the DMA if the CPU were put in IDLE mode.  This might
212 *     also be a problem with other on-chip peripherals.  So use this
213 *     hook with caution.
214 */
215
216void _CPU_Internal_threads_Idle_thread_body( void )
217{
218    while (1)
219        pause();
220}
221
222void _CPU_Context_Initialize(
223  Context_Control  *_the_context,
224  unsigned32       *_stack_base,
225  unsigned32        _size,
226  unsigned32        _new_level,
227  void             *_entry_point
228)
229{
230    unsigned32  *addr;
231    unsigned32   jmp_addr;
232    unsigned32   _stack_low;   /* lowest "stack aligned" address */
233    unsigned32   _stack_high;  /* highest "stack aligned" address */
234    unsigned32   _the_size;
235
236    jmp_addr = (unsigned32) _entry_point;
237
238    /*
239     *  On CPUs with stacks which grow down, we build the stack
240     *  based on the _stack_high address.  On CPUs with stacks which
241     *  grow up, we build the stack based on the _stack_low address. 
242     */
243
244    _stack_low = ((unsigned32)(_stack_base) + CPU_STACK_ALIGNMENT);
245    _stack_low &= ~(CPU_STACK_ALIGNMENT - 1);
246
247    _stack_high = ((unsigned32)(_stack_base) + _size);
248    _stack_high &= ~(CPU_STACK_ALIGNMENT - 1);
249
250    _the_size = _size & ~(CPU_STACK_ALIGNMENT - 1);
251
252    /*
253     * Slam our jmp_buf template into the context we are creating
254     */
255
256    memcpy(_the_context, default_context, sizeof(jmp_buf));
257
258    addr = (unsigned32 *)_the_context;
259
260#if defined(hppa1_1)
261    *(addr + RP_OFF) = jmp_addr;
262    *(addr + SP_OFF) = (unsigned32)(_stack_low + CPU_FRAME_SIZE);
263
264    /*
265     * See if we are using shared libraries by checking
266     * bit 30 in 24 off of newp. If bit 30 is set then
267     * we are using shared libraries and the jump address
268     * is at what 24 off of newp points to so shove that
269     * into 24 off of newp instead.
270     */
271
272    if (jmp_addr & 0x40000000) {
273       jmp_addr &= 0xfffffffc;
274       *(addr + RP_OFF) = (unsigned32)*(unsigned32 *)jmp_addr;
275    }
276#elif defined(sparc)
277
278    /*
279     *  See /usr/include/sys/stack.h in Solaris 2.3 for a nice
280     *  diagram of the stack.
281     */
282
283    asm ("ta  0x03");            /* flush registers */
284
285    *(addr + RP_OFF) = jmp_addr + ADDR_ADJ_OFFSET;
286    *(addr + SP_OFF) = (unsigned32)(_stack_high - CPU_FRAME_SIZE);
287    *(addr + FP_OFF) = (unsigned32)(_stack_high);
288#else
289#error "UNKNOWN CPU!!!"
290#endif
291
292    if (_new_level)
293        _CPU_ISR_Set_signal_level(1);
294    else
295        _CPU_ISR_Set_signal_level(0);
296
297}
298
299void _CPU_Context_restore(
300  Context_Control  *next
301)
302{
303    longjmp(next->regs, 0);
304}
305
306void _CPU_Context_switch(
307  Context_Control  *current,
308  Context_Control  *next
309)
310{
311    /*
312     * Save the current context
313     */
314
315    if (setjmp(current->regs) == 0) {
316
317       /*
318        * Switch to the new context
319        */
320
321       longjmp(next->regs, 0);
322    }
323}
324
325void _CPU_Save_float_context(
326  Context_Control_fp *fp_context
327)
328{
329}
330
331void _CPU_Restore_float_context(
332  Context_Control_fp *fp_context
333)
334{
335}
336
337void _CPU_ISR_Set_signal_level(unsigned32 level)
338{
339    if (level)
340        _CPU_Disable_signal();
341    else
342        _CPU_Enable_signal(0);
343}
344
345
346unsigned32 _CPU_Disable_signal(void)
347{
348    sigset_t  old_mask;
349    sigset_t  empty_mask;
350
351    sigemptyset(&empty_mask);
352    sigemptyset(&old_mask);
353    sigprocmask(SIG_BLOCK, &UNIX_SIGNAL_MASK, &old_mask);
354
355    if (memcmp((char *)&empty_mask, (char *)&old_mask, sizeof(sigset_t)) != 0)
356        return 1;
357
358    return 0;
359}
360
361
362void _CPU_Enable_signal(unsigned32 level)
363{
364    if (level == 0)
365        sigprocmask(SIG_UNBLOCK, &UNIX_SIGNAL_MASK, 0);
366}
367
368
369/*
370 * Support for external and spurious interrupts on HPPA
371 *
372 *  TODO:
373 *    delete interrupt.c etc.
374 *    Count interrupts
375 *    make sure interrupts disabled properly
376 *    should handler check again for more interrupts before exit?
377 *    How to enable interrupts from an interrupt handler?
378 *    Make sure there is an entry for everything in ISR_Vector_Table
379 */
380
381/*
382 * Init the external interrupt scheme
383 * called by bsp_start()
384 */
385
386rtems_status_code
387signal_initialize(void)
388{
389    struct sigaction act;
390    sigset_t         mask;
391
392    /* mark them all active except for TraceTrap  and Abort */
393
394    sigfillset(&mask);
395    sigdelset(&mask, SIGTRAP);
396    sigdelset(&mask, SIGABRT);
397    sigdelset(&mask, SIGIOT);
398    sigdelset(&mask, SIGCONT);
399    sigprocmask(SIG_UNBLOCK, &mask, 0);
400
401    act.sa_handler = interrupt_handler;
402    act.sa_mask = mask;
403#if defined(solaris)
404    act.sa_flags = SA_RESTART;
405#else
406    act.sa_flags = 0;
407#endif
408
409    sigaction(SIGHUP, &act, 0);
410    sigaction(SIGINT, &act, 0);
411    sigaction(SIGQUIT, &act, 0);
412    sigaction(SIGILL, &act, 0);
413    sigaction(SIGEMT, &act, 0);
414    sigaction(SIGFPE, &act, 0);
415    sigaction(SIGKILL, &act, 0);
416    sigaction(SIGBUS, &act, 0);
417    sigaction(SIGSEGV, &act, 0);
418    sigaction(SIGSYS, &act, 0);
419    sigaction(SIGPIPE, &act, 0);
420    sigaction(SIGALRM, &act, 0);
421    sigaction(SIGTERM, &act, 0);
422    sigaction(SIGUSR1, &act, 0);
423    sigaction(SIGUSR2, &act, 0);
424    sigaction(SIGCHLD, &act, 0);
425    sigaction(SIGCLD, &act, 0);
426    sigaction(SIGPWR, &act, 0);
427    sigaction(SIGVTALRM, &act, 0);
428    sigaction(SIGPROF, &act, 0);
429    sigaction(SIGIO, &act, 0);
430    sigaction(SIGWINCH, &act, 0);
431    sigaction(SIGSTOP, &act, 0);
432    sigaction(SIGTTIN, &act, 0);
433    sigaction(SIGTTOU, &act, 0);
434    sigaction(SIGURG, &act, 0);
435/*
436 *  XXX: Really should be on HPUX.
437 */
438
439#if defined(hppa1_1)
440    sigaction(SIGLOST, &act, 0);
441#endif
442
443    return RTEMS_SUCCESSFUL;
444}
445
446
447/*
448 * External interrupt handler.
449 * This is installed as cpu interrupt handler.
450 * It vectors out to specific external interrupt handlers.
451 */
452
453void
454interrupt_handler(int vector)
455{
456    if (_ISR_Nest_level++ == 0) {
457        /* switch to interrupt stack */
458    }
459
460    _Thread_Dispatch_disable_level++;
461
462    if (_ISR_Vector_table[vector]) {
463       _ISR_Vector_table[vector](vector);
464    }
465    else {
466       Stray_signal(vector);
467    }
468
469    if (_ISR_Nest_level-- == 0) {
470        /* switch back to original stack */
471    }
472
473    _Thread_Dispatch_disable_level--;
474
475    if (_Thread_Dispatch_disable_level == 0 &&
476        (_Context_Switch_necessary || _ISR_Signals_to_thread_executing)) {
477        _CPU_Enable_signal(0);
478        _Thread_Dispatch();
479    }
480}
481
482
483void
484Stray_signal(int sig_num)
485{
486    char buffer[ 80 ];   
487
488    /*
489     *  We avoid using the stdio section of the library.
490     *  The following is generally safe.
491     */
492
493    write( 
494      2,
495      buffer, 
496      sprintf( buffer, "Stray signal %d\n", sig_num )
497    );
498 
499    /*
500     * If it was a "fatal" signal, then exit here
501     * If app code has installed a hander for one of these, then
502     * we won't call Stray_signal, so this is ok.
503     */
504 
505    switch (sig_num)
506    {
507        case SIGINT:
508        case SIGHUP:
509        case SIGQUIT:
510        case SIGILL:
511        case SIGEMT:
512        case SIGKILL:
513        case SIGBUS:
514        case SIGSEGV:
515        case SIGTERM:
516            _CPU_Fatal_error(0x100 + sig_num);
517    }
518}
519
520
521void
522_CPU_Fatal_error(unsigned32 error)
523{
524    setitimer(ITIMER_REAL, 0, 0);
525
526    _exit(error);
527}
528
529int
530_CPU_ffs(unsigned32 value)
531{
532    int output;
533
534    output = ffs(value);
535    output = output - 1;
536
537    return(output);
538}
Note: See TracBrowser for help on using the repository browser.