📄 intarchlib.c
字号:
* 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'.** NOTE ARM:* 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>.** NOTE X86:* Refer to the special x86 routine intHandlerCreateI86().* * NOTE SH:* 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:** .CS* #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);* ...* }* .CE** The used vector numbers of SH processors are limited to certain ranges,* depending on the processor type. The `sysInumVirtBase' should be initialized* to a value higher than the last used vector number, defined as INUM_INTR_HIGH.* It is typically safe to set `sysInumVirtBase' to (INUM_INTR_HIGH + 1).** The sysIntConnect() routine 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'.** RETURNS: OK, or ERROR if the interrupt handler cannot be built.** SEE ALSO: intHandlerCreate(), intVecSet()*/STATUS intConnect ( VOIDFUNCPTR * vector, /* interrupt vector to attach to */ VOIDFUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ ) { ... }/********************************************************************************* intHandlerCreate - construct an interrupt handler for a C routine (MC680x0, x86, MIPS, SimSolaris)** 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.** RETURNS: A pointer to the new interrupt handler, or NULL if memory * is insufficient.* */FUNCPTR intHandlerCreate ( FUNCPTR routine, /* routine to be called */ int parameter /* parameter to be passed to routine */ ) { ... }/********************************************************************************* intLockLevelSet - set the current interrupt lock-out level (MC680x0, x86, ARM, SH, SimSolaris, SimNT)* * 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,* x86 = 1, SH = 15) is initially set by kernelInit() when* VxWorks is initialized.** NOTE SIMSOLARIS, SIMNT:* This routine does nothing.** NOTE ARM:* On the ARM, this call establishes the interrupt level to be set when* intLock() is called.** RETURNS: N/A* * SEE ALSO: intLockLevelGet(), intLock(), taskLock()*/void intLockLevelSet ( int newLevel /* new interrupt level */ ) { ... }/********************************************************************************* intLockLevelGet - get the current interrupt lock-out level (MC680x0, x86, ARM, SH, SimSolaris, SimNT)* * 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, x86 = 1, SH = 15)* is initially set by kernelInit() when VxWorks is initialized.** NOTE SIMNT:* This routine does nothing.** RETURNS: The interrupt level currently stored in the interrupt* lock-out mask. (ARM = ERROR always)** SEE ALSO: intLockLevelSet()*/int intLockLevelGet (void) { ... }/********************************************************************************* intVecBaseSet - set the vector (trap) base address (MC680x0, x86, MIPS, ARM, SimSolaris, SimNT)** 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, until modified by calls to this routine.** \"NOTE SPARC:* \"On SPARC processors, the vector base address must be on a 4 Kbyte boundary* \"(that is, its bottom 12 bits must be zero).* \"* NOTE 68000:* The 68000 has no vector base register; thus, this routine is a no-op for* 68000 systems.** \"NOTE I960:* \"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.* \"* NOTE MIPS:* The MIPS processors have no vector base register;* thus this routine is a no-op for this architecture.** NOTE SH77XX:* 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().** NOTE ARM:* The ARM processors have no vector base register;* thus this routine is a no-op for this architecture.** NOTE SIMSOLARIS, SIMNT:* This routine does nothing.** RETURNS: N/A** SEE ALSO: intVecBaseGet(), intVecGet(), intVecSet()*/void intVecBaseSet ( FUNCPTR * baseAddr /* new vector (trap) base address */ ) { ... }/********************************************************************************* intVecBaseGet - get the vector (trap) base address (MC680x0, x86, MIPS, ARM, SimSolaris, SimNT)** This routine returns the current vector base address, which is set* with intVecBaseSet().** RETURNS: The current vector base address* (MIPS = 0 always, ARM = 0 always, SimSolaris = 0 always and * SimNT = 0 always).** SEE ALSO: intVecBaseSet()*/FUNCPTR *intVecBaseGet (void) { ... }/******************************************************************************** intVecSet - set a CPU vector (trap) (MC680x0, x86, MIPS, SH, SimSolaris, SimNT)** 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:* * .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). The vector table is* set up in usrInit().** 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 SPARC:* \"This routine generates code to:* \".IP (1) 4* \"save volatile registers;* \".IP (2)* \"fix possible window overflow;* \".IP (3)* \"read the processor state register into register %L0; and * \".IP (4)* \"jump to the specified address.* \".LP* \"* 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.** \"NOTE I960:* \"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.* \"* NOTE MIPS:* On MIPS CPUs the vector table is set up statically in software.** NOTE SH77XX:* The specified interrupt handler <function> has to coordinate with an interrupt* stack frame which is specially designed for SH77XX version of VxWorks:**.CS* [ 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)* | |*.CE** 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -