📄 except.s
字号:
// TITLE("Interrupt and Exception Processing")
//++
//
// Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
//
// Module Name:
//
// except.s
//
// Abstract:
//
// This module implements the code necessary to field and process MIPS
// interrupt and exception conditions.
//
// WARNING: This module executes in KSEG0 and, in general, cannot
// tolerate a TLB Miss. Registers k0 and k1 are used during initial
// interrupt and exception processing, and therefore, extreme care must
// be exercised when modifying this module.
//
//--
#include "ksmips.h"
#include "nkintr.h"
#include "kpage.h"
#include "mem_mips.h"
#include "psyscall.h"
#include "xtime.h"
.text
.globl PtrCurMSec
PtrCurMSec: .word AddrCurMSec
PosTable:
.byte 0,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
.byte 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
.byte 7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
.byte 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
.byte 8,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
.byte 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
.byte 7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
.byte 6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
LEAF_ENTRY (GetHighPos)
.set noreorder
addi t0, zero, -1
andi t1, a0, 0xff
lb v0, PosTable(t1)
bne zero, v0, res
srl a0, a0, 8
addi t0, t0, 8
andi t1, a0, 0xff
lb v0, PosTable(t1)
bne zero, v0, res
srl a0, a0, 8
addi t0, t0, 8
andi t1, a0, 0xff
lb v0, PosTable(t1)
bne zero, v0, res
srl a0, a0, 8
addi t0, t0, 8
andi t1, a0, 0xff
lb v0, PosTable(t1)
bne zero, v0, res
nop
addi v0, v0, 9
res:
j ra
add v0, v0, t0
.end GetHighPos
LEAF_ENTRY(INTERRUPTS_ON)
.set noreorder
lw t0, BasePSR
nop
or t0, 1
j ra
mtc0 t0, psr
.end INTERRUPTS_ON
LEAF_ENTRY(INTERRUPTS_OFF)
.set noreorder
mtc0 zero, psr
nop // 3 cycle delay
j ra
nop
.end INTERRUPTS_OFF
LEAF_ENTRY(SetCPUHardwareWatch)
.set noreorder
lui t0, 0x7fff
ori t0, t0, 0xfff8
and a0, a0, t0
or a0, a0, a1
mtc0 a0, $18
nop
nop
mtc0 zero, $19
nop
nop
j ra
nop
.end SetCPUHardwareWatch
LEAF_ENTRY(SetCPUASID)
.set noreorder
#ifdef CELOG
//
// NOTE : To make things relatively consistent, I'm going to make
// the registers v0, t0-t9, a0, a1 available for use. On entry to
// CeLogThreadMigrateMIPS, a0 will contain the handle of the new process.
//
// I'm assuming that at this point the only registers of these that
// I need to preserve are A0 and RA.
//
lw t0, ThProc(a0) // (t0) = ptr to new process
lw t1, PrcHandle(t0) // (t1) = handle of new process
lw t0, hCurProc // (t0) = current process handle
beq t0, t1, celog10 // if procs are equal then skip CeLog call
nop
subu sp, 8 // adjust sp
sw ra, 0(sp) // save RA
sw a0, 4(sp) // save arg
move a0, t1 // (a0) = handle of new process
jal CELOG_ThreadMigrateMIPS
nop
lw ra, 0(sp) // restore RA
lw a0, 4(sp) // restore arg
addu sp, 8 // adjust sp
celog10:
#endif
lw t0, ThProc(a0) // (t0) = ptr to current process
lw t1, ThAKey(a0) // (t1) = thread's access key
lw t2, PrcHandle(t0) // (t2) = handle of current process
sw t0, CurPrcPtr // remember current process pointer
sw t2, hCurProc // remember current process handle
lw t2, PrcVMBase(t0) // (t2) = memory section base address
lb t0, PrcID(t0) // (t0) = process ID
srl t2, VA_SECTION-2 // (t2) = index into section table
lw t2, SectionTable(t2) // (t2) = process's memory section
sw t1, CurAKey // save access key for TLB handler
#if ENTRYHI_PID != 0
sll t0, ENTRYHI_PID
#endif
mtc0 t0, entryhi // set ASID
j ra
sw t2, SectionTable(zero) // swap in default process slot
.end SetCPUASID
NESTED_ENTRY(xKCall, 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,20(sp) // save stack pointer
sw ra,16(sp) // save return address
PROLOGUE_END
ALTERNATE_ENTRY(KCall)
// KCall - call kernel function
//
// KCall invokes a kernel function in a non-preemtable state by incrementing
// the kernel nest level and switching onto a kernel stack.
//
// While in a preemtible state, the thread's register save area is
// volatile. On the way in, nothing can be saved into the thread
// structure until KNest is set and on the way out anything needed from the
// thread structure must be loaded before restoring KNest.
//
// The sequence of stack switching must be handled carefully because
// whenever KNest != 1, the general exception handler assumes that the kernel
// stack is current and will not switch stacks. On the way in, we must switch
// to the kernel stack before setting KNest but not use it until after KNest
// is set. On the way out, we must reset KNest before restoring the thread's
// stack pointer.
//
// Entry (a0) = ptr to function to call
// (a1) = first function arg
// (a2) = second fucntion arg
// (a3) = third function arg
// Exit (v0) = function return value
// Uses v0, a0-a3, t0-t9
.set noreorder
move t0, a0 // (t0) = ptr to function to call
lh t1, ReschedFlag // (t1) = resched flag + nest level
move a0, a1 // ripple args down
move a1, a2
subu t1, 256
bltz t1, 50f // nested kernel call
move a2, a3
// Entering non-preemptible state. We must switch onto the kernel stack
// before setting KNest in case an interrupt occurs during the switch.
move t2, sp // (t2) = original stack pointer
la sp, KStack // switch to kernel stack
sh t1, ReschedFlag // enter non-preemtible state
sw ra, 16(sp) // thread will resume at return address
jal t0
sw t2, 20(sp) // save thread's stack pointer
// Function complete. Return to preemtible state after checking if a reschedule
// is needed.
mtc0 zero, psr
nop
nop
nop
lh t9, ReschedFlag // (t9) = resched flag + nest level
li t1, 1
beq t9, t1, 20f // reschedule needed
lw ra, 16(sp) // (ra) = return address
lw t2, dwKCRes
bne t2, zero, 20f // reschedule needed
nop
lw t2, 20(sp) // (t2) = original stack pointer
addu t9, 256
sh t9, ReschedFlag // leave non-preemtible state
lw t9, BasePSR
or t9, 1
#ifdef MIPS_HAS_FPU
lw t8, g_CurFPUOwner
lw t7, CurThdPtr
bne t7, t8, 19f
lui t8, 0x2000
or t9, t8
19:
#endif
mtc0 t9, psr
j ra
move sp, t2 // restore stack pointer
// ReschedFlag set, so must run the scheduler to find which thread
// to dispatch next.
//
// (v0) = KCall return value
20:
lw t9, BasePSR
or t9, 1
mtc0 t9, psr
lw t0, CurThdPtr // (t0) = ptr to current thread
lw t2, 20(sp) // (t2) = original stack pointer
li t3, KERNEL_MODE
sw ra, TcxFir(t0) // thread will resume at return address
sw t3, TcxPsr(t0) // & in kernel mode
sw t2, TcxIntSp(t0) // save stack pointer
sw v0, TcxIntV0(t0) // save return value
sw s0, TcxIntS0(t0) // save thread's permanent registers
sw s1, TcxIntS1(t0) // ...
sw s2, TcxIntS2(t0) // ...
sw s3, TcxIntS3(t0) // ...
sw s4, TcxIntS4(t0) // ...
sw s5, TcxIntS5(t0) // ...
sw s6, TcxIntS6(t0) // ...
sw s7, TcxIntS7(t0) // ...
sw s8, TcxIntS8(t0) // ...
sw zero, TcxContextFlags(t0)
sw gp, TcxIntGp(t0)
j resched
move s0, t0 // (s0) = ptr to current thread struct
25: j resched
move s0, zero // no current thread
// Nested KCall. Just invoke the function directly.
//
// (t0) = function address
// (a0) = 1st function argument
// (a1) = 2nd function argument
// (a2) = 3rd function argument
50: j t0
nop
.set reorder
.end xKCall
// Interlocked singly-linked list functions.
//
// These functions are used internally by the kernel. They are not exported
// because they require privileged instructions on some CPUs.
// InterlockedPopList - remove first item from list
//
// Entry (a0) = ptr to list head
// Return (v0) = item at head of list
// If (list not emtpy) next item is now head of list
// Usea t0, t1
LEAF_ENTRY(InterlockedPopList)
#if NO_LL
la t0, IPopRestart
.set noreorder
IPopRestart:
move k1, t0 // interlocked operation in progress
lw v0, (a0) // (v0) = original contents
beq v0, zero, 10f
nop
lw t1, (v0) // (t1) = next item on the list
sw t1, (a0) // update head of list
10: j ra
move k1, zero // interlocked operation complete
#else
#error Unimplemented.
#endif
.end InterlockedPopList
// InterlockedPushList - add an item to head of list
//
// Entry (a0) = ptr to list head
// (a1) = ptr to item
// Return (v0) = old head of list
// Uses t0, v0
LEAF_ENTRY(InterlockedPushList)
#if NO_LL
la t0, IPushRestart
.set noreorder
IPushRestart:
move k1, t0 // interlocked operation in progress
lw v0, (a0) // (v0) = original list head
sw v0, (a1) // store linkage
sw a1, (a0) // store new list head
j ra
move k1, zero // interlocked operation complete
#else
#error Unimplemented.
#endif
.end InterlockedPushList
#ifdef MIPS_HAS_FPU
LEAF_ENTRY(GetAndClearFloatCode)
mfc0 a1, psr
lui a2, 0x2000
or a1, a2
mtc0 a1, psr
nop
nop
nop
cfc1 v0, fsr
li t0, 0xfffc0fff
and t0, t0, v0
ctc1 t0, fsr
j ra
nop
.end GetCode
LEAF_ENTRY(SaveFloatContext)
mfc0 t0, psr
lui t1, 0x2000
or t0, t1
mtc0 t0, psr
nop
nop
nop
cfc1 t0, fsr
sw t0, TcxFsr(a0)
swc1 f0, TcxFltF0(a0)
swc1 f1, TcxFltF1(a0)
swc1 f2, TcxFltF2(a0)
swc1 f3, TcxFltF3(a0)
swc1 f4, TcxFltF4(a0)
swc1 f5, TcxFltF5(a0)
swc1 f6, TcxFltF6(a0)
swc1 f7, TcxFltF7(a0)
swc1 f8, TcxFltF8(a0)
swc1 f9, TcxFltF9(a0)
swc1 f10, TcxFltF10(a0)
swc1 f11, TcxFltF11(a0)
swc1 f12, TcxFltF12(a0)
swc1 f13, TcxFltF13(a0)
swc1 f14, TcxFltF14(a0)
swc1 f15, TcxFltF15(a0)
swc1 f16, TcxFltF16(a0)
swc1 f17, TcxFltF17(a0)
swc1 f18, TcxFltF18(a0)
swc1 f19, TcxFltF19(a0)
swc1 f20, TcxFltF20(a0)
swc1 f21, TcxFltF21(a0)
swc1 f22, TcxFltF22(a0)
swc1 f23, TcxFltF23(a0)
swc1 f24, TcxFltF24(a0)
swc1 f25, TcxFltF25(a0)
swc1 f26, TcxFltF26(a0)
swc1 f27, TcxFltF27(a0)
swc1 f28, TcxFltF28(a0)
swc1 f29, TcxFltF29(a0)
swc1 f30, TcxFltF30(a0)
swc1 f31, TcxFltF31(a0)
j ra
nop
.end SaveFloatContext
LEAF_ENTRY(RestoreFloatContext)
mfc0 t0, psr
lui t1, 0x2000
or t0, t1
mtc0 t0, psr
nop
nop
nop
lw t0, TcxFsr(a0)
ctc1 t0, fsr
lwc1 f0, TcxFltF0(a0)
lwc1 f1, TcxFltF1(a0)
lwc1 f2, TcxFltF2(a0)
lwc1 f3, TcxFltF3(a0)
lwc1 f4, TcxFltF4(a0)
lwc1 f5, TcxFltF5(a0)
lwc1 f6, TcxFltF6(a0)
lwc1 f7, TcxFltF7(a0)
lwc1 f8, TcxFltF8(a0)
lwc1 f9, TcxFltF9(a0)
lwc1 f10, TcxFltF10(a0)
lwc1 f11, TcxFltF11(a0)
lwc1 f12, TcxFltF12(a0)
lwc1 f13, TcxFltF13(a0)
lwc1 f14, TcxFltF14(a0)
lwc1 f15, TcxFltF15(a0)
lwc1 f16, TcxFltF16(a0)
lwc1 f17, TcxFltF17(a0)
lwc1 f18, TcxFltF18(a0)
lwc1 f19, TcxFltF19(a0)
lwc1 f20, TcxFltF20(a0)
lwc1 f21, TcxFltF21(a0)
lwc1 f22, TcxFltF22(a0)
lwc1 f23, TcxFltF23(a0)
lwc1 f24, TcxFltF24(a0)
lwc1 f25, TcxFltF25(a0)
lwc1 f26, TcxFltF26(a0)
lwc1 f27, TcxFltF27(a0)
lwc1 f28, TcxFltF28(a0)
lwc1 f29, TcxFltF29(a0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -