📄 cpu.c
字号:
/* * UNIX Simulator Dependent Source * * COPYRIGHT (c) 1994,95 by Division Incorporated * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.com/license/LICENSE. * * $Id: cpu.c,v 1.46.2.1 2003/09/04 18:47:42 joel Exp $ */#include <rtems/system.h>#include <rtems/score/isr.h>#include <rtems/score/interr.h>#if defined(__linux__)#define _XOPEN_SOURCE#define MALLOC_0_RETURNS_NULL#endif#include <sys/types.h>#include <sys/times.h>#include <stdio.h>#include <stdlib.h>#include <setjmp.h>#include <signal.h>#include <time.h>#include <sys/time.h>#include <errno.h>#include <unistd.h>#if defined(RTEMS_MULTIPROCESSING)#include <sys/ipc.h>#include <sys/shm.h>#include <sys/sem.h>#endif#include <string.h> /* memset */#ifndef SA_RESTART#define SA_RESTART 0#endiftypedef struct { jmp_buf regs; int isr_level;} Context_Control_overlay;void _CPU_Signal_initialize(void);void _CPU_Stray_signal(int);void _CPU_ISR_Handler(int);static sigset_t _CPU_Signal_mask;static Context_Control_overlay _CPU_Context_Default_with_ISRs_enabled;static Context_Control_overlay _CPU_Context_Default_with_ISRs_disabled;/* * Sync IO support, an entry for each fd that can be set */void _CPU_Sync_io_Init();static rtems_sync_io_handler _CPU_Sync_io_handlers[FD_SETSIZE];static int sync_io_nfds;static fd_set sync_io_readfds;static fd_set sync_io_writefds;static fd_set sync_io_exceptfds;/* * Which cpu are we? Used by libcpu and libbsp. */int cpu_number;/*PAGE * * _CPU_Initialize_vectors() * * Support routine to initialize the RTEMS vector table after it is allocated. * * UNIX Specific Information: * * Complete initialization since the table is now allocated. */ sigset_t posix_empty_mask;void _CPU_Initialize_vectors(void){ unsigned32 i; proc_ptr old_handler; /* * Generate an empty mask to be used by disable_support */ sigemptyset(&posix_empty_mask); /* * Block all the signals except SIGTRAP for the debugger * and fatal error signals. */ (void) sigfillset(&_CPU_Signal_mask); (void) sigdelset(&_CPU_Signal_mask, SIGTRAP); (void) sigdelset(&_CPU_Signal_mask, SIGABRT);#if !defined(__CYGWIN__) (void) sigdelset(&_CPU_Signal_mask, SIGIOT);#endif (void) sigdelset(&_CPU_Signal_mask, SIGCONT); (void) sigdelset(&_CPU_Signal_mask, SIGSEGV); (void) sigdelset(&_CPU_Signal_mask, SIGBUS); (void) sigdelset(&_CPU_Signal_mask, SIGFPE); _CPU_ISR_Enable(1); /* * 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 < CPU_INTERRUPT_NUMBER_OF_VECTORS; i++) (void)_CPU_ISR_install_vector(i, _CPU_Stray_signal, &old_handler); _CPU_Signal_initialize();}void _CPU_Signal_initialize( void ){ struct sigaction act; sigset_t mask; /* mark them all active except for TraceTrap and Abort */ mask = _CPU_Signal_mask; sigprocmask(SIG_UNBLOCK, &mask, 0); act.sa_handler = _CPU_ISR_Handler; act.sa_mask = mask; act.sa_flags = SA_RESTART; sigaction(SIGHUP, &act, 0); sigaction(SIGINT, &act, 0); sigaction(SIGQUIT, &act, 0); sigaction(SIGILL, &act, 0);#ifdef SIGEMT sigaction(SIGEMT, &act, 0);#endif sigaction(SIGFPE, &act, 0); sigaction(SIGKILL, &act, 0); sigaction(SIGBUS, &act, 0); sigaction(SIGSEGV, &act, 0);#ifdef SIGSYS sigaction(SIGSYS, &act, 0);#endif sigaction(SIGPIPE, &act, 0); sigaction(SIGALRM, &act, 0); sigaction(SIGTERM, &act, 0); sigaction(SIGUSR1, &act, 0); sigaction(SIGUSR2, &act, 0); sigaction(SIGCHLD, &act, 0);#ifdef SIGCLD sigaction(SIGCLD, &act, 0);#endif#ifdef SIGPWR sigaction(SIGPWR, &act, 0);#endif 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);#ifdef SIGLOST sigaction(SIGLOST, &act, 0);#endif}/*PAGE * * _CPU_Context_From_CPU_Init */void _CPU_Context_From_CPU_Init(){#if defined(__hppa__) && defined(RTEMS_UNIXLIB_SETJMP) /* * HACK - set the _SYSTEM_ID to 0x20c so that setjmp/longjmp * will handle the full 32 floating point registers. */ { extern unsigned32 _SYSTEM_ID; _SYSTEM_ID = 0x20c; }#endif /* * get default values to use in _CPU_Context_Initialize() */ if ( sizeof(Context_Control_overlay) > sizeof(Context_Control) ) _CPU_Fatal_halt( 0xdeadf00d ); (void) memset( &_CPU_Context_Default_with_ISRs_enabled, 0, sizeof(Context_Control_overlay) ); (void) memset( &_CPU_Context_Default_with_ISRs_disabled, 0, sizeof(Context_Control_overlay) ); _CPU_ISR_Set_level( 0 ); _CPU_Context_switch( (Context_Control *) &_CPU_Context_Default_with_ISRs_enabled, (Context_Control *) &_CPU_Context_Default_with_ISRs_enabled ); _CPU_ISR_Set_level( 1 ); _CPU_Context_switch( (Context_Control *) &_CPU_Context_Default_with_ISRs_disabled, (Context_Control *) &_CPU_Context_Default_with_ISRs_disabled );}/*PAGE * * _CPU_Sync_io_Init */void _CPU_Sync_io_Init(){ int fd; for (fd = 0; fd < FD_SETSIZE; fd++) _CPU_Sync_io_handlers[fd] = NULL; sync_io_nfds = 0; FD_ZERO(&sync_io_readfds); FD_ZERO(&sync_io_writefds); FD_ZERO(&sync_io_exceptfds);}/*PAGE * * _CPU_ISR_Get_level */unsigned32 _CPU_ISR_Get_level( void ){ sigset_t old_mask; sigemptyset( &old_mask ); sigprocmask(SIG_BLOCK, 0, &old_mask); if (memcmp((void *)&posix_empty_mask, (void *)&old_mask, sizeof(sigset_t))) return 1; return 0;}/* _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 */){ /* * If something happened where the public Context_Control is not * at least as large as the private Context_Control_overlay, then * we are in trouble. */ if ( sizeof(Context_Control_overlay) > sizeof(Context_Control) ) _CPU_Fatal_error(0x100 + 1); /* * 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; _CPU_Sync_io_Init(); _CPU_Context_From_CPU_Init();}/*PAGE * * _CPU_ISR_install_raw_handler */void _CPU_ISR_install_raw_handler( unsigned32 vector, proc_ptr new_handler, proc_ptr *old_handler){ _CPU_Fatal_halt( 0xdeaddead );}/*PAGE * * _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 _CPU_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_Thread_Idle_body * * Stop until we get a signal which is the logically the same thing * entering low-power or sleep mode on a real processor and waiting for * an interrupt. This significantly reduces the consumption of host * CPU cycles which is again similar to low power mode. */void _CPU_Thread_Idle_body( void ){#if CPU_SYNC_IO extern void _Thread_Dispatch(void); int fd;#endif while (1) {#ifdef RTEMS_DEBUG /* interrupts had better be enabled at this point! */ if (_CPU_ISR_Get_level() != 0) abort();#endif /* * Block on a select statement, the CPU interface added allow the * user to add new descriptors which are to be blocked on */#if CPU_SYNC_IO if (sync_io_nfds) { int result; fd_set readfds, writefds, exceptfds; readfds = sync_io_readfds; writefds = sync_io_writefds; exceptfds = sync_io_exceptfds; result = select(sync_io_nfds, &readfds, &writefds, &exceptfds, NULL); if (result < 0) { if (errno != EINTR) _CPU_Fatal_error(0x200); /* FIXME : what number should go here !! */ _Thread_Dispatch(); continue; } for (fd = 0; fd < sync_io_nfds; fd++) { boolean read = FD_ISSET(fd, &readfds); boolean write = FD_ISSET(fd, &writefds); boolean except = FD_ISSET(fd, &exceptfds); if (_CPU_Sync_io_handlers[fd] && (read || write || except)) _CPU_Sync_io_handlers[fd](fd, read, write, except); } _Thread_Dispatch(); } else pause();#else pause();#endif }}/*PAGE * * _CPU_Context_Initialize */void _CPU_Context_Initialize( Context_Control *_the_context, unsigned32 *_stack_base, unsigned32 _size, unsigned32 _new_level, void *_entry_point, boolean _is_fp){ unsigned32 *addr; unsigned32 jmp_addr; unsigned32 _stack_low; /* lowest "stack aligned" address */ unsigned32 _stack_high; /* highest "stack aligned" address */ unsigned32 _the_size; jmp_addr = (unsigned32) _entry_point; /* * On CPUs with stacks which grow down, we build the stack * based on the _stack_high address. On CPUs with stacks which * grow up, we build the stack based on the _stack_low address. */ _stack_low = (unsigned32)(_stack_base) + CPU_STACK_ALIGNMENT - 1; _stack_low &= ~(CPU_STACK_ALIGNMENT - 1); _stack_high = (unsigned32)(_stack_base) + _size; _stack_high &= ~(CPU_STACK_ALIGNMENT - 1); if (_stack_high > _stack_low) _the_size = _stack_high - _stack_low; else _the_size = _stack_low - _stack_high; /* * Slam our jmp_buf template into the context we are creating */ if ( _new_level == 0 ) *(Context_Control_overlay *)_the_context = _CPU_Context_Default_with_ISRs_enabled; else *(Context_Control_overlay *)_the_context = _CPU_Context_Default_with_ISRs_disabled; addr = (unsigned32 *)_the_context;#if defined(__hppa__) *(addr + RP_OFF) = jmp_addr; *(addr + SP_OFF) = (unsigned32)(_stack_low + 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 * points to the pointer, so we put that into rp instead. */ if (jmp_addr & 0x40000000) { jmp_addr &= 0xfffffffc; *(addr + RP_OFF) = *(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_high - CPU_FRAME_SIZE); *(addr + FP_OFF) = (unsigned32)(_stack_high);#elif defined(__i386__) /* * This information was gathered by disassembling setjmp(). */ { unsigned32 stack_ptr; stack_ptr = _stack_high - CPU_FRAME_SIZE; *(addr + EBX_OFF) = 0xFEEDFEED; *(addr + ESI_OFF) = 0xDEADDEAD; *(addr + EDI_OFF) = 0xDEAFDEAF; *(addr + EBP_OFF) = stack_ptr; *(addr + ESP_OFF) = stack_ptr; *(addr + RET_OFF) = jmp_addr; addr = (unsigned32 *) stack_ptr; addr[ 0 ] = jmp_addr; addr[ 1 ] = (unsigned32) stack_ptr; addr[ 2 ] = (unsigned32) stack_ptr; }#else#error "UNKNOWN CPU!!!"#endif}/*PAGE * * _CPU_Context_restore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -