VxWorks Reference Manual : Libraries
intArchLib - architecture-dependent interrupt library
intLevelSet( ) - set the interrupt level (MC680x0, SPARC, i960, x86, ARM and SH)
intLock( ) - lock out interrupts
intUnlock( ) - cancel interrupt locks
intEnable( ) - enable corresponding interrupt bits (MIPS, PowerPC, ARM)
intDisable( ) - disable corresponding interrupt bits (MIPS, PowerPC, ARM)
intCRGet( ) - read the contents of the cause register (MIPS)
intCRSet( ) - write the contents of the cause register (MIPS)
intSRGet( ) - read the contents of the status register (MIPS)
intSRSet( ) - update the contents of the status register (MIPS)
intConnect( ) - connect a C routine to a hardware interrupt
intHandlerCreate( ) - construct an interrupt handler for a C routine (MC680x0, SPARC, i960, x86, MIPS)
intLockLevelSet( ) - set the current interrupt lock-out level (MC680x0, SPARC, i960, x86, ARM, SH)
intLockLevelGet( ) - get the current interrupt lock-out level (MC680x0, SPARC, i960, x86, ARM, SH)
intVecBaseSet( ) - set the vector (trap) base address (MC680x0, SPARC, i960, x86, MIPS, ARM)
intVecBaseGet( ) - get the vector (trap) base address (MC680x0, SPARC, i960, x86, MIPS, ARM)
intVecSet( ) - set a CPU vector (trap) (MC680x0, SPARC, i960, x86, MIPS, SH)
intVecGet( ) - get an interrupt vector (MC680x0, SPARC, i960, x86, MIPS, SH)
intVecTableWriteProtect( ) - write-protect exception vector table (MC680x0, SPARC, i960, x86, ARM)
intUninitVecSet( ) - set the uninitialized vector handler (ARM)
This library provides architecture-dependent routines to manipulate and connect to hardware interrupts. Any C language routine can be connected to any interrupt by calling intConnect( ). Vectors can be accessed directly by intVecSet( ) and intVecGet( ). The vector (trap) base register (if present) can be accessed by the routines intVecBaseSet( ) and intVecBaseGet( ).
Tasks can lock and unlock interrupts by calling intLock( ) and intUnlock( ). The lock-out level can be set and reported by intLockLevelSet( ) and intLockLevelGet( ) (MC680x0, SPARC, i960, i386/i486, ARM and SH only). The routine intLevelSet( ) changes the current interrupt level of the processor (MC680x0, SPARC, i960, ARM and SH).
Do not call VxWorks system routines with interrupts locked. Violating this rule may re-enable interrupts unpredictably.
Most of the routines in this library take an interrupt vector as a parameter, which is generally the byte offset into the vector table. Macros are provided to convert between interrupt vectors and interrupt numbers:
- IVEC_TO_INUM(intVector)
- converts a vector to a number.
- INUM_TO_IVEC(intNumber)
- converts a number to a vector.
- TRAPNUM_TO_IVEC(trapNumber)
- converts a trap number to a vector.
To switch between one of several routines for a particular interrupt, the following code fragment is one alternative:
vector = INUM_TO_IVEC(some_int_vec_num); oldfunc = intVecGet (vector); newfunc = intHandlerCreate (routine, parameter); intVecSet (vector, newfunc); ... intVecSet (vector, oldfunc); /* use original routine */ ... intVecSet (vector, newfunc); /* reconnect new routine */
iv.h, intLib.h
intLevelSet( ) - set the interrupt level (MC680x0, SPARC, i960, x86, ARM and SH)
int intLevelSet ( int level /* new interrupt level mask */ )
This routine changes the interrupt mask in the status register to take on the value specified by level. Interrupts are locked out at or below that level. The value of level must be in the following range:
On SPARC systems, traps must be enabled before the call.
MC680x0: 0 - 7 SPARC: 0 - 15 i960: 0 - 31 SH: 0 - 15 ARM BSP-specific
Do not call VxWorks system routines with interrupts locked. Violating this rule may re-enable interrupts unpredictably.
The previous interrupt level.
intLock( ) - lock out interrupts
int intLock (void)
This routine disables interrupts. The intLock( ) routine returns an architecture-dependent lock-out key representing the interrupt level prior to the call; this key can be passed to intUnlock( ) to re-enable interrupts.
For MC680x0, SPARC, i960, i386/i486, and SH architectures, interrupts are disabled at the level set by intLockLevelSet( ). The default lock-out level is the highest interrupt level (MC680x0 = 7, SPARC = 15, i960 = 31, i386/i486 = 1, SH = 15).
For MIPS processors, interrupts are disabled at the master lock-out level; this means no interrupt can occur even if unmasked in the IntMask bits (15-8) of the status register.
For ARM processors, interrupts (IRQs) are disabled by setting the I bit in the CPSR. This means no IRQs can occur.
For PowerPC processors, there is only one interrupt vector. The external interrupt (vector offset 0x500) is disabled when intLock( ) is called; this means that the processor cannot be interrupted by any external event.
The lock-out key is implemented differently for different architectures:
MC680x0: interrupt field mask SPARC: interrupt level (0 - 15) i960: interrupt level (0 - 31) MIPS: status register i386/i486: interrupt enable flag (IF) bit from EFLAGS register PowerPC: MSR register value ARM I bit from the CPSR SH: status register
Do not call VxWorks system routines with interrupts locked. Violating this rule may re-enable interrupts unpredictably.
The routine intLock( ) can be called from either interrupt or task level. When called from a task context, the interrupt lock level is part of the task context. Locking out interrupts does not prevent rescheduling. Thus, if a task locks out interrupts and invokes kernel services that cause the task to block (e.g., taskSuspend( ) or taskDelay( )) or that cause a higher priority task to be ready (e.g., semGive( ) or taskResume( )), then rescheduling occurs and interrupts are unlocked while other tasks run. Rescheduling may be explicitly disabled with taskLock( ). Traps must be enabled when calling this routine.
lockKey = intLock (); ... (work with interrupts locked out) intUnlock (lockKey);To lock out interrupts and task scheduling as well (see WARNING above):if (taskLock() == OK) { lockKey = intLock (); ... (critical section) intUnlock (lockKey); taskUnlock(); } else { ... (error message or recovery attempt) }
An architecture-dependent lock-out key for the interrupt level prior to the call.
intArchLib, intUnlock( ), taskLock( ), intLockLevelSet( )
intUnlock( ) - cancel interrupt locks
void intUnlock ( int lockKey /* lock-out key returned by preceding intLock() */ )
This routine re-enables interrupts that have been disabled by intLock( ). The parameter lockKey is an architecture-dependent lock-out key returned by a preceding intLock( ) call.
N/A
intArchLib, intLock( )
intEnable( ) - enable corresponding interrupt bits (MIPS, PowerPC, ARM)
int intEnable ( int level /* new interrupt bits (0x00 - 0xff00) */ )
This routine enables the input interrupt bits on the present status register of the MIPS and PowerPC processors.
ARM processors generally do not have on-chip interrupt controllers. Control of interrupts is a BSP-specific matter. This routine calls a BSP-specific routine to enable the interrupt. For each interrupt level to be used, there must be a call to this routine before it will be allowed to interrupt.
For MIPS, it is strongly advised that the level be a combination of SR_IBIT1 - SR_IBIT8.
OK or ERROR. (MIPS: The previous contents of the status register).
intDisable( ) - disable corresponding interrupt bits (MIPS, PowerPC, ARM)
int intDisable ( int level /* new interrupt bits (0x0 - 0xff00) */ )
On MIPS and PowerPC architectures, this routine disables the corresponding interrupt bits from the present status register.
ARM processors generally do not have on-chip interrupt controllers. Control of interrupts is a BSP-specific matter. This routine calls a BSP-specific routine to disable a particular interrupt level, regardless of the current interrupt mask level.
For MIPS, the macros SR_IBIT1 - SR_IBIT8 define bits that may be set.
OK or ERROR. (MIPS: The previous contents of the status register).
intCRGet( ) - read the contents of the cause register (MIPS)
int intCRGet (void)
This routine reads and returns the contents of the MIPS cause register.
The contents of the cause register.
intCRSet( ) - write the contents of the cause register (MIPS)
void intCRSet ( int value /* value to write to cause register */ )
This routine writes the contents of the MIPS cause register.
N/A
intSRGet( ) - read the contents of the status register (MIPS)
int intSRGet (void)
This routine reads and returns the contents of the MIPS status register.
The previous contents of the status register.
intSRSet( ) - update the contents of the status register (MIPS)
int intSRSet ( int value /* value to write to status register */ )
This routine updates and returns the previous contents of the MIPS status register.
The previous contents of the status register.
intConnect( ) - connect a C routine to a hardware interrupt
STATUS intConnect ( VOIDFUNCPTR * vector, /* interrupt vector to attach to */ VOIDFUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ )
This routine connects a specified C routine to a specified interrupt vector. The address of routine is generally stored at vector so that routine is called with parameter when the interrupt occurs. The routine is invoked in supervisor mode at interrupt level. A proper C environment is established, the necessary registers saved, and the stack set up.
The routine can be any normal C code, except that it must not invoke certain operating system functions that may block or perform I/O operations.
This routine generally simply calls intHandlerCreate( ) and intVecSet( ). The address of the handler returned by intHandlerCreate( ) is what actually goes in the interrupt vector.
This routine takes an interrupt vector as a parameter, which is the byte offset into the vector table. Macros are provided to convert between interrupt vectors and interrupt numbers, see intArchLib.
ARM processors generally do not have on-chip interrupt controllers. Control of interrupts is a BSP-specific matter. This routine calls a BSP-specific routine to install the handler such that, when the interrupt occurs, routine is called with parameter.
The on-chip interrupt controller (INTC) design of SH architecture depends on the processor type, but there are some similarities. The number of external interrupt inputs are limited, so it may necessary to multiplex some interrupt requests. However most of them are auto-vectored, thus have only one vector to an external interrupt input. As a framework to handle this type of multiplexed interrupt, you can use your original intConnect code by hooking it to _func_intConnectHook pointer. If _func_intConnectHook is set, the SH version of intConnect( ) simply calls the hooked routine with same arguments, then returns the status of hooked routine. A sysLib sample is shown below:
#include "intLib.h" #include "iv.h" /* INUM_INTR_HIGH for SH7750/SH7700 */ #define SYS_INT_TBL_SIZE (255 - INUM_INTR_HIGH) typedef struct { VOIDFUNCPTR routine; /* routine to be called */ int parameter; /* parameter to be passed */ } SYS_INT_TBL; LOCAL SYS_INT_TBL sysIntTbl [SYS_INT_TBL_SIZE]; /* local vector table */ LOCAL int sysInumVirtBase = INUM_INTR_HIGH + 1; STATUS sysIntConnect ( VOIDFUNCPTR *vec, /* interrupt vector to attach to */ VOIDFUNCPTR routine, /* routine to be called */ int param /* parameter to be passed to routine */ ) { FUNCPTR intDrvRtn; if (vec >= INUM_TO_IVEC (0) && vec < INUM_TO_IVEC (sysInumVirtBase)) { /* do regular intConnect() process */ intDrvRtn = intHandlerCreate ((FUNCPTR)routine, param); if (intDrvRtn == NULL) return ERROR; /* make vector point to synthesized code */ intVecSet ((FUNCPTR *)vec, (FUNCPTR)intDrvRtn); } else { int index = IVEC_TO_INUM (vec) - sysInumVirtBase; if (index < 0 || index >= SYS_INT_TBL_SIZE) return ERROR; sysIntTbl [index].routine = routine; sysIntTbl [index].parameter = param; } return OK; } void sysHwInit (void) { ... _func_intConnectHook = (FUNCPTR)sysIntConnect; } LOCAL void sysVmeIntr (void) { volatile UINT32 vec = *VME_VEC_REGISTER; /* get VME interrupt vector */ int i = vec - sysInumVirtBase; if (i >= 0 && i < SYS_INT_TBL_SIZE && sysIntTbl[i].routine != NULL) (*sysIntTbl[i].routine)(sysIntTbl[i].parameter); else logMsg ("uninitialized VME interrupt: vec = %d\n", vec,0,0,0,0,0); } void sysHwInit2 (void) { int i; ... /* initialize VME interrupts dispatch table */ for (i = 0; i < SYS_INT_TBL_SIZE; i++) { sysIntTbl[i].routine = (VOIDFUNCPTR)NULL; sysIntTbl[i].parameter = NULL; } /* connect generic VME interrupts handler */ intConnect (INT_VEC_VME, sysVmeIntr, NULL); ... }As shown below, the used vector numbers of SH processors are limited to certain ranges. Here the vector numbers for SH77XX processors are defined as (INTEVT register code)/0x20. The sysInumVirtBase should be initialized to a value higher than these used vector numbers, and the highest vector number is defined as INUM_INTR_HIGH. Thus it is typically safe to set sysInumVirtBase to (INUM_INTR_HIGH + 1).
The sysIntConnect( ) simply acts as the regular intConnect( ) if vector is smaller than INUM_TO_IVEC (sysInumVirtBase), so sysHwInit2( ) connects a common VME interrupt dispatcher sysVmeIntr to the multiplexed interrupt vector. If vector is equal to or greater than INUM_TO_IVEC (sysInumVirtBase), the sysIntConnect( ) fills a local vector entry in sysIntTbl[] with an individual VME interrupt handler, in a coordinated manner with sysVmeIntr.
------------------------------ type used vector number suggested sysInumVirtBase _ SH702x 0 - 115 128 SH703x 0 - 115 128 SH704x 0 - 156 157 SH760x 0 - 127 128 SH77xx 0 - 80 128 _
OK, or ERROR if the interrupt handler cannot be built.
intArchLib, intHandlerCreate( ), intVecSet( )
intHandlerCreate( ) - construct an interrupt handler for a C routine (MC680x0, SPARC, i960, x86, MIPS)
FUNCPTR intHandlerCreate ( FUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ )
This routine builds an interrupt handler around the specified C routine. This interrupt handler is then suitable for connecting to a specific vector address with intVecSet( ). The interrupt handler is invoked in supervisor mode at interrupt level. A proper C environment is established, the necessary registers saved, and the stack set up.
The routine can be any normal C code, except that it must not invoke certain operating system functions that may block or perform I/O operations.
A pointer to the new interrupt handler, or NULL if memory is insufficient.
intLockLevelSet( ) - set the current interrupt lock-out level (MC680x0, SPARC, i960, x86, ARM, SH)
void intLockLevelSet ( int newLevel /* new interrupt level */ )
This routine sets the current interrupt lock-out level and stores it in the globally accessible variable intLockMask. The specified interrupt level is masked when interrupts are locked by intLock( ). The default lock-out level (MC680x0 = 7, SPARC = 15, i960 = 31, i386/i486 = 1, SH = 15) is initially set by kernelInit( ) when VxWorks is initialized.
On the ARM, this call establishes the interrupt level to be set when intLock( ) is called.
N/A
intArchLib, intLockLevelGet( ), intLock( ), taskLock( )
intLockLevelGet( ) - get the current interrupt lock-out level (MC680x0, SPARC, i960, x86, ARM, SH)
int intLockLevelGet (void)
This routine returns the current interrupt lock-out level, which is set by intLockLevelSet( ) and stored in the globally accessible variable intLockMask. This is the interrupt level currently masked when interrupts are locked out by intLock( ). The default lock-out level (MC680x0 = 7, SPARC = 15, i960 = 31, i386/i486 = 1, SH = 15) is initially set by kernelInit( ) when VxWorks is initialized.
The interrupt level currently stored in the interrupt lock-out mask. (ARM = ERROR always)
intArchLib, intLockLevelSet( )
intVecBaseSet( ) - set the vector (trap) base address (MC680x0, SPARC, i960, x86, MIPS, ARM)
void intVecBaseSet ( FUNCPTR * baseAddr /* new vector (trap) base address */ )
This routine sets the vector (trap) base address. The CPU's vector base register is set to the specified value, and subsequent calls to intVecGet( ) or intVecSet( ) will use this base address. The vector base address is initially 0 (0x1000 for SPARC), until modified by calls to this routine.
On SPARC processors, the vector base address must be on a 4 Kbyte boundary (that is, its bottom 12 bits must be zero).
The 68000 has no vector base register; thus, this routine is a no-op for 68000 systems.
This routine is a no-op for i960 systems. The interrupt vector table is located in sysLib, and moving it by intVecBaseSet( ) would require resetting the processor. Also, the vector base is cached on-chip in the PRCB and thus cannot be set from this routine.
The MIPS processors have no vector base register; thus this routine is a no-op for this architecture.
This routine sets baseAddr to vbr, then loads an interrupt dispatch code to (vbr + 0x600). When SH77XX processor accepts an interrupt request, it sets an exception code to INTEVT register and jumps to (vbr + 0x600). Thus this dispatch code is commonly used for all interrupts' handling.
The exception codes are 12bits width, and interleaved by 0x20. VxWorks for SH77XX locates a vector table at (vbr + 0x800), and defines the vector offsets as (exception codes / 8). This vector table is commonly used by all interrupts, exceptions, and software traps.
All SH77XX processors have INTEVT register at address 0xffffffd8. The SH7707 processor has yet another INTEVT2 register at address 0x04000000, to identify its enhanced interrupt sources. The dispatch code obtains the address of INTEVT register from a global constant intEvtAdrs. The constant is defined in sysLib, thus the selection of INTEVT/INTEVT2 is configurable at BSP level. The intEvtAdrs is loaded to (vbr + 4) by intVecBaseSet( ).
After fetching the exception code, the interrupt dispatch code applies a new interrupt mask to the status register, and jumps to an individual interrupt handler. The new interrupt mask is taken from intPrioTable[], which is defined in sysALib. The intPrioTable[] is loaded to (vbr + 0xc00) by intVecBaseSet( ).
The ARM processors have no vector base register; thus this routine is a no-op for this architecture.
N/A
intArchLib, intVecBaseGet( ), intVecGet( ), intVecSet( )
intVecBaseGet( ) - get the vector (trap) base address (MC680x0, SPARC, i960, x86, MIPS, ARM)
FUNCPTR *intVecBaseGet (void)
This routine returns the current vector base address, which is set with intVecBaseSet( ).
The current vector base address (i960 = value of sysIntTable set in sysLib, MIPS = 0 always, ARM = 0 always).
intVecSet( ) - set a CPU vector (trap) (MC680x0, SPARC, i960, x86, MIPS, SH)
void intVecSet ( FUNCPTR * vector, /* vector offset */ FUNCPTR function /* address to place in vector */ )
This routine attaches an exception/interrupt/trap handler to a specified vector. The vector is specified as an offset into the CPU's vector table. This vector table starts, by default, at:
However, the vector table may be set to start at any address with intVecBaseSet( ) (on CPUs for which it is available). The vector table is set up in usrInit( ).
MC680x0: 0 SPARC: 0x1000 i960: sysIntTable in sysLib MIPS: excBsrTbl in excArchLib i386/i486: 0 SH702x/SH703x/SH704x/SH76xx: excBsrTbl in excArchLib SH77xx vbr + 0x800 This routine takes an interrupt vector as a parameter, which is the byte offset into the vector table. Macros are provided to convert between interrupt vectors and interrupt numbers, see intArchLib.
This routine generates code to:
- (1)
- save volatile registers;
- (2)
- fix possible window overflow;
- (3)
- read the processor state register into register %L0; and
- (4)
- jump to the specified address.
The intVecSet( ) routine puts this generated code into the trap table entry corresponding to vector.
Window overflow and window underflow are sacred to the kernel and may not be pre-empted. They are written here only to track changing trap base registers (TBRs). With the "branch anywhere" scheme (as opposed to the branch PC-relative +/-8 megabytes) the first instruction in the vector table must not be a change of flow control nor affect any critical registers. The JMPL that replaces the BA will always execute the next vector's first instruction.
Vectors 0-7 are illegal vectors; using them puts the vector into the priorities/pending portion of the table, which yields undesirable actions. The i960CA caches the NMI vector in internal RAM at system power-up. This is where the vector is taken when the NMI occurs. Thus, it is important to check to see if the vector being changed is the NMI vector, and, if so, to write it to internal RAM.
On MIPS CPUs the vector table is set up statically in software.
The specified interrupt handler function has to coordinate with an interrupt stack frame which is specially designed for SH77XX version of VxWorks:
[ task's stack ] [ interrupt stack ] | xxx | high address | yyy | +-------+ |__zzz__|<--------------|task'sp| 0 | | |INTEVT | -4 | | low address | ssr | -8 |_ spc _| -12 <- sp (non-nested interrupt) : : : : :_______: |INTEVT | 0 | ssr | -4 |_ spc _| -8 <- sp (nested interrupt) | |This interrupt stack frame is formed by a common interrupt dispatch code which is loaded at (vbr + 0x600). You usually do not have to pay any attention to this stack frame, since intConnect( ) automatically appends an appropriate stack manipulation code to your interrupt service routine. The intConnect( ) assumes that your interrupt service routine (ISR) is written in C, thus it also wraps your ISR in minimal register save/restore codes. However if you need a very fast response time to a particular interrupt request, you might want to skip this register save/restore sequence by directly attaching your ISR to the corresponding vector table entry using intVecSet( ). Note that this technique is only applicable to an interrupt service with NO VxWorks system call. For example it is not allowed to use semGive( ) or logMsg( ) in the interrupt service routine which is directly attached to vector table by intVecSet( ). To facilitate the direct usage of intVecSet( ) by user, a special entry point to exit an interrupt context is provided within the SH77XX version of VxWorks kernel. This entry point is located at address (vbr + intRte1W), here the intRte1W is a global symbol for the vbr offset of the entry point in 16 bit length. This entry point intRte1 assumes that the current register bank is 0 (SR.RB == 0), and r1 and r0 are still saved on the interrupt stack, and it also requires 0x70000000 in r0. Then intRte1 properly cleans up the interrupt stack and executes rte instruction to return to the previous interrupt or task context. The following code is an example of intRte1 usage. Here the corresponding intPrioTable[] entry is assumed to be 0x400000X0, namely MD=1, RB=0, BL=0 at the beginning of usrIsr1.
.text .align 2 .global _usrIsr1 .type _usrIsr1,@function .extern _usrRtn .extern intRte1W /* intPrioTable[] sets SR to 0x400000X0 */ _usrIsr1: mov.l r0,@-sp /* must save r0 first (BANK0) */ mov.l r1,@-sp /* must save r1 second (BANK0) */ mov.l r2,@-sp /* save rest of volatile registers (BANK0) */ mov.l r3,@-sp mov.l r4,@-sp mov.l r5,@-sp mov.l r6,@-sp mov.l r7,@-sp sts.l pr,@-sp sts.l mach,@-sp sts.l macl,@-sp mov.l UsrRtn,r0 jsr @r0 /* call user's C routine */ nop /* (delay slot) */ lds.l @sp+,macl /* restore volatile registers (BANK0) */ lds.l @sp+,mach lds.l @sp+,pr mov.l @sp+,r7 mov.l @sp+,r6 mov.l @sp+,r5 mov.l @sp+,r4 mov.l @sp+,r3 mov.l @sp+,r2 /* intRte1 restores r1 and r0 */ mov.l IntRte1W,r1 mov.w @r1,r0 stc vbr,r1 add r0,r1 mov.l IntRteSR,r0 /* r0: 0x70000000 */ jmp @r1 /* let intRte1 clean up stack, then rte */ nop /* (delay slot) */ .align 2 UsrRtn: .long _usrRtn /* user's C routine */ IntRteSR: .long 0x70000000 /* MD=1, RB=1, BL=1 */ IntRte1W: .long intRte1WThe intRte1 sets r0 to status register (SR: 0x70000000), to safely restore SPC/SSR and to clean up the interrupt stack. Note that TLB mishit exception immediately reboots CPU while SR.BL=1. To avoid this fatal condition, VxWorks loads the intRte1 code and the interrupt stack to a physical address space (P1) where no TLB mishit happens.Furthermore, there is another special entry point called intRte2 at an address (vbr + intRte2W). The intRte2 assumes that SR is already set to 0x70000000 (MD: 1, RB: 1, BL: 1), then it does not restore r1 and r0. While SR value is 0x70000000, you may use r0,r1,r2,r3 in BANK1 as volatile registers. The rest of BANK1 registers (r4,r5,r6,r7) are non-volatile, so if you need to use them then you have to preserve their original values by saving/restoring them on the interrupt stack. So, if you need the ultimate interrupt response time, you may set the corresponding intPrioTable[] entry to NULL and manage your interrupt service only with r0,r1,r2,r3 in BANK1 as shown in the next sample code:
.text .global _usrIsr2 .type _usrIsr2,@function .extern _usrIntCnt /* interrupt counter */ .extern intRte2W .align 2 /* MD=1, RB=1, BL=1, since SR is not */ /* substituted from intPrioTable[]. */ _usrIsr2: mov.l UsrIntAck,r1 mov #0x1,r0 mov.b r0,@r1 /* acknowledge interrupt */ mov.l UsrIntCnt,r1 mov.l X1FFFFFFF,r2 mov.l X80000000,r3 and r2,r1 or r3,r1 /* r1: _usrIntCnt address in P1 */ mov.l @r1,r0 add #1,r0 mov.l r0,@r1 /* increment counter */ mov.l IntRte2W,r1 and r2,r1 or r3,r1 /* r1: intRte2W address in P1 */ mov.w @r1,r0 stc vbr,r1 add r1,r0 jmp @r0 /* let intRte2 clean up stack, then rte */ nop /* (delay slot) */ .align 2 UsrIntAck: .long 0xa0001234 /* interrupt acknowledge register */ UsrIntCnt: .long _usrIntCnt IntRte2W: .long intRte2W X1FFFFFFF: .long 0x1fffffff X80000000: .long 0x80000000Note that the entire interrupt service is executed under SR.BL=1 in this sample code. It means that any access to virtual address space may reboot CPU, since TLB mishit exception is blocked. Therefore usrIsr2 has to access usrIntCnt and intRte2W from P1 region. Also usrIsr2 itself has to be executed on P1 region, and it can be done by relocating the address of usrIsr2 to P1 as shown below:
IMPORT void usrIsr2 (void); intVecSet (vector, (FUNCPTR)(((UINT32)usrIsr2 & 0x1fffffff) | 0x80000000));In conclusion, you have to guarantee that the entire ISR does not access to any virtual address space if you set the corresponding intPrioTable[] entry to NULL.
N/A
intArchLib, intVecBaseSet( ), intVecGet( )
intVecGet( ) - get an interrupt vector (MC680x0, SPARC, i960, x86, MIPS, SH)
FUNCPTR intVecGet ( FUNCPTR * vector /* vector offset */ )
This routine returns a pointer to the exception/interrupt handler attached to a specified vector. The vector is specified as an offset into the CPU's vector table. This vector table starts, by default, at:
However, the vector table may be set to start at any address with intVecBaseSet( ) (on CPUs for which it is available).
MC680x0: 0 SPARC: 0x1000 i960: sysIntTable in sysLib MIPS: excBsrTbl in excArchLib i386/i486: 0 SH702x/SH703x/SH704x/SH76xx: excBsrTbl in excArchLib SH77xx vbr + 0x800 This routine takes an interrupt vector as a parameter, which is the byte offset into the vector table. Macros are provided to convert between interrupt vectors and interrupt numbers, see intArchLib.
The interrupt table location is reinitialized to sysIntTable after booting. This location is returned by intVecBaseGet( ).
A pointer to the exception/interrupt handler attached to the specified vector.
intArchLib, intVecSet( ), intVecBaseSet( )
intVecTableWriteProtect( ) - write-protect exception vector table (MC680x0, SPARC, i960, x86, ARM)
STATUS intVecTableWriteProtect (void)
If the unbundled Memory Management Unit (MMU) support package (VxVMI) is present, this routine write-protects the exception vector table to protect it from being accidentally corrupted.
Note that other data structures contained in the page will also be write-protected. In the default VxWorks configuration, the exception vector table is located at location 0 in memory. Write-protecting this affects the backplane anchor, boot configuration information, and potentially the text segment (assuming the default text location of 0x1000.) All code that manipulates these structures has been modified to write-enable memory for the duration of the operation. If you select a different address for the exception vector table, be sure it resides in a page separate from other writable data structures.
OK, or ERROR if memory cannot be write-protected.
S_intLib_VEC_TABLE_WP_UNAVAILABLE
intUninitVecSet( ) - set the uninitialized vector handler (ARM)
void intUninitVecSet ( VOIDFUNCPTR routine /* ptr to user routine */ )
This routine installs a handler for the uninitialized vectors to be called when any uninitialised vector is entered.
N/A.