If we don't acknowledge the IRQ, we'll never get it again, so
this is important. */
static void
-pic_eoi (void)
+pic_eoi (int irq)
{
/* FIXME? The Linux code is much more complicated. */
+ ASSERT (irq >= 0x20 && irq < 0x30);
outb (0x20, 0x20);
+ if (irq >= 0x28)
+ outb (0xa0, 0x20);
}
\f
#define INTR_CNT 256
void intr_handler (struct intr_frame *args);
-bool intr_in_progress;
-bool yield_on_return;
+static bool intr_in_progress;
+static bool yield_on_return;
const char *
intr_name (int vec)
void
intr_handler (struct intr_frame *args)
{
- bool external;
-
- yield_on_return = false;
-
- external = args->vec_no >= 0x20 && args->vec_no < 0x30;
+ bool external = args->vec_no >= 0x20 && args->vec_no < 0x30;
if (external)
{
ASSERT (intr_get_level () == IF_OFF);
ASSERT (!intr_context ());
intr_in_progress = true;
+ yield_on_return = false;
}
intr_handlers[args->vec_no] (args);
ASSERT (intr_get_level () == IF_OFF);
ASSERT (intr_context ());
intr_in_progress = false;
- pic_eoi ();
- }
+ pic_eoi (args->vec_no);
- if (yield_on_return)
- thread_yield ();
+ if (yield_on_return)
+ thread_yield ();
+ }
}
bool
void
intr_yield_on_return (void)
{
+ ASSERT (intr_context ());
yield_on_return = true;
}
intr_handler_func intr_kill NO_RETURN;
static uint64_t
-make_intr_gate (void (*target) (void),
- int dpl)
+make_gate (void (*target) (void), int dpl, enum seg_type type)
{
uint32_t offset = (uint32_t) target;
uint32_t e0 = ((offset & 0xffff) /* Offset 15:0. */
| (SEL_KCSEG << 16)); /* Target code segment. */
uint32_t e1 = ((offset & 0xffff0000) /* Offset 31:16. */
| (1 << 15) /* Present. */
- | (dpl << 13) /* Descriptor privilege. */
+ | ((uint32_t) dpl << 13) /* Descriptor privilege. */
| (SYS_SYSTEM << 12) /* System. */
- | (TYPE_INT_32 << 8)); /* 32-bit interrupt gate. */
+ | ((uint32_t) type << 8)); /* Gate type. */
return e0 | ((uint64_t) e1 << 32);
}
static uint64_t
-make_trap_gate (void (*target) (void),
- int dpl)
+make_intr_gate (void (*target) (void), int dpl)
+{
+ return make_gate (target, dpl, TYPE_INT_32);
+}
+
+static uint64_t
+make_trap_gate (void (*target) (void), int dpl)
{
- return make_intr_gate (target, dpl) | (1 << 8);
+ return make_gate (target, dpl, TYPE_TRAP_32);
}
-/* We don't support nested interrupts generated by external
- hardware, so these interrupts (vec_no 0x20...0x2f) should
- specify IF_OFF for LEVEL. Otherwise a timer interrupt could
- cause a task switch during interrupt handling. Most other
- interrupts can and should be handled with interrupts
- enabled. */
void
intr_register (uint8_t vec_no, int dpl, enum if_level level,
intr_handler_func *handler,
const char *name)
{
+ /* Interrupts generated by external hardware (0x20 <= VEC_NO <=
+ 0x2f) should specify IF_OFF for LEVEL. Otherwise a timer
+ interrupt could cause a task switch during interrupt
+ handling. Most other interrupts can and should be handled
+ with interrupts enabled. */
+ ASSERT (vec_no < 0x20 || vec_no > 0x2f || level == IF_OFF);
+
if (level == IF_ON)
idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
else
intr_panic (struct intr_frame *regs)
{
dump_intr_frame (regs);
- panic ("Panic!");
+ PANIC ("Panic!");
}
void
switch (f->cs)
{
case SEL_UCSEG:
- printk ("[%p] Interrupt %#04x (%s), killing process.\n",
- thread_current (), f->vec_no, intr_name (f->vec_no));
+ printk ("%s: dying due to interrupt %#04x (%s).\n",
+ thread_current ()->name, f->vec_no, intr_name (f->vec_no));
thread_exit ();
- default:
- panic ("Interrupt %#04x (%s) in unknown segment %04x",
- f->vec_no, intr_name (f->vec_no), f->cs);
-
case SEL_KCSEG:
- printk ("intr_kill -> panic %d\n", f->vec_no);
+ printk ("Kernel bug - unexpected interrupt in kernel context\n");
intr_panic (f);
+
+ default:
+ printk ("Interrupt %#04x (%s) in unknown segment %04x\n",
+ f->vec_no, intr_name (f->vec_no), f->cs);
+ thread_exit ();
}
}