📄 intarchlib.c
字号:
* 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'.**.CS* .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 intRte1W* .CE** The `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:** .CS* .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 0x80000000* .CE** Note 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:** .CS* IMPORT void usrIsr2 (void);** intVecSet (vector, (FUNCPTR)(((UINT32)usrIsr2 & 0x1fffffff) | 0x80000000));* .CE** 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.* * NOTE SIMNT:* This routine does nothing.** RETURNS: N/A** SEE ALSO: intVecBaseSet(), intVecGet()*/void intVecSet ( FUNCPTR * vector, /* vector offset */ FUNCPTR function /* address to place in vector */ ) { ... }/********************************************************************************* intVecGet - get an interrupt vector (MC680x0, x86, MIPS, SH, SimSolaris, SimNT)** 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:* * .TS* tab(|);* l l.* MC680x0: | 0* MIPS: | `excBsrTbl' in excArchLib* x86: | 0* SH702x/SH703x/SH704x/SH76xx: | `excBsrTbl' in excArchLib* SH77xx: | vbr + 0x800* SimSolaris: | 0* .TE** However, the vector table may be set to start at any address with* intVecBaseSet() (on CPUs for which it is available).** 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'.** \"NOTE I960:* \"The interrupt table location is reinitialized to <sysIntTable> after* \"booting. This location is returned by intVecBaseGet().* \"* NOTE SIMNT:* This routine does nothing and always returns 0.** RETURNS:* A pointer to the exception/interrupt handler attached to the specified vector.** SEE ALSO: intVecSet(), intVecBaseSet()*/FUNCPTR intVecGet ( FUNCPTR * vector /* vector offset */ ) { ... }/********************************************************************************* intVecTableWriteProtect - write-protect exception vector table (MC680x0, x86, ARM, SimSolaris, SimNT)** 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.** NOTE SIMSOLARIS, SIMNT:* This routine always returns ERROR on simulators.** RETURNS: OK, or ERROR if memory cannot be write-protected.** ERRNO: S_intLib_VEC_TABLE_WP_UNAVAILABLE*/STATUS intVecTableWriteProtect (void) { ... }/********************************************************************************* intUninitVecSet - set the uninitialized vector handler (ARM)** This routine installs a handler for the uninitialized vectors to be* called when any uninitialised vector is entered.** RETURNS: N/A.*/void intUninitVecSet ( VOIDFUNCPTR routine /* ptr to user routine */ ) { ... }/********************************************************************************* intHandlerCreateI86 - construct an interrupt handler for a C routine (x86)** This routine builds an interrupt handler around a 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.** IMPLEMENTATION:* This routine builds an interrupt handler of the following form in* allocated memory:** .CS* 00 e8 kk kk kk kk call _intEnt * tell kernel* 05 50 pushl %eax * save regs* 06 52 pushl %edx* 07 51 pushl %ecx* 08 68 pp pp pp pp pushl $_parameterBoi * push BOI param* 13 e8 rr rr rr rr call _routineBoi * call BOI routine* 18 68 pp pp pp pp pushl $_parameter * push param* 23 e8 rr rr rr rr call _routine * call C routine* 28 68 pp pp pp pp pushl $_parameterEoi * push EOI param* 33 e8 rr rr rr rr call _routineEoi * call EOI routine* 38 83 c4 0c addl $12, %esp * pop param* 41 59 popl %ecx * restore regs* 42 5a popl %edx* 43 58 popl %eax* 44 e9 kk kk kk kk jmp _intExit * exit via kernel* .CE* * Third and fourth parameter of intHandlerCreateI86() are the BOI routine * address and its parameter that are inserted into the code as "routineBoi" * and "parameterBoi". * Fifth and sixth parameter of intHandlerCreateI86() are the EOI routine * address and its parameter that are inserted into the code as "routineEoi" * and "parameterEoi". * The BOI routine detects if this interrupt is stray/spurious/phantom by* interrogating the interrupt controller, and returns from the interrupt* if it is. The EOI routine issues End Of Interrupt signal to the * interrupt controller, if it is required by the controller. * Each interrupt controller has its own BOI and EOI routine. They are* located in the BSP, and their address and parameter are taken by the* intEoiGet function (set to sysIntEoiGet() in the BSP).* The Tornado 2, and later, BSPs should use the BOI and EOI mechanism with* intEoiGet function pointer.** To keep the Tornado 101 BSP backward compatible, the function pointer * intEOI is not removed. If intEoiGet is NULL, it should be set to the* sysIntEoiGet() routine in the BSP, intHandlerCreate() and the intEOI * function pointer (set to sysIntEOI() in the Tornado 101 BSP) is used.* * RETURNS: A pointer to the new interrupt handler, or NULL if memory* is insufficient.*/FUNCPTR intHandlerCreateI86 ( FUNCPTR routine, /* routine to be called */ int parameter, /* parameter to be passed to routine */ FUNCPTR routineBoi, /* BOI routine to be called */ int parameterBoi, /* parameter to be passed to routineBoi */ FUNCPTR routineEoi, /* EOI routine to be called */ int parameterEoi /* parameter to be passed to routineEoi */ ) { ... }/******************************************************************************** intVecSet2 - set a CPU vector, gate type(int/trap), and selector (x86)** This routine attaches an exception handler to a specified vector,* with the type of the gate and the selector of the gate. * The vector is specified as an offset into the CPU's vector table. This* vector table starts, by default, at address 0. * However, the vector table may be set to start at any address with* intVecBaseSet(). The vector table is set up in usrInit().** RETURNS: N/A** SEE ALSO: intVecBaseSet(), intVecGet(), intVecSet(), intVecGet2()*/void intVecSet2 ( FUNCPTR * vector, /* vector offset */ FUNCPTR function, /* address to place in vector */ int idtGate, /* IDT_TRAP_GATE or IDT_INT_GATE */ int idtSelector /* sysCsExc or sysCsInt */ ) { ... }/******************************************************************************** intVecGet2 - get a CPU vector, gate type(int/trap), and gate selector (x86)** This routine gets a pointer to the exception/interrupt handler attached* to a specified vector, the type of the gate, the selector of the gate. * The vector is specified as an offset into the CPU's vector table. * This vector table starts, by default, at address 0.* However, the vector table may be set to start at any address with* intVecBaseSet().** RETURNS: N/A** SEE ALSO: intVecBaseSet(), intVecGet(), intVecSet(), intVecSet2()*/void intVecGet2 ( FUNCPTR * vector, /* vector offset */ FUNCPTR * pFunction, /* address to place in vector */ int * pIdtGate, /* IDT_TRAP_GATE or IDT_INT_GATE */ int * pIdtSelector /* sysCsExc or sysCsInt */ ) { ... }/********************************************************************************* intStackEnable - enable or disable the interrupt stack usage (x86)** This routine enables or disables the interrupt stack usage and is only * callable from the task level. An Error is returned for any other calling * context. The interrupt stack usage is disabled in the default configuration* for the backward compatibility. Routines that manipulate the interrupt* stack, are located in the file i86/windALib.s. These routines include* intStackEnable(), intEnt() and intExit().** RETURNS: OK, or ERROR if it is not in the task level.*/STATUS intStackEnable ( BOOL enable /* TRUE to enable, FALSE to disable */ ) { ... }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -