Coherent4.2.10/i386/lib/intr_disp.s

/ $Header: $
		.unixorder
/ Assembly-language code to perform low-level interrupt dispatching.
/ The entry points defined here are referred to by the code elsewhere that
/ defines the initial IDT contents.
/ $Log: $
/
		.include	"struct.inc"
		.include	"intr.inc"
		.include	"ddi.inc"
		.include	"select.inc"

		.globl		return_to_user		/ external
		.globl		return_from_interrupt	/ external
		.globl		trap_level		/ external
		.text

/ Generic interrupt entry-point handler. This duplicates some of the major
/ functionality of "tsave", so ensure that we stay in synch somehow.
/
/ Here, we create fairly standard saved context frame, even though it wastes
/ some time.

context_save:
		pusha
		push	%ds			/ Save current state
		push	%es
		push	%fs
		push	%gs

	/ Now we can play with the registers, fetch the trap structure
	/ address from the stack frame. We store the previous contents of
	/ the global vector mask in a stack frame slot that is unused for us.

		movw	$SEL_386_KD, %dx	/ Map %ds to kernel data
		movw	%dx, %ds

		movl	_err(%esp), %ebx	/ trap information pointer
		movl	cpu+dc_base_mask, %eax	/ get old mask
		movl	%eax, _err(%esp)	/ save old mask

		orl	_int_mask(%ebx), %eax
		movl	%eax, cpu+dc_base_mask	/ set new mask

	/ We interleave some other setup in with writing the new mask and
	/ sending EOI's to the interrupt controllers so we don't need to get
	/ into the I/O recovery delay games. The ideal choice is a segment
	/ register maniplation, since they take so long.

		outb	$PICM			/ set new master mask

		movw	%dx, %es		/ map %es to kernel data

		movb	%ah, %al
		outb	$SPICM			/ set new slave mask

	/ Now we have written the masks, we need to send EOI's to the
	/ interrupt controllers to allow the non-masked interrupts to proceed.
	/ Again, we thread some extra setup through here to avoid having to
	/ play the I/O recovery-delay game.

		movb	$EOI_COMMAND, %al
		cmpl	$0, _trapno (%esp)
		je	?master_eoi

		outb	$SPICC			/ Slave PIC EOI
?master_eoi:
		xor	%ebp, %ebp		/ Halt stack backtraces
		subl	%edx, %edx		/ set fs to NULL, since we
		movw	%dx, %fs		/ have no user context.

		outb	$PICC			/ Master PIC EOI

	/ Now we have done pretty much all the setup that is possible, we
	/ increment the global DDI/DKI flag that says we are in an interrupt
	/ context, and increment our flag that says we are in the kernel
	/ before globally enabling interrupts in the CPU.

		incb	cpu+dc_int_level	/ in an interrupt
		sti

		incl	_int_count(%ebx)	/ count interrupt

		pushl	%ebx			/ point at interrupt info
		pushl	_int_arg(%ebx)		/ arg for user function
		icall	_int_func(%ebx)		/ call the function
		addl	$8, %esp		/ discard arguments

	/ Now we can restore the PIC mask settings. We disable interrupts
	/ while we do this, because even while we don't care about this being
	/ interrupted we have to avoid infinite stack growth. From here to the
	/ final interrupt return has to be disabled, with the possible
	/ exception of the code to process deferred functions and whatnot
	/ (which cannot be re-entered due to the protocol for managing the
	/ dc_int_level/dc_user_level flag).

		movl	_err(%esp), %eax	/ load saved mask
		cli
		outb	$PICM			/ restore master mask

		movl	%eax, cpu+dc_base_mask	/ restore base mask
		cmpb	$2, cpu+dc_int_level	/ what int level are we at?

		mov	%ah, %al
		outb	$SPICM			/ restore slave mask

		jae	?skip_defer		/ if >= 2, don't do defer

	/ There are two kinds of deferred routine; DDI/DKI and Coherent. The
	/ DDI/DKI semantics don't specify when the deferred routines are run.
	/ The Coherent routines historically run just before return to user
	/ mode, but it is not clear whether this is important.

		cmpb	$0, cpu+dc_ipl		/ if ipl > 0, don't do defer.
		jne	?skip_defer

		sti				/ can run this enabled
		call	return_from_interrupt
		cli

?skip_defer:
		decb	cpu+dc_int_level

	/ Now we test to see whether we came from user mode (or the idle
	/ process, which tests the same), and if so we run the "stand" routine
	/ to check for rescheduling.

		call    trap_level
		testl   %eax, %eax		/ were we in user mode?
		jne	?skip_dispatch

		sti

		movw	$SEL_386_UD, %dx	/ now we *do* have context
		movw	%dx, %fs

		call	return_to_user
		cli

?skip_dispatch:
		pop	%gs			/ restore saved context
		pop	%fs
		pop	%es
		pop	%ds
		popa
		add	$8, %esp		/ forget err, trapno
		iret				/ Done.


INTR		.macro	int_no
/		.globl	__interrupt_\int_no
/__interrupt_\int_no:
		.globl	dev\int_no
dev\int_no:
		push	$ints + int_no * SIZE..intr_t

	.if	int_no < 8
		pushl	$0
	.else
		pushl	$1
	.endi
		jmp	context_save
	.endm

		INTR	0		/ periodic timer
		INTR	1		/ keyboard
					/ for chaining PIC B
		INTR	3		/ COM2
		INTR	4		/ COM1
		INTR	5		/ 
		INTR	6		/ floppy disk controller
		INTR	7		/ parallel port

		INTR	8		/ RTC
		INTR	9		/ original IRQ 2
		INTR	10
		INTR	11
		INTR	12
		INTR	13
		INTR	14		/ AT hard-disk
		INTR	15