📄 except.s
字号:
lwc1 f30, TcxFltF30(a0)
lwc1 f31, TcxFltF31(a0)
j ra
nop
.end RestoreFloatContext
#endif
LEAF_ENTRY(FirstSchedule)
.set reorder
la s0, KData
j resched
.end FirstSchedule
NESTED_ENTRY(GeneralExceptionP, 0, zero)
//++
//
// The following code is never executed. Its purpose is to support unwinding
// through the call to the exception dispatcher.
//
//--
.set noreorder
.set noat
sw sp,TcxIntSp(sp) // save stack pointer
sw 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
PROLOGUE_END
ALTERNATE_ENTRY(GeneralException)
.set noreorder
.set noat
mfc0 k0, epc // (k0) = resume address
#if NO_LL
bne zero, k1, 30f // interlocked operation restart
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
sw t0, SaveT0 // get a working register
#if R4100
andi t0, k1, 0xff // 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 -
#endif
// 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.
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
sw sp, TcxIntSp(t0)
sw gp, TcxIntGp(t0)
la sp, KStack
// Reenter here from nested exception setup.
10: sw k0, TcxFir(t0)
sw s0, TcxIntS0(t0)
move s0, t0 // (s0) = ptr to thread structure
sw v0, TcxIntV0(s0)
sw a0, TcxIntA0(s0)
and t0, k1, XCODE_MASK
bne t0, zero, 40f // not a h/w interrupt
lw t0, SaveT0 // restore T0
lw a0, BasePSR // (a0) = interrupt mask
sw a1, TcxIntA1(s0)
sw AT, TcxIntAt(s0)
.set at
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
sw a2, TcxIntA2(s0)
move k1, zero // reset atomic op. flag
lw v0, ISRTable(a0) // (v0) = interrupt handler
sw ra, TcxIntRa(s0) // save return address
mfc0 k0, psr
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
#ifdef CELOG
//
// NOTE : To make things relatively consistent, I'm going to make
// the registers v0, AT, a0-a3 available for use. On entry to CeLogInterruptMIPS
// A0 will contain the value to be logged (cNest + SYSINTR value)
//
// I'm assuming that at this point the only register of these that
// I need to preserve is V0 (ISR pointer)
//
move k0, v0 // save v0
jal CeLogInterruptMIPS
li a0, 0x80000000 // delay slot (a0 = mark as ISR entry)
move v0, k0 // restore v0
mfc0 k0, psr
#endif
#if R4000
// 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)
#elif R3000
ori k0, 1 << PSR_IEC // set int enable
#else
#error Unknown processor type
#endif
mtc0 k0, psr // enable interrupts
jal v0
sw a3, TcxIntA3(s0)
#if R4000
mfc0 a0, psr
ori a0, (1<<PSR_IE)
xori a0, (1<<PSR_IE)
mtc0 a0, psr // clear interrupt enable
#endif
lw a0, TcxPsr(s0)
nop
mtc0 a0, psr // now restore real psr, also toggling interrupt enable
.set noat
#if SYSINTR_NOP != 0
#error
#endif
#ifdef CELOG
//
// NOTE : To make things relatively consistent, I'm going to make
// the registers v0, AT, a0-a3 available for use. On entry to CeLogInterruptMIPS
// A0 will contain the value to be logged (cNest + SYSINTR value)
//
// I'm assuming that at this point the only register of these that
// I need to preserve is V0 (SYSINTR value)
//
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 CeLogInterruptMIPS
or a0, a0, v0 // delay slot (a0 = (-KNest << 16) | SYSINTR)
move v0, k0 // restore V0
#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, PendEvents
// The ISR has requested that an interrupt event be signalled
li a2, 1
sll a3, a2, v0
or a1, a1, a3
sw a1, PendEvents
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
lw AT, TcxIntAt(s0)
lw ra, TcxIntRa(s0)
lw a0, TcxIntA0(s0)
lw a1, TcxIntA1(s0)
lw a2, TcxIntA2(s0)
lw a3, TcxIntA3(s0)
lw k0, TcxFir(s0) // (k0) = exception return address
lw v0, TcxIntV0(s0) // restore return value
#if R4000
mtc0 k0, epc // restore EPC to interrupted stream
#endif
lw sp, TcxIntSp(s0) // restore stack pointer
lw gp, TcxIntGp(s0)
lw s0, TcxIntS0(s0)
#if R3000
j k0 // return to original caller
rfe // restore user status
#elif R4000
eret // restore user status
nop
nop
eret
#else
#error Unknown processor type
#endif
// 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
// 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) = start of sequence
// (k0) = exception PC
// (t0) = also start of sequence
#if NO_LL
30: bne t0, k1, 32f // go check for possible nested fault
nop
li k1, -1 // (k1) = -1 (in case fault loading instruction)
lw t6, (k0) // (t6) = interrupted instruction
lui t5, 0x03E0
ori t5, 0x0008 // (t5) = "J RA" INSTRUCTION
beq t6, t5, 1b // on the return instruction
nop // so no restart needed
b 1b
move k0, t0 // (k0) = restart address
// False interlocked trigger. If k1==-1, then the above interlocked api check
// generated a fault and we will just report the fault at the restart address.
//
// (t0) = interlocked api restart address.
32: addu k1, 1
bne k1, zero, 1b // not in NK's interlock code
nop
b 1b
move k0, t0 // report exception at 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
sw sp, TcxIntSp(t0) // save current stack ptr
move sp, t0
sw 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
// original V0, A0, S0, Sp, Gp, & EPC saved into thread struct
40: sw a1, TcxIntA1(s0)
sw a2, TcxIntA2(s0)
sw a3, TcxIntA3(s0)
sw ra, TcxIntRa(s0)
sw AT, TcxIntAt(s0)
mfc0 a2, badvaddr
// 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
and v0, k0, MODE_MASK // (v0) = thread's mode
#if R4000
// 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)
#elif R3000
ori k0, 1 << PSR_IEC // set int enable
#else
#error Unknown processor type
#endif
mtc0 k0, psr // enable interrupts
sw v0, TcxPsr(s0) // record the original mode in Thread struct
sw v1, TcxIntV1(s0)
sw t0, TcxIntT0(s0)
sw t1, TcxIntT1(s0)
sw t2, TcxIntT2(s0)
sw t3, TcxIntT3(s0)
mfhi t0
mflo t1
sw t4, TcxIntT4(s0)
sw t5, TcxIntT5(s0)
sw t6, TcxIntT6(s0)
sw t7, TcxIntT7(s0)
sw t8, TcxIntT8(s0)
sw t9, TcxIntT9(s0)
sw t0, TcxIntHi(s0) // save HI mul/div register
sw t1, TcxIntLo(s0) // save LO mul/div register
sw s1, TcxIntS1(s0)
sw s2, TcxIntS2(s0)
sw s3, TcxIntS3(s0)
sw s4, TcxIntS4(s0)
sw s5, TcxIntS5(s0)
sw s6, TcxIntS6(s0)
sw s7, TcxIntS7(s0)
sw s8, TcxIntS8(s0)
li t0, CONTEXT_CONTROL | CONTEXT_INTEGER
beq a1, zero, 50f
sw t0, TcxContextFlags(s0)
jal HandleException // jump to handler
move a0, s0 // (a0) = ptr to thread
bne v0, zero, 60f // resume current thread
nop
// The current thread has been blocked or a reschedule is pending.
// Save the remaining CPU state and call the scheduler to obtain the
// highest priority thread to run.
//
// (s0) = CurThdPtr.
resched:
50: lb t0, BPowerOff // if power off flag set
bne zero, t0, 90f
nop
51:
lh t0, ReschedFlag
beq zero, t0, 52f
nop
jal NextThread
sh zero, ReschedFlag // clear reschedule, still in kernel
52: lw s1, dwKCRes
beq zero, s1, 53f
nop
jal KCNextThread
sw zero, dwKCRes // clear KCreschedule
lw s1, dwKCRes
bne zero, s1, 51b
nop
53:
la t0, RunList
lw v0, 4(t0)
beq zero, v0, Idle // no threads to run, do idle processing
nop
beq s0, v0, 60f // resume current thread
move s0, v0 // (s0) = new current thread
lw t0, ThHandle(s0) // (t0) = thread's handle
sw s0, CurThdPtr // remember current THREAD pointer
sw t0, hCurThread // and current thread handle
lw t0, ThProc(s0) // (t0) = ptr to current process
lw t4, ThAKey(s0) // (t4) = thread's access key
lw v0, PrcHandle(t0) // (v0) = handle of current process
sw t0, CurPrcPtr // remember current process pointer
sw v0, hCurProc // and current process handle
lw t2, PrcVMBase(t0) // (t2) = memory section base address
lw t3, ThTlsPtr(s0)
srl t2, VA_SECTION-2 // (t2) = index into section table
sw t3, lpvTls
lw t2, SectionTable(t2) // (t2) = process's memory section
lb t0, PrcID(t0) // (t0) = process ID
sw t4, CurAKey // save access key for TLB handler
#if ENTRYHI_PID != 0
sll t0, ENTRYHI_PID
#endif
mtc0 t0, entryhi // set ASID
sw t2, SectionTable(zero) // swap in default process slot
// Restore the complete thread state.
//
// (s0) = ptr to thread structure
60: lw s1, TcxIntS1(s0) // Restore thread's permanent registers
lw s2, TcxIntS2(s0)
lw s3, TcxIntS3(s0)
lw s4, TcxIntS4(s0)
lw s5, TcxIntS5(s0)
lw s6, TcxIntS6(s0)
lw v0, TcxContextFlags(s0)
lw s7, TcxIntS7(s0)
andi v1, v0, CONTEXT_INTEGER & 0xFF
beq v1, zero, 65f
lw s8, TcxIntS8(s0)
lw t0, TcxIntHi(s0) // (t0) = HI mul/div register
lw t1, TcxIntLo(s0) // (t1) = LO mul/div register
mthi t0
mtlo t1
lw v1, TcxIntV1(s0)
lw t0, TcxIntT0(s0)
lw t1, TcxIntT1(s0)
lw t2, TcxIntT2(s0)
lw t3, TcxIntT3(s0)
lw t4, TcxIntT4(s0)
lw t5, TcxIntT5(s0)
lw t6, TcxIntT6(s0)
lw t7, TcxIntT7(s0)
lw t8, TcxIntT8(s0)
lw t9, TcxIntT9(s0)
lw AT, TcxIntAt(s0)
lw a0, TcxIntA0(s0)
lw a1, TcxIntA1(s0)
lw a2, TcxIntA2(s0)
lw a3, TcxIntA3(s0)
65: mtc0 zero, psr // all interrupts off!
nop
lw ra, TcxIntRa(s0)
lw v0, TcxIntV0(s0) // restore return value
lh k1, ReschedFlag // (k1) = resched + nested exception
li k0, 1
beq k1, k0, 68f // reschedule pending
addu k1, 256 // remove one level of nesting
sh k1, ReschedFlag
lw k0, BasePSR // (k0) = global default status value
lw k1, TcxPsr(s0) // (k1) = thread's default status
lw sp, TcxIntSp(s0) // restore stack pointer
or k1, k0 // (k1) = thread + global status
#ifdef MIPS_HAS_FPU
lw k0, g_CurFPUOwner
bne k0, s0, 66f
lui k0, 0x2000
or k1, k0
66:
#endif
mtc0 k1, psr // restore status
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -