source: rtems/cpukit/score/cpu/unix/cpu.c @ ac7d5ef0

4.104.114.84.95
Last change on this file since ac7d5ef0 was ac7d5ef0, checked in by Joel Sherrill <joel.sherrill@…>, on 05/11/95 at 17:39:37

Initial revision

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