From ac7d5ef06a6d6e8d84abbd1f0b82162725f98326 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 11 May 1995 17:39:37 +0000 Subject: Initial revision --- c/src/exec/score/cpu/unix/cpu.c | 529 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 529 insertions(+) create mode 100644 c/src/exec/score/cpu/unix/cpu.c (limited to 'c/src/exec/score/cpu/unix/cpu.c') diff --git a/c/src/exec/score/cpu/unix/cpu.c b/c/src/exec/score/cpu/unix/cpu.c new file mode 100644 index 0000000000..ed94953d58 --- /dev/null +++ b/c/src/exec/score/cpu/unix/cpu.c @@ -0,0 +1,529 @@ +/* + * HP PA-RISC CPU Dependent Source + * + * + * To anyone who acknowledges that this file is provided "AS IS" + * without any express or implied warranty: + * permission to use, copy, modify, and distribute this file + * for any purpose is hereby granted without fee, provided that + * the above copyright notice and this notice appears in all + * copies, and that the name of Division Incorporated not be + * used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Division Incorporated makes no representations about the + * suitability of this software for any purpose. + * + * $Id$ + */ + +#include +#include +#include +#include +/* + * In order to get the types and prototypes used in this file under + * Solaris 2.3, it is necessary to pull the following magic. + */ + +#if defined(solaris) +#warning "Ignore the undefining __STDC__ warning" +#undef __STDC__ +#define __STDC__ 0 +#undef _POSIX_C_SOURCE +#endif + +#include +#include +#include +#include +#include +#include + +extern void set_vector(proc_ptr, int, int); +extern void _Thread_Dispatch(void); + +extern unsigned32 _Thread_Dispatch_disable_level; +extern unsigned32 _SYSTEM_ID; +extern boolean _Context_Switch_necessary; + + +rtems_status_code signal_initialize(void); +void Stray_signal(int); +void signal_enable(unsigned32); +void signal_disable(unsigned32); +void interrupt_handler(); + +sigset_t UNIX_SIGNAL_MASK; +jmp_buf default_context; + +/* + * Which cpu are we? Used by libcpu and libbsp. + */ + +int cpu_number; + +/* _CPU_Initialize + * + * This routine performs processor dependent initialization. + * + * INPUT PARAMETERS: + * cpu_table - CPU table to initialize + * thread_dispatch - address of disptaching routine + */ + + +void _CPU_Initialize( + rtems_cpu_table *cpu_table, + void (*thread_dispatch) /* ignored on this CPU */ +) +{ + unsigned32 i; + + if ( cpu_table == NULL ) + rtems_fatal_error_occurred( RTEMS_NOT_CONFIGURED ); + + /* + * The thread_dispatch argument is the address of the entry point + * for the routine called at the end of an ISR once it has been + * decided a context switch is necessary. On some compilation + * systems it is difficult to call a high-level language routine + * from assembly. This allows us to trick these systems. + * + * If you encounter this problem save the entry point in a CPU + * dependent variable. + */ + + _CPU_Thread_dispatch_pointer = thread_dispatch; + + /* + * XXX; If there is not an easy way to initialize the FP context + * during Context_Initialize, then it is usually easier to + * save an "uninitialized" FP context here and copy it to + * the task's during Context_Initialize. + */ + + /* XXX: FP context initialization support */ + + _CPU_Table = *cpu_table; + +#if defined(hppa1_1) && defined(RTEMS_UNIXLIB) + /* + * HACK - set the _SYSTEM_ID to 0x20c so that setjmp/longjmp + * will handle the full 32 floating point registers. + * + * NOTE: Is this a bug in HPUX9? + */ + + _SYSTEM_ID = 0x20c; +#endif + + /* + * get default values to use in _CPU_Context_Initialize() + */ + + setjmp(default_context); + + /* + * Block all the signals except SIGTRAP for the debugger + * and SIGABRT for fatal errors. + */ + + _CPU_ISR_Set_signal_level(1); + + sigfillset(&UNIX_SIGNAL_MASK); + sigdelset(&UNIX_SIGNAL_MASK, SIGTRAP); + sigdelset(&UNIX_SIGNAL_MASK, SIGABRT); + sigdelset(&UNIX_SIGNAL_MASK, SIGIOT); + sigdelset(&UNIX_SIGNAL_MASK, SIGCONT); + + sigprocmask(SIG_BLOCK, &UNIX_SIGNAL_MASK, 0); + + /* + * Set the handler for all signals to be signal_handler + * which will then vector out to the correct handler + * for whichever signal actually happened. Initially + * set the vectors to the stray signal handler. + */ + + for (i = 0; i < 32; i++) + (void)set_vector(Stray_signal, i, 1); + + signal_initialize(); +} + +/* _CPU_ISR_install_vector + * + * This kernel routine installs the RTEMS handler for the + * specified vector. + * + * Input parameters: + * vector - interrupt vector number + * old_handler - former ISR for this vector number + * new_handler - replacement ISR for this vector number + * + * Output parameters: NONE + * + */ + + +void _CPU_ISR_install_vector( + unsigned32 vector, + proc_ptr new_handler, + proc_ptr *old_handler +) +{ + *old_handler = _ISR_Vector_table[ vector ]; + + /* + * If the interrupt vector table is a table of pointer to isr entry + * points, then we need to install the appropriate RTEMS interrupt + * handler for this vector number. + */ + + /* + * We put the actual user ISR address in '_ISR_vector_table'. This will + * be used by the _ISR_Handler so the user gets control. + */ + + _ISR_Vector_table[ vector ] = new_handler; +} + +/*PAGE + * + * _CPU_Install_interrupt_stack + */ + +void _CPU_Install_interrupt_stack( void ) +{ +} + +/*PAGE + * + * _CPU_Internal_threads_Idle_thread_body + * + * NOTES: + * + * 1. This is the same as the regular CPU independent algorithm. + * + * 2. If you implement this using a "halt", "idle", or "shutdown" + * instruction, then don't forget to put it in an infinite loop. + * + * 3. Be warned. Some processors with onboard DMA have been known + * to stop the DMA if the CPU were put in IDLE mode. This might + * also be a problem with other on-chip peripherals. So use this + * hook with caution. + */ + +void _CPU_Internal_threads_Idle_thread_body( void ) +{ + while (1) + pause(); +} + +void _CPU_Context_Initialize( + Context_Control *_the_context, + unsigned32 *_stack_base, + unsigned32 _size, + unsigned32 _new_level, + proc_ptr *_entry_point +) +{ + unsigned32 *addr; + unsigned32 jmp_addr; + unsigned32 _stack; + unsigned32 _the_size; + + jmp_addr = (unsigned32) _entry_point; + + _stack = ((unsigned32)(_stack_base) + CPU_STACK_ALIGNMENT); + _stack &= ~(CPU_STACK_ALIGNMENT - 1); + + _the_size = _size & ~(CPU_STACK_ALIGNMENT - 1); + + /* + * Slam our jmp_buf template into the context we are creating + */ + + memcpy(_the_context, default_context, sizeof(jmp_buf)); + + addr = (unsigned32 *)_the_context; + +#if defined(hppa1_1) + *(addr + RP_OFF) = jmp_addr; + *(addr + SP_OFF) = (unsigned32)(_stack + CPU_FRAME_SIZE); + + /* + * See if we are using shared libraries by checking + * bit 30 in 24 off of newp. If bit 30 is set then + * we are using shared libraries and the jump address + * is at what 24 off of newp points to so shove that + * into 24 off of newp instead. + */ + + if (jmp_addr & 0x40000000) { + jmp_addr &= 0xfffffffc; + *(addr + RP_OFF) = (unsigned32)*(unsigned32 *)jmp_addr; + } +#elif defined(sparc) + + /* + * See /usr/include/sys/stack.h in Solaris 2.3 for a nice + * diagram of the stack. + */ + + asm ("ta 0x03"); /* flush registers */ + + *(addr + RP_OFF) = jmp_addr + ADDR_ADJ_OFFSET; + *(addr + SP_OFF) = (unsigned32)(_stack +_the_size - CPU_FRAME_SIZE); + *(addr + FP_OFF) = (unsigned32)(_stack +_the_size); +#else +#error "UNKNOWN CPU!!!" +#endif + + if (_new_level) + _CPU_ISR_Set_signal_level(1); + else + _CPU_ISR_Set_signal_level(0); + +} + +void _CPU_Context_restore( + Context_Control *next +) +{ + longjmp(next->regs, 0); +} + +void _CPU_Context_switch( + Context_Control *current, + Context_Control *next +) +{ + /* + * Save the current context + */ + + if (setjmp(current->regs) == 0) { + + /* + * Switch to the new context + */ + + longjmp(next->regs, 0); + } +} + +void _CPU_Save_float_context( + Context_Control_fp *fp_context +) +{ +} + +void _CPU_Restore_float_context( + Context_Control_fp *fp_context +) +{ +} + +void _CPU_ISR_Set_signal_level(unsigned32 level) +{ + if (level) + _CPU_Disable_signal(); + else + _CPU_Enable_signal(0); +} + + +unsigned32 _CPU_Disable_signal(void) +{ + sigset_t old_mask; + sigset_t empty_mask; + + sigemptyset(&empty_mask); + sigemptyset(&old_mask); + sigprocmask(SIG_BLOCK, &UNIX_SIGNAL_MASK, &old_mask); + + if (memcmp((char *)&empty_mask, (char *)&old_mask, sizeof(sigset_t)) != 0) + return 1; + + return 0; +} + + +void _CPU_Enable_signal(unsigned32 level) +{ + if (level == 0) + sigprocmask(SIG_UNBLOCK, &UNIX_SIGNAL_MASK, 0); +} + + +/* + * Support for external and spurious interrupts on HPPA + * + * TODO: + * delete interrupt.c etc. + * Count interrupts + * make sure interrupts disabled properly + * should handler check again for more interrupts before exit? + * How to enable interrupts from an interrupt handler? + * Make sure there is an entry for everything in ISR_Vector_Table + */ + +/* + * Init the external interrupt scheme + * called by bsp_start() + */ + +rtems_status_code +signal_initialize(void) +{ + struct sigaction act; + sigset_t mask; + + /* mark them all active except for TraceTrap and Abort */ + + sigfillset(&mask); + sigdelset(&mask, SIGTRAP); + sigdelset(&mask, SIGABRT); + sigdelset(&mask, SIGIOT); + sigdelset(&mask, SIGCONT); + sigprocmask(SIG_UNBLOCK, &mask, 0); + + act.sa_handler = interrupt_handler; + act.sa_mask = mask; +#if defined(solaris) + act.sa_flags = SA_RESTART; +#else + act.sa_flags = 0; +#endif + + sigaction(SIGHUP, &act, 0); + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); + sigaction(SIGILL, &act, 0); + sigaction(SIGEMT, &act, 0); + sigaction(SIGFPE, &act, 0); + sigaction(SIGKILL, &act, 0); + sigaction(SIGBUS, &act, 0); + sigaction(SIGSEGV, &act, 0); + sigaction(SIGSYS, &act, 0); + sigaction(SIGPIPE, &act, 0); + sigaction(SIGALRM, &act, 0); + sigaction(SIGTERM, &act, 0); + sigaction(SIGUSR1, &act, 0); + sigaction(SIGUSR2, &act, 0); + sigaction(SIGCHLD, &act, 0); + sigaction(SIGCLD, &act, 0); + sigaction(SIGPWR, &act, 0); + sigaction(SIGVTALRM, &act, 0); + sigaction(SIGPROF, &act, 0); + sigaction(SIGIO, &act, 0); + sigaction(SIGWINCH, &act, 0); + sigaction(SIGSTOP, &act, 0); + sigaction(SIGTTIN, &act, 0); + sigaction(SIGTTOU, &act, 0); + sigaction(SIGURG, &act, 0); +/* + * XXX: Really should be on HPUX. + */ + +#if defined(hppa1_1) + sigaction(SIGLOST, &act, 0); +#endif + + return RTEMS_SUCCESSFUL; +} + + +/* + * External interrupt handler. + * This is installed as cpu interrupt handler. + * It vectors out to specific external interrupt handlers. + */ + +void +interrupt_handler(int vector) +{ + if (_ISR_Nest_level++ == 0) { + /* switch to interrupt stack */ + } + + _Thread_Dispatch_disable_level++; + + if (_ISR_Vector_table[vector]) { + _ISR_Vector_table[vector](vector); + } + else { + Stray_signal(vector); + } + + if (_ISR_Nest_level-- == 0) { + /* switch back to original stack */ + } + + _Thread_Dispatch_disable_level--; + + if (_Thread_Dispatch_disable_level == 0 && + (_Context_Switch_necessary || _ISR_Signals_to_thread_executing)) { + _CPU_Enable_signal(0); + _Thread_Dispatch(); + } +} + + +void +Stray_signal(int sig_num) +{ + char buffer[ 80 ]; + + /* + * We avoid using the stdio section of the library. + * The following is generally safe. + */ + + write( + 2, + buffer, + sprintf( buffer, "Stray signal %d\n", sig_num ) + ); + + /* + * If it was a "fatal" signal, then exit here + * If app code has installed a hander for one of these, then + * we won't call Stray_signal, so this is ok. + */ + + switch (sig_num) + { + case SIGINT: + case SIGHUP: + case SIGQUIT: + case SIGILL: + case SIGEMT: + case SIGKILL: + case SIGBUS: + case SIGSEGV: + case SIGTERM: + _CPU_Fatal_error(0x100 + sig_num); + } +} + + +void +_CPU_Fatal_error(unsigned32 error) +{ + setitimer(ITIMER_REAL, 0, 0); + + _exit(error); +} + +int +_CPU_ffs(unsigned32 value) +{ + int output; + + output = ffs(value); + output = output - 1; + + return(output); +} -- cgit v1.2.3