NetBSD-currentの割り込み

FreeBSD 6.3の割り込み - かーねる・う゛いえむにっき
で割り込み時のコンテキストがスタックに退避されてるー、って書いたけど、これはx86に限らず一般的にこうなってるもののようだ。
NetBSD/mipsはそれなりにコードを読んだつもりだったが、割り込み時のコンテキスト退避・復帰とyield()などでのコンテキスト切り替えとシステムコールでの切り替えと、色々あってそれぞれの処理の違いを頭の中でまとめきれてない。(似たようなもんだろ、と思ってたが、良く見るとちょっと違う。)

以下、NetBSD-current/mipsの割り込み処理。

/*
 * mipsX_KernIntr
 *
 * Handle an interrupt from kernel mode.
 * Build intrframe on stack to hold interrupted kernel context, then
 * call cpu_intr() to process it.
 *
 */
NESTED_NOPROFILE(MIPSX(KernIntr), KERNFRAME_SIZ, ra)
	.set	noat
	.mask	0x80000000, -4
	subu	sp, sp, KERNFRAME_SIZ
/*
 * Save the relevant kernel registers onto the stack.
 * We don't need to save s0 - s8, sp and gp because
 * the compiler does it for us.
 */
	REG_S	AT, TF_BASE+TF_REG_AST(sp)
	REG_S	v0, TF_BASE+TF_REG_V0(sp)
	REG_S	v1, TF_BASE+TF_REG_V1(sp)
	mflo	v0
	mfhi	v1
	REG_S	a0, TF_BASE+TF_REG_A0(sp)
	REG_S	a1, TF_BASE+TF_REG_A1(sp)
	REG_S	a2, TF_BASE+TF_REG_A2(sp)
	REG_S	a3, TF_BASE+TF_REG_A3(sp)
	mfc0	a0, MIPS_COP_0_STATUS		# 1st arg is STATUS
	REG_S	t0, TF_BASE+TF_REG_T0(sp)
	REG_S	t1, TF_BASE+TF_REG_T1(sp)
	REG_S	t2, TF_BASE+TF_REG_T2(sp)
	REG_S	t3, TF_BASE+TF_REG_T3(sp)
	mfc0	a1, MIPS_COP_0_CAUSE		# 2nd arg is CAUSE
	REG_S	ta0, TF_BASE+TF_REG_TA0(sp)
	REG_S	ta1, TF_BASE+TF_REG_TA1(sp)
	REG_S	ta2, TF_BASE+TF_REG_TA2(sp)
	REG_S	ta3, TF_BASE+TF_REG_TA3(sp)
	mfc0	a2, MIPS_COP_0_EXC_PC		# 3rd arg is exception PC
	REG_S	t8, TF_BASE+TF_REG_T8(sp)
	REG_S	t9, TF_BASE+TF_REG_T9(sp)
	REG_S	ra, TF_BASE+TF_REG_RA(sp)
	REG_S	a0, TF_BASE+TF_REG_SR(sp)
	REG_S	v0, TF_BASE+TF_REG_MULLO(sp)
	REG_S	v1, TF_BASE+TF_REG_MULHI(sp)
	REG_S	a2, TF_BASE+TF_REG_EPC(sp)
	REG_S	MIPS_CURLWP, TF_BASE+TF_PAD(sp)	# XXX Atheros HAL
/*
 * Call the interrupt handler.
 */
#if defined(DDB) || defined(DEBUG) || defined(KGDB)
	move	ra, a2
	sw	ra, KERNFRAME_RA(sp)		# for debugging
#endif
#ifdef IPL_ICU_MASK
	.set at
	lw	t0, _C_LABEL(md_imask)
	sw	t0, TF_BASE+TF_PPL(sp)
	.set noat
#endif
	mtc0	zero, MIPS_COP_0_STATUS		# Reset exl, trap possible.
	COP0_SYNC
	lw	MIPS_CURLWP, CPUVAR(CURLWP)	# XXX Atheros HAL
	jal	_C_LABEL(cpu_intr)
	and	a3, a0, a1			# 4th is STATUS & CAUSE
/*
 * Restore registers and return from the interrupt.
 */
	mtc0	zero, MIPS_COP_0_STATUS		# Disable interrupt
	COP0_SYNC
	nop
	nop
	nop
#ifdef IPL_ICU_MASK
	.set at
	lw	a0, TF_BASE+TF_PPL(sp)
	sw	a0, _C_LABEL(md_imask)
	jal	_C_LABEL(md_imask_update)
	nop
	.set noat
#endif
	REG_L	MIPS_CURLWP, TF_BASE+TF_PAD(sp)	# XXX Atheros HAL
	REG_L	a0, TF_BASE+TF_REG_SR(sp)	# ??? why differs ???
	DYNAMIC_STATUS_MASK(a0, t0)		# machine dependent masking
	REG_L	t0, TF_BASE+TF_REG_MULLO(sp)
	REG_L	t1, TF_BASE+TF_REG_MULHI(sp)
	REG_L	v0, TF_BASE+TF_REG_EPC(sp)
	mtc0	a0, MIPS_COP_0_STATUS		# restore the SR, disable intrs
	COP0_SYNC
	mtlo	t0
	mthi	t1

#ifdef notyet
	/* Check for restartable sequences. */
	lui	t0, %hi(_C_LABEL(_lock_ras_start))
	ori	t0, zero, %lo(_C_LABEL(_lock_ras_start))
	li	t1, -MIPS_LOCK_RAS_SIZE
	and	t1, t1, v0
	bne	t1, t0, 1f
	move	k1, v0
	jal	_C_LABEL(_lock_ras)
	nop
	mov	v0, k1
#endif

1:	_MTC0	v0, MIPS_COP_0_EXC_PC		# set return address
	COP0_SYNC

	REG_L	AT, TF_BASE+TF_REG_AST(sp)
	REG_L	v0, TF_BASE+TF_REG_V0(sp)
	REG_L	v1, TF_BASE+TF_REG_V1(sp)
	REG_L	a0, TF_BASE+TF_REG_A0(sp)
	REG_L	a1, TF_BASE+TF_REG_A1(sp)
	REG_L	a2, TF_BASE+TF_REG_A2(sp)
	REG_L	a3, TF_BASE+TF_REG_A3(sp)
	REG_L	t0, TF_BASE+TF_REG_T0(sp)
	REG_L	t1, TF_BASE+TF_REG_T1(sp)
	REG_L	t2, TF_BASE+TF_REG_T2(sp)
	REG_L	t3, TF_BASE+TF_REG_T3(sp)
	REG_L	ta0, TF_BASE+TF_REG_TA0(sp)
	REG_L	ta1, TF_BASE+TF_REG_TA1(sp)
	REG_L	ta2, TF_BASE+TF_REG_TA2(sp)
	REG_L	ta3, TF_BASE+TF_REG_TA3(sp)
	REG_L	t8, TF_BASE+TF_REG_T8(sp)
	REG_L	t9, TF_BASE+TF_REG_T9(sp)
	REG_L	ra, TF_BASE+TF_REG_RA(sp)
	addu	sp, sp, KERNFRAME_SIZ		# restore kernel SP
	eret					# return to interrupted point
	.set	at
END(MIPSX(KernIntr))

内容はx86のとほぼ変わらんように見える。