📄 except.s
字号:
151: lw k1, 8(t0) // (k1) = MapArray[i].VAEnd
sltu k1, k0, k1 // (k1) = (badaddr < MapArray[i].VAEnd)
beqz k1, 151b // continue if not
addu t0, 12 // (delay slot) i ++
// (k0) = badaddr
// (t0) = one entry past the possible one (need to check VA start)
lw k1, -12(t0) // (k1) = VAStart
subu k1, k0, k1 // (k1) = (badaddr - VaStart)
bltz k1, 125b // fault if (badaddr < VaStart)
lw t0, -8(t0) // (delay slot) (t0) = TLB Entry for Base PA
// (k1) = (badaddr - VaStart)
// (t0) = TLB Entry for Base PA
srl k1, VA_PAGE+1 // clear the lower 13 bits to make the even page number
lw k0, TlbShift // (k0) = (VA_PAGE+1) - PFN_SHIFT
sllv k1, k1, k0 // (k1) = (# of even pages) >> PFN_SHIFT
addu t0, t0, k1 // (t0) = even page number
lw k0, PfnIncr // (k0) = PFN_INCR
b 102b // back to normal routine updating TLB
add k0, k0, t0 // (delay slot) (k0) = odd page number
.end GeneralExceptionP
//------------------------------------------------------------------------------
// Stack structure during API call processing.
.struct 0
_apiArg: .space 4 * REG_SIZE // argument register save area (call standard, room fo 4 registers)
apiSaveRet: .space REG_SIZE // return value
_filler_: .space 4 // padding. make 8 bytes aligned for MIP32
objcallstr:
apiMethod: .space 4 // API method
svrrtnstr:
apiPrevSP: .space 4 // previous SP if stack changed
apiMode: .space 4 // (pMode) argument
apiSaveGp: .space 4 // extra cpu dependent info (Global Pointer)
apiSaveRA: .space 4 // return address
size_api_args: // length of stack frame
apiArg0: .space REG_SIZE // caller argument save area
apiArg1: .space REG_SIZE
apiArg2: .space REG_SIZE
apiArg3: .space REG_SIZE
//------------------------------------------------------------------------------
// The following code is never executed. Its purpose is to support unwinding
// through the calls to ObjectCall or ServerCallReturn.
//------------------------------------------------------------------------------
NESTED_ENTRY(APICall, 0, zero)
.set noreorder
.set noat
subu sp, size_api_args
sw ra, apiSaveRA(sp) // unwinder: (ra) = APICallReturn
PROLOGUE_END
//
// Process an API Call or return.
//
// (k0) = EPC (encodes the API set & method index)
//
200: lb t0, KNest // (t0) = kernel nest depth
mfc0 t1, psr // (t1) = processor status
blez t0, 5b // non-preemtible, API Calls not allowed
subu t0, k0, FIRST_METHOD
lw t3, BasePSR
move k1, zero // reset atomic op. flag
or t3, 1 // (t3) = current interrupt mask + int enable
#ifdef MIPS_HAS_FPU
lw t8, g_CurFPUOwner
lw t7, CurThdPtr
bne t7, t8, 201f
nop
la t9, dwNKCoProcEnableBits
lw t9, (t9)
or t3, t9
201:
#endif
mtc0 t3, psr // enable interrupts
#if APICALL_SCALE == 2
sra t0, 1 // (t0) = method index
#elif APICALL_SCALE == 4
sra t0, 2 // (t0) = method index
#else
#error Invalid value for APICALL_SCALE
#endif
addu t3, t0, 1 // (t3) = 0 if return from CALLBACK
beq zero, t3, MD_CBRtn
and t1, MODE_MASK // (t1) = thread's execution mode (delay slot)
and t2, t1, 1 << PSR_PMODE
beq t2, zero, KPSLCall // calling from kernel mode if = 0
li t4, 0 // (t4) = prevSP, init to 0 (delay slot)
// PSL call from User Mode
// (t0) = iMethod
// (t1) = caller's mode
// special case RaiseException
li t2, RAISEEXCEPTION
beq t0, t2, PSLCallCommon // do not switch stack if it's RaiseException
// check trust level
lw t3, CurPrcPtr // (t3) = pCurProc (in delay slot, okay to execute if branch taken)
lb t3, PrcTrust(t3) // (t3) = pCurProc->bTrustLevel
li t2, KERN_TRUST_FULL // (t2) = KERN_TRUST_FULL
beq t2, t3, PSLCallCommon // go to common code if fully trusted
nop
// not fully trusted, need to perform stack switch
lw t3, CurThdPtr // (t3) = pCurThread
lw t2, ThTlsSecure(t3) // (t2) = pCurThread->tlsSecure
sw t2, ThTlsPtr(t3) // pCurThread->tlsPtr = pCurThread->tlsSecure
sw t2, lpvTls // update TLS in KPAGE
// find the 'real' stack top (exception handler might put in faked ones)
lw t3, ThPcstkTop(t3) // (t3) = pCurThread->pcstkTop
move t4, sp // (t4) = caller's SP (delay slot)
subu sp, t2, SECURESTK_RESERVE // init new SP to be (tlsptr - reserve)
NextCStk:
beq t3, zero, CopyStack // start copying if no call stack
move t6, t3 // (t6) == current pcstk (delay slot)
lw t5, CstkAkyLast(t6) // akyLast == 0 if exception handler put it in
beq t5, zero, NextCStk // get to next pcstk if akyLast == 0
lw t3, CstkNext(t6) // (t3) == pcstk->pcstkNext (delay slot)
// found a callstack, update sp (DEBUGCHK (pcstk->dwPrevSP != 0))
lw sp, CstkPrevSP(t6)
CopyStack:
// copy arguments from caller stack to the new stack
// (t4) == old SP
// (sp) == new SP
subu sp, MAX_PSL_ARGS // MAX_PSL_ARGS == 56
// don't need to copy the 1st 4 since they are in register
L_REG t2, 4 * REG_SIZE(t4)
L_REG t3, 5 * REG_SIZE(t4)
L_REG t5, 6 * REG_SIZE(t4)
L_REG t6, 7 * REG_SIZE(t4)
S_REG t2, 4 * REG_SIZE(sp)
S_REG t3, 5 * REG_SIZE(sp)
S_REG t5, 6 * REG_SIZE(sp)
S_REG t6, 7 * REG_SIZE(sp)
L_REG t2, 8 * REG_SIZE(t4)
L_REG t3, 9 * REG_SIZE(t4)
L_REG t5, 10 * REG_SIZE(t4)
L_REG t6, 11 * REG_SIZE(t4)
S_REG t2, 8 * REG_SIZE(sp)
S_REG t3, 9 * REG_SIZE(sp)
S_REG t5, 10 * REG_SIZE(sp)
S_REG t6, 11 * REG_SIZE(sp)
L_REG t2, 12 * REG_SIZE(t4)
L_REG t3, 13 * REG_SIZE(t4)
S_REG t2, 12 * REG_SIZE(sp)
b PSLCallCommon
S_REG t3, 13 * REG_SIZE(sp) // (delay slot)
KPSLCall:
// calling from KMODE, check PerformCallBack
// (t0) = method
// (t1) = KERNEL_MODE
// (t4) = 0
li t3, PERFORMCALLBACK
beq t0, t3, DoPerformCallBack
nop
PSLCallCommon:
// (t0) = iMethod
// (t1) = caller's mode
// a0-a3 = arguments
// (t4) = previous SP
subu sp, size_api_args // make room for new args + temps
// Save api arguments onto the stack
S_REG a0, apiArg0(sp)
S_REG a1, apiArg1(sp)
S_REG a2, apiArg2(sp)
S_REG a3, apiArg3(sp)
// setup ObjectCall arguments
sw t1, apiMode(sp) // what mode we're from
sw t4, apiPrevSP(sp) // previous AP
sw t0, apiMethod(sp) // method
sw ra, apiSaveRA(sp) // return address
jal ObjectCall
addu a0, sp, objcallstr // (a0) = ptr to OBJCALLSTRUCT (delay slot)
//
// Invoke server function. If the thread is running in kernel mode, then
// we just call the function directly from here.
//
// (v0) = address of server function
//
L_REG a0, apiArg0(sp) // reload argument registers.
L_REG a1, apiArg1(sp)
L_REG a2, apiArg2(sp)
L_REG a3, apiArg3(sp)
// always run PSL calls in KMODE
jal v0
addu sp, size_api_args // remove extra stuff from the stack
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ALTERNATE_ENTRY(APICallReturn)
subu sp, size_api_args // recreate entry frame
//
// (v0) = api return value (must be preserved)
S_REG v0, apiSaveRet(sp) // save return value
jal ServerCallReturn
addu a0, sp, svrrtnstr // (a0) = ptr to SVRRTNSTRUCT (delay slot)
lw t0, apiMode(sp) // (t0) = mode to return to
move ra, v0 // (ra) = return address
and t1, t0, 1 << PSR_PMODE
beq t1, zero, 255f // returning to kernel mode
L_REG v0, apiSaveRet(sp) // restore return value (delay slot)
//
// return to user mode, check trust level and switch stack if necessary
//
lw t2, apiPrevSP(sp) // (t2) = previous SP
beq t2, zero, UPSLRtnCommon // go to common code if prevsp == 0
move t4, ra // (t4) = user mode return address (delay slot)
// need to perform stack switch
// (t2) = previous SP
lw t1, CurThdPtr // (t1) = pCurThread
lw t3, ThTlsNonSecure(t1) // (t3) = pCurThread->tlsNonSecure
sw t3, ThTlsPtr(t1) // pCurThread->tlsPtr = pCurThread->tlsNonSecure
sw t3, lpvTls // update TLS in KPAGE
subu sp, t2, size_api_args // (restore SP, but subtract siz_api_args, will be add back later
UPSLRtnCommon:
//
// Return to user mode. To do this: build a new PSR value from the thread's mode
// and BasePSR. This must be done with interrupts disabled so that BasePSR is not
// changing.
//
// (t0) = new mode bits
// (t4) = return address
//
CP0_STOP_PREFETCH(mtc0, zero, psr, t1); // all interrupts off
nop // 3 cycle hazard
nop
addu sp, size_api_args
lw t1, BasePSR
mtc0 t4, epc
#ifdef MIPS_HAS_FPU
lw t8, g_CurFPUOwner
lw t7, CurThdPtr
bne t7, t8, 251f
nop
la t9, dwNKCoProcEnableBits
lw t9, (t9)
or t1, t9
251:
#endif
or t1, t0 // (t1) = merged status
mtc0 t1, psr // reload status
ssnop
ssnop // super scalar core requires 4 integer
ssnop // instructions to guarantee
ssnop // a 2 cycle hazard
eret
// Return to kernel mode.
255: j ra
addu sp, size_api_args // remove extra stuff from the stack (delay slot)
DoPerformCallBack:
// (t1) = caller's mode
// a0-a3 = arguments
subu sp, size_api_args // make room for new args + temps
// Save api arguments and ra onto the stack
S_REG a0, apiArg0(sp)
S_REG a1, apiArg1(sp)
S_REG a2, apiArg2(sp)
S_REG a3, apiArg3(sp)
// setup PerformCallbackExt arguments
sw t1, apiMode(sp)
addu t3, sp, size_api_args // (t3) == original SP
sw t3, apiPrevSP(sp)
sw ra, apiSaveRA(sp)
// call PerformCallBackExt
jal PerformCallBackExt
addu a0, sp, objcallstr // (arg0) == ptr to OBJCALLSTRUCT (delay slot)
// v0 == function to call
// restore arguments and return address
L_REG a0, apiArg0(sp)
L_REG a1, apiArg1(sp)
L_REG a2, apiArg2(sp)
L_REG a3, apiArg3(sp)
move t4, v0 // (t4) = function to call
// check if need stack switch
lw t3, apiPrevSP(sp) // (t3) == new SP if != 0
beq t3, zero, CBCommon
lw t0, apiMode(sp) // (t0) == mode to call to (delay slot)
// stack switch is required...
// (t0) = mode to return to
// (t3) = new SP
// (t4) = function to call
// must save callee saved registers in secure stack or security risk.
// NOTE: must do this before updating sp and tls, or DemmandCommit might fail
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -