⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 except.s

📁 可用于嵌入式编程学习
💻 S
📖 第 1 页 / 共 4 页
字号:
	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 + -