|
Listing 12:
/* [excerpted from i386.c] */
...
init386() {
...
outb(0xf1,0); /* clear coprocessor to cover all bases */
/* initialize 8259 ICU's in preperation for device interrupts */
outb(ICU1,0x11); /* reset the unit */
outb(ICU1+1,32); /* start with idt 32 */
outb(ICU1+1,4); /* master please */
outb(ICU1+1,1);
outb(ICU1+1,0xff); /* all disabled */
outb(ICU2,0x11);
outb(ICU2+1,40); /* start with idt 40 */
outb(ICU2+1,2); /* just a slave */
outb(ICU2+1,1);
outb(ICU2+1,0xff); /* all disabled */
/* initialize 8253 timer on interrupt #0 */
outb (0x43, 0x36);
outb (0x40, 193182/60);
outb (0x40, (193182/60)/256);
}
test386(){
...
/* test interrupts for a while */
printf("inton"); getchar();
outb(ICU1+1,0); /* unmask all interrupts */
outb(ICU2+1,0);
inton();
timeout = 0x8000000;
do nothing(); while (timeout-- );
intoff();
...
# excerpted from srt.s
...
#define INTR(a) \
pushal ; \
push %ds ; \
push %es ; \
movw $0x10, %ax ; \
movw %ax, %ds ; \
movw %ax,%es ; \
pushl $##a ; \
call _intr ; \
pop %eax ; \
pop %es ; \
pop %ds ; \
popal ; \
iret
/* hardware 32 - 47 */
IDTVEC(intr0)
INTR(0)
IDTVEC(intr1)
INTR(1)
IDTVEC(intr2)
INTR(2)
IDTVEC(intr3)
INTR(3)
IDTVEC(intr4)
INTR(4)
IDTVEC(intr5)
INTR(5)
IDTVEC(intr6)
INTR(6)
IDTVEC(intr7)
INTR(7)
IDTVEC(intr8)
INTR(8)
IDTVEC(intr9)
INTR(9)
IDTVEC(intr10)
INTR(10)
IDTVEC(intr11)
INTR(11)
IDTVEC(intr12)
INTR(12)
IDTVEC(intr13)
INTR(13)
IDTVEC(intr14)
INTR(14)
IDTVEC(intr15)
INTR(15)
.globl _inton
_inton:
sti
ret
.globl _intoff
_intoff:
cli
ret
...
/* back to i386.c */
...
/* Interrupt vector processing code */
intr(ivec) {
static clk;
int omsk1, omsk2;
/* mask off interrupt being serviced, save old mask */
if (ivec > 7) {
omsk2 = inb(ICU2+1);
outb(ICU2+1, 1<<(ivec-8));
} else {
omsk1 = inb(ICU1+1);
outb(ICU1+1, 1<<ivec);
}
/* re-enable processor's interrupts, allowing others in */
inton();
/* if we are the clock, count clock tick */
if (ivec == 0) clk++;
/* if we are the keyboard, show data incoming */
else if (ivec == 1) printf("kbd data %x, clk %d\n", inb(0x60), clk);
/* otherwise print message stating source and time */
else {
printf("intr %d, clk %d \n", ivec, clk);
getchar();
}
/* turn off interrupts, re-enable old mask, do interrupt acknowledge */
intoff();
if (ivec > 7) {
outb(ICU2+1,omsk2);
outb(ICU2,0x20);
} else
outb(ICU1+1,omsk1);
outb(ICU1,0x20);
/* return to interrupt stub */
}
...
In intr(), the present interrupt is masked off and the interrupts are then reenabled so other interrupts can be active while the received interrupt is processed. Note that both the stubs and this function are fully reentrant, as this is not an uncommon occurrence. The example code also provides some trivial interrupt actions for our timer, keyboard, and any other device that generates an interrupt. At this point, we dispatch to a specific device driver's interrupt routine. After responding to the interrupt, we restore our old mask in an uninterruptable "critical section," and signal the interrupt control unit that this interrupt is to be acknowledged as "finished." Our interrupt stub then unwinds the stack, restores the state as needed, and returns us to the exact state we were in prior to processing the interrupt signaled to the 386.
|
|