📄 except.s
字号:
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LEAF_ENTRY(FirstSchedule)
.set reorder
la s0, KData
j resched
.end FirstSchedule
//------------------------------------------------------------------------------
//
// The following code is never executed. Its purpose is to support unwinding
// through the call to the exception dispatcher.
//
//------------------------------------------------------------------------------
NESTED_ENTRY(GeneralExceptionP, 0, zero)
.set noreorder
.set noat
S_REG sp,TcxIntSp(sp) // save stack pointer
S_REG ra,TcxIntRa(sp) // save return address
sw ra,TcxFir(sp) // save return address
sw gp,TcxIntGp(sp) // save integer register gp
sw s0,TcxIntS0(sp) // save S0
move s0, sp // set pointer to thread
S_REG gp,TcxIntGp(sp) // save integer register gp
S_REG s0,TcxIntS0(sp) // save S0
move s0, sp // set pointer to thread
PROLOGUE_END
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ALTERNATE_ENTRY(GeneralException)
.set noreorder
.set noat
mfc0 k0, epc // (k0) = resume address
#if NO_LL
bne zero, k1, 30f // Check if interlock operation is in progress
nop
#endif
1: ori k1, k0, 0xFFFC // (k1) = 0xFFFFFFFE iff an API call
addu k1, 2 // (k1) = 0 iff an API call
beq zero, k1, 200f // go process an API call or API return
mfc0 k1, cause // (k1) = exception cause
S_REG t0, SaveT0 // get a working register
lw t0, IsR41XX // is this R41XX?
beqz t0, 3f
andi t0, k1, 0xff // (in delay slot, but okay) ignore exception b's - We're getting extraneous exception B's
xori t0, t0, 0x2c // ignore exception b's - ignore them
beq t0, zero, 104f // ignore exception b's -
//
// The read and write miss codes differ by exactly one bit such that they
// can be tested for by a single mask operation followed by a test for the
// read miss code.
//
3:
and t0,k1,MISS_MASK // isolate exception code
xori t0,XCODE_READ_MISS // get exception code for read miss
beq t0,zero,100f // read or write TLB miss
5: lb t0, KNest // (t0) = reentrancy count
subu t0, 1
bne zero, t0, 35f // nested exception
sb t0, KNest
lw t0, CurThdPtr // (t0) = ptr to current thread
S_REG sp, TcxIntSp(t0)
S_REG gp, TcxIntGp(t0)
la sp, KStack
//
// Reenter here from nested exception setup.
//
10: sw k0, TcxFir(t0)
S_REG s0, TcxIntS0(t0)
move s0, t0 // (s0) = ptr to thread structure
S_REG v0, TcxIntV0(s0)
S_REG a0, TcxIntA0(s0)
//
// ISR is now 'cooked'. i.e. ISR can now be written in C, instead of assembly only.
// save all volatile registers..
//
S_REG v1, TcxIntV1(s0)
L_REG t0, SaveT0 // restore T0
S_REG t1, TcxIntT1(s0)
S_REG t2, TcxIntT2(s0)
S_REG t3, TcxIntT3(s0)
S_REG t0, TcxIntT0(s0)
mfhi t1
mflo t2
S_REG t4, TcxIntT4(s0)
S_REG t5, TcxIntT5(s0)
S_REG t6, TcxIntT6(s0)
S_REG t7, TcxIntT7(s0)
and t0, k1, XCODE_MASK
S_REG t8, TcxIntT8(s0)
S_REG t9, TcxIntT9(s0)
S_REG t1, TcxIntHi(s0) // save HI mul/div register
S_REG t2, TcxIntLo(s0) // save LO mul/div register
S_REG a2, TcxIntA2(s0)
S_REG ra, TcxIntRa(s0) // save return address
S_REG AT, TcxIntAt(s0)
S_REG a3, TcxIntA3(s0)
bne t0, zero, 40f // not a h/w interrupt
S_REG a1, TcxIntA1(s0) // (delay slot) save a1
.set at
lw a0, BasePSR // (a0) = interrupt mask
subu sp, 4*REG_SIZE // reserver space
// for 4 registers per C calling
// convention
and a0, k1 // (a0) = bits 15-10 pending interrupts
srl a0, CAUSE_INTPEND+2
and a0, 0x3F // (a0) = hw interrupt cause bits
lb a0, IntrPriority(a0) // (a0) = highest pri interrupt * 4
move k1, zero // reset atomic op. flag
mfc0 k0, psr
lw v0, ISRTable(a0) // (v0) = interrupt handler
sw k0, TcxPsr(s0)
sra a0, 2 // Keep the sign for spurious interrupts
addi a0, 1
lbu a0, IntrMask(a0)
sll a0, 10
not a0
and k0, k0, a0
mtc0 k0, psr
#if defined(NKPROF)
//
// NOTE : The only volatile register that we need to save/restore is v0 since it holds
// the ISR function to call.
//
move k0, v0 // save v0
jal CeLogInterrupt
li a0, 0x80000000 // delay slot (a0 = mark as ISR entry)
move v0, k0 // restore v0
mfc0 k0, psr
#endif // NKPROF
// clear User mode, EXL & ERL bits in PSR
ori k0, (1<<PSR_EXL) | (1<<PSR_ERL) | (1<<PSR_PMODE)
xori k0, (1<<PSR_EXL) | (1<<PSR_ERL) | (1<<PSR_PMODE)
jal v0 // Call OEM ISR
mtc0 k0, psr // (delay slot) enable interrupts
// call the ISR hook (pfnOEMIntrOccurs is set to a faked function if not changed by OEM)
lw a1, pfnOEMIntrOccurs // a1 = pfnOEMIntrOccurs
jal a1 // call pfnOEMIntrOccurs
move a0, v0 // (delay slot) (a0) = SYSINTR == parameter to pfnOEMIntrOccurs
mfc0 a0, psr
ori a0, (1<<PSR_IE)
xori a0, (1<<PSR_IE)
mtc0 a0, psr // clear interrupt enable
lw a0, TcxPsr(s0)
nop
mtc0 a0, psr // now restore real psr, also toggling interrupt enable
.set noat
#if defined(NKPROF)
//
// NOTE : The only volatile register that we need to save/restore is v0 since it holds
// the return value of ISR.
//
move k0, v0 // save V0
lb a0, KNest // (a0) = nest level (0, -1, -2, etc)
sub a0, zero, a0 // (a0) = nest level (0, 1, 2, etc)
sll a0, a0, 16 // (a0) = (a0) << 16
jal CeLogInterrupt
or a0, a0, v0 // delay slot (a0 = (-KNest << 16) | SYSINTR)
move v0, k0 // restore V0
#endif // NKPROF
addu sp, 4*REG_SIZE // reclaim the stack space
#if SYSINTR_NOP != 0
#error
#endif
beq v0, zero, 20f // return == SYSINTR_NOP
li a3, SYSINTR_BREAK
beq v0, a3, 25f // debug break interrupt
subu v0, SYSINTR_DEVICES
bltz v0, 15f // not device signal, treat as reschedule
sltu a3, v0, SYSINTR_MAX_DEVICES
beq a3, zero, 20f // out of range, ignore
lw a1, PendEvents1 // (a1) = PendEvent1
// The ISR has requested that an interrupt event be signalled
subu a3, v0, 32 // (a3) = (ISR requested - 32)
bgez a3, 27f // handle ISR requested >= 32 if (a3) >= 0
li a2, 1 // (delay slot) (a2) = 1
// ISR requested < 32
sllv a3, a2, v0 // (a3) = 1 << ISR#
or a1, a1, a3 // (a1) = PendEvents1 | (1 << ISR#)
sw a1, PendEvents1 // Update PendEvents1
15: lb v0, ReschedFlag
or v0, 1
sb v0, ReschedFlag // set reschedule flag
// Interrupt processing is complete. If the reschedule flag has been set and
// this is not a nested exception, then save the full thread context and
// obtain a new thread to run.
20: lh k0, ReschedFlag // (k0) = resched + nested exception
li a0, 1
beq k0, a0, 41f // reschedule needed
move k1, zero // (k1) = 0 (no atomic op in progress)
addu k0, 256 // remove one level of nesting
sh k0, ReschedFlag // save updated nest info
L_REG t0, TcxIntHi(s0) // save HI mul/div register
L_REG t1, TcxIntLo(s0) // save LO mul/div register
L_REG AT, TcxIntAt(s0)
L_REG ra, TcxIntRa(s0)
L_REG a0, TcxIntA0(s0)
L_REG a1, TcxIntA1(s0)
L_REG a2, TcxIntA2(s0)
L_REG a3, TcxIntA3(s0)
mthi t0
mtlo t1
lw k0, TcxFir(s0) // (k0) = exception return address
L_REG v0, TcxIntV0(s0) // restore return value
L_REG v1, TcxIntV1(s0)
L_REG t0, TcxIntT0(s0)
L_REG t1, TcxIntT1(s0)
L_REG t2, TcxIntT2(s0)
L_REG t3, TcxIntT3(s0)
L_REG t4, TcxIntT4(s0)
L_REG t5, TcxIntT5(s0)
L_REG t6, TcxIntT6(s0)
L_REG t7, TcxIntT7(s0)
L_REG t8, TcxIntT8(s0)
L_REG t9, TcxIntT9(s0)
mtc0 k0, epc // restore EPC to interrupted stream
// MUST use lw instead of L_REG so sp get automatic sign extension.
// The reason is that we do arithmetics on SP during exception handling
// and SP can become a positive 64 bit value.
lw sp, TcxIntSp(s0) // restore stack pointer
L_REG gp, TcxIntGp(s0)
L_REG s0, TcxIntS0(s0)
eret // restore user status
nop
nop
eret
//
// HW Break button pushed. Pass an exception to the debugger.
//
25: li k1, 1 // (k1) = cause (1 for h/w break)
j 41f // route into vanilla exception path
move a2, zero // clear BadVAddr for exception handler
// ISR # >= 32
// (a2) = 1
// (a3) = ISR# - 32
27: lw a1, PendEvents2 // (a1) = PendEvents2
sllv a3, a2, a3 // (a3) = 1 << (ISR#-32)
or a1, a1, a3 // (a1) = PendEvents2 | 1 << (ISR#-32)
b 15b // reschedule
sw a1, PendEvents2 // (delay slot) Update PendEvents2
//
// An atomic instruction sequence was interrupted. Check if we are past the
// store instruction and reset the EPC back to the starting point if not.
// Note that since we know what the interrupted stream is it is safe to
// trash certain registers.
//
// this code needs to be more careful about addressing user memory!
//
// (k1) = address of "IXXXDone"
// (k0) = exception PC
// (t0) = beginning of Interlocked funciton
//
#if NO_LL
//
// if ((k1 != 0) && (k1 != epc)) {
// epc = t0; // actuall, change k0 which holds epc
// }
30: beq k0, k1, 1b // If (epc == k1)
nop // done, don't restart
//
// Interlock operation in progress, reset restart address
//
b 1b
move k0, t0 // (k0) = restart address
#endif
// A nested exception has occured. If this a h/w interrupt, create a temporary
// thread structure on the stack and save the current state into that.
35: subu t0, sp, TcxSizeof // (t0) = ptr to dummy kernel thread
S_REG sp, TcxIntSp(t0) // save current stack ptr
move sp, t0
S_REG gp, TcxIntGp(t0)
j 10b
sw zero, ThPcstkTop(t0) // clear call stack pointer
// Handle an exception which is not a h/w interrupt nor an API call.
//
// (k1) = cause
// (s0) = ptr to thread structure
// all volatile registers saved
40: mfc0 a2, badvaddr // (a2) = fault address
// Interrupt reschedules enter here to save register context.
//
// (k1) = exception cause (0 if resched, 1 if h/w break button)
41: mfc0 k0, psr // (k0) = processor status
move a1, k1 // (a1) = exception cause
move k1, zero // no interlocked api in progress
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -