The _ISR_Handler routine provides the RTEMS interrupt management.
void _ISR_Handler()
This discussion ignores a lot of the ugly details in a real implementation such as saving enough registers/state to be able to do something real. Keep in mind that the goal is to invoke a user's ISR handler which is written in C. That ISR handler uses a known set of registers thus allowing the ISR to preserve only those that would normally be corrupted by a subroutine call.
Also note that the exact order is to a large extent flexible. Hardware
will dictate a sequence for a certain subset of _ISR_Handler while
requirements for setting the RTEMS state variables that indicate the
interrupt nest level (_ISR_Nest_level) and dispatching disable
level (_Thread_Dispatch_disable_level) will also
restrict the allowable order.
Upon entry to _ISR_Handler, _Thread_Dispatch_disable_level is
zero if the interrupt occurred while outside an RTEMS service call.
Conversely, it will be non-zero if interrupting an RTEMS service
call. Thus, _Thread_Dispatch_disable_level will always be
greater than or equal to _ISR_Nest_level and not strictly
equal.
Upon entry to the "common" _ISR_Handler, the vector number must be
available. On some CPUs the hardware puts either the vector number or the
offset into the vector table for this ISR in a known place. If the
hardware does not provide this information, then the assembly portion of
RTEMS for this port will contain a set of distinct interrupt entry points
which somehow place the vector number in a known place (which is safe if
another interrupt nests this one) and branches to _ISR_Handler.
save some or all context on stack
may need to save some special interrupt information for exit
#if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
if ( _ISR_Nest_level == 0 )
switch to software interrupt stack
#endif
_ISR_Nest_level++;
_Thread_Dispatch_disable_level++;
(*_ISR_Vector_table[ vector ])( vector );
--_ISR_Nest_level;
if ( _ISR_Nest_level )
goto the label "exit interrupt (simple case)"
#if ( CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE )
restore stack
#endif
if ( _Thread_Dispatch_disable_level )
_ISR_Signals_to_thread_executing = FALSE;
goto the label "exit interrupt (simple case)"
if ( _Context_Switch_necessary || _ISR_Signals_to_thread_executing )
_ISR_Signals_to_thread_executing = FALSE;
call _Thread_Dispatch() or prepare to return to _ISR_Dispatch
prepare to get out of interrupt
return from interrupt (maybe to _ISR_Dispatch)
LABEL "exit interrupt (simple case):
prepare to get out of interrupt
return from interrupt
Some ports have the special routine _ISR_Dispatch because
the CPU has a special "interrupt mode" and RTEMS must switch back
to the task stack and/or non-interrupt mode before invoking
_Thread_Dispatch. For example, consider the MC68020 where
upon return from the outermost interrupt, the CPU must switch
from the interrupt stack to the master stack before invoking
_Thread_Dispatch. _ISR_Dispatch is the special port
specific wrapper for _Thread_Dispatch used in this case.
Copyright © 1988-2004 OAR Corporation