Use macros for 8259A PIC registers, instead of writing them literally.
[pintos-anon] / src / threads / interrupt.c
index 268e3b530c4c5ab16034e134db28f49ad3bf41f0..9ffd873540b803ca3414b83f10c6da4e8c4b2f54 100644 (file)
@@ -1,19 +1,30 @@
-#include "interrupt.h"
+#include "threads/interrupt.h"
+#include <debug.h>
 #include <inttypes.h>
 #include <stdint.h>
 #include <inttypes.h>
 #include <stdint.h>
-#include "intr-stubs.h"
-#include "debug.h"
-#include "io.h"
-#include "lib.h"
-#include "mmu.h"
-#include "thread.h"
-#include "timer.h"
+#include <stdio.h>
+#include "threads/flags.h"
+#include "threads/intr-stubs.h"
+#include "threads/io.h"
+#include "threads/thread.h"
+#include "threads/vaddr.h"
+#include "devices/timer.h"
+
+/* Programmable Interrupt Controller (PIC) registers.
+   A PC has two PICs, called the master and slave PICs, with the
+   slave attached ("cascaded") to the master IRQ line 2. */
+#define PIC0_CTRL      0x20    /* Master PIC control register address. */
+#define PIC0_DATA      0x21    /* Master PIC data register address. */
+#define PIC1_CTRL      0xa0    /* Slave PIC control register address. */
+#define PIC1_DATA      0xa1    /* Slave PIC data register address. */
 
 /* Number of x86 interrupts. */
 #define INTR_CNT 256
 
 /* The Interrupt Descriptor Table (IDT).  The format is fixed by
 
 /* Number of x86 interrupts. */
 #define INTR_CNT 256
 
 /* The Interrupt Descriptor Table (IDT).  The format is fixed by
-   the CPU.  See [IA32-v3] sections 5.10, 5.11, 5.12.1.2. */
+   the CPU.  See [IA32-v3a] sections 5.10 "Interrupt Descriptor
+   Table (IDT)", 5.11 "IDT Descriptors", 5.12.1.2 "Flag Usage By
+   Exception- or Interrupt-Handler Procedure". */
 static uint64_t idt[INTR_CNT];
 
 /* Interrupt handler functions for each interrupt. */
 static uint64_t idt[INTR_CNT];
 
 /* Interrupt handler functions for each interrupt. */
@@ -39,19 +50,22 @@ static void pic_end_of_interrupt (int irq);
 /* Interrupt Descriptor Table helpers. */
 static uint64_t make_intr_gate (void (*) (void), int dpl);
 static uint64_t make_trap_gate (void (*) (void), int dpl);
 /* Interrupt Descriptor Table helpers. */
 static uint64_t make_intr_gate (void (*) (void), int dpl);
 static uint64_t make_trap_gate (void (*) (void), int dpl);
+static inline uint64_t make_idtr_operand (uint16_t limit, void *base);
 
 /* Interrupt handlers. */
 void intr_handler (struct intr_frame *args);
 
 /* Interrupt handlers. */
 void intr_handler (struct intr_frame *args);
-static intr_handler_func panic NO_RETURN;
-static intr_handler_func kill NO_RETURN;
 \f
 /* Returns the current interrupt status. */
 enum intr_level
 intr_get_level (void) 
 {
   uint32_t flags;
 \f
 /* Returns the current interrupt status. */
 enum intr_level
 intr_get_level (void) 
 {
   uint32_t flags;
-  
-  asm ("pushfl; popl %0" : "=g" (flags));
+
+  /* Push the flags register on the processor stack, then pop the
+     value off the stack into `flags'.  See [IA32-v2b] "PUSHF"
+     and "POP" and [IA32-v3a] 5.8.1 "Masking Maskable Hardware
+     Interrupts". */
+  asm volatile ("pushfl; popl %0" : "=g" (flags));
 
   return flags & FLAG_IF ? INTR_ON : INTR_OFF;
 }
 
   return flags & FLAG_IF ? INTR_ON : INTR_OFF;
 }
@@ -69,7 +83,14 @@ enum intr_level
 intr_enable (void) 
 {
   enum intr_level old_level = intr_get_level ();
 intr_enable (void) 
 {
   enum intr_level old_level = intr_get_level ();
+  ASSERT (!intr_context ());
+
+  /* Enable interrupts by setting the interrupt flag.
+
+     See [IA32-v2b] "STI" and [IA32-v3a] 5.8.1 "Masking Maskable
+     Hardware Interrupts". */
   asm volatile ("sti");
   asm volatile ("sti");
+
   return old_level;
 }
 
   return old_level;
 }
 
@@ -78,7 +99,12 @@ enum intr_level
 intr_disable (void) 
 {
   enum intr_level old_level = intr_get_level ();
 intr_disable (void) 
 {
   enum intr_level old_level = intr_get_level ();
-  asm volatile ("cli");
+
+  /* Disable interrupts by clearing the interrupt flag.
+     See [IA32-v2b] "CLI" and [IA32-v3a] 5.8.1 "Masking Maskable
+     Hardware Interrupts". */
+  asm volatile ("cli" : : : "memory");
+
   return old_level;
 }
 \f
   return old_level;
 }
 \f
@@ -89,45 +115,74 @@ intr_init (void)
   uint64_t idtr_operand;
   int i;
 
   uint64_t idtr_operand;
   int i;
 
+  /* Initialize interrupt controller. */
   pic_init ();
 
   pic_init ();
 
+  /* Initialize IDT. */
+  for (i = 0; i < INTR_CNT; i++)
+    idt[i] = make_intr_gate (intr_stubs[i], 0);
+
+  /* Load IDT register.
+     See [IA32-v2a] "LIDT" and [IA32-v3a] 5.10 "Interrupt
+     Descriptor Table (IDT)". */
+  idtr_operand = make_idtr_operand (sizeof idt - 1, idt);
+  asm volatile ("lidt %0" : : "m" (idtr_operand));
+
   /* Initialize intr_names. */
   for (i = 0; i < INTR_CNT; i++)
     intr_names[i] = "unknown";
   /* Initialize intr_names. */
   for (i = 0; i < INTR_CNT; i++)
     intr_names[i] = "unknown";
+  intr_names[0] = "#DE Divide Error";
+  intr_names[1] = "#DB Debug Exception";
+  intr_names[2] = "NMI Interrupt";
+  intr_names[3] = "#BP Breakpoint Exception";
+  intr_names[4] = "#OF Overflow Exception";
+  intr_names[5] = "#BR BOUND Range Exceeded Exception";
+  intr_names[6] = "#UD Invalid Opcode Exception";
+  intr_names[7] = "#NM Device Not Available Exception";
+  intr_names[8] = "#DF Double Fault Exception";
+  intr_names[9] = "Coprocessor Segment Overrun";
+  intr_names[10] = "#TS Invalid TSS Exception";
+  intr_names[11] = "#NP Segment Not Present";
+  intr_names[12] = "#SS Stack Fault Exception";
+  intr_names[13] = "#GP General Protection Exception";
+  intr_names[14] = "#PF Page-Fault Exception";
+  intr_names[16] = "#MF x87 FPU Floating-Point Error";
+  intr_names[17] = "#AC Alignment Check Exception";
+  intr_names[18] = "#MC Machine-Check Exception";
+  intr_names[19] = "#XF SIMD Floating-Point Exception";
+}
 
 
-  /* Most exceptions require ring 0.
-     Exceptions 3, 4, and 5 can be caused by ring 3 directly. */
-  intr_register (0, 0, INTR_ON, kill, "#DE Divide Error");
-  intr_register (1, 0, INTR_ON, kill, "#DB Debug Exception");
-  intr_register (2, 0, INTR_ON, panic, "NMI Interrupt");
-  intr_register (3, 3, INTR_ON, kill, "#BP Breakpoint Exception");
-  intr_register (4, 3, INTR_ON, kill, "#OF Overflow Exception");
-  intr_register (5, 3, INTR_ON, kill, "#BR BOUND Range Exceeded Exception");
-  intr_register (6, 0, INTR_ON, kill, "#UD Invalid Opcode Exception");
-  intr_register (7, 0, INTR_ON, kill, "#NM Device Not Available Exception");
-  intr_register (8, 0, INTR_ON, panic, "#DF Double Fault Exception");
-  intr_register (9, 0, INTR_ON, panic, "Coprocessor Segment Overrun");
-  intr_register (10, 0, INTR_ON, panic, "#TS Invalid TSS Exception");
-  intr_register (11, 0, INTR_ON, kill, "#NP Segment Not Present");
-  intr_register (12, 0, INTR_ON, kill, "#SS Stack Fault Exception");
-  intr_register (13, 0, INTR_ON, kill, "#GP General Protection Exception");
-  intr_register (16, 0, INTR_ON, kill, "#MF x87 FPU Floating-Point Error");
-  intr_register (17, 0, INTR_ON, panic, "#AC Alignment Check Exception");
-  intr_register (18, 0, INTR_ON, panic, "#MC Machine-Check Exception");
-  intr_register (19, 0, INTR_ON, kill, "#XF SIMD Floating-Point Exception");
-
-  /* Most exceptions can be handled with interrupts turned on.
-     We need to disable interrupts for page faults because the
-     fault address is stored in CR2 and needs to be preserved. */
-  intr_register (14, 0, INTR_OFF, kill, "#PF Page-Fault Exception");
-
-  idtr_operand = make_dtr_operand (sizeof idt - 1, idt);
-  asm volatile ("lidt %0" :: "m" (idtr_operand));
+/* Registers interrupt VEC_NO to invoke HANDLER with descriptor
+   privilege level DPL.  Names the interrupt NAME for debugging
+   purposes.  The interrupt handler will be invoked with
+   interrupt status set to LEVEL. */
+static void
+register_handler (uint8_t vec_no, int dpl, enum intr_level level,
+                  intr_handler_func *handler, const char *name)
+{
+  ASSERT (intr_handlers[vec_no] == NULL);
+  if (level == INTR_ON)
+    idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
+  else
+    idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
+  intr_handlers[vec_no] = handler;
+  intr_names[vec_no] = name;
+}
+
+/* Registers external interrupt VEC_NO to invoke HANDLER, which
+   is named NAME for debugging purposes.  The handler will
+   execute with interrupts disabled. */
+void
+intr_register_ext (uint8_t vec_no, intr_handler_func *handler,
+                   const char *name) 
+{
+  ASSERT (vec_no >= 0x20 && vec_no <= 0x2f);
+  register_handler (vec_no, 0, INTR_OFF, handler, name);
 }
 
 }
 
-/* Registers interrupt VEC_NO to invoke HANDLER, which is named
-   NAME for debugging purposes.  The interrupt handler will be
-   invoked with interrupt status set to LEVEL.
+/* Registers internal interrupt VEC_NO to invoke HANDLER, which
+   is named NAME for debugging purposes.  The interrupt handler
+   will be invoked with interrupt status LEVEL.
 
    The handler will have descriptor privilege level DPL, meaning
    that it can be invoked intentionally when the processor is in
 
    The handler will have descriptor privilege level DPL, meaning
    that it can be invoked intentionally when the processor is in
@@ -135,29 +190,15 @@ intr_init (void)
    user mode to invoke the interrupts and DPL==0 prevents such
    invocation.  Faults and exceptions that occur in user mode
    still cause interrupts with DPL==0 to be invoked.  See
    user mode to invoke the interrupts and DPL==0 prevents such
    invocation.  Faults and exceptions that occur in user mode
    still cause interrupts with DPL==0 to be invoked.  See
-   [IA32-v3] sections 4.5 and 4.8.1.1 for further discussion. */
+   [IA32-v3a] sections 4.5 "Privilege Levels" and 4.8.1.1
+   "Accessing Nonconforming Code Segments" for further
+   discussion. */
 void
 void
-intr_register (uint8_t vec_no, int dpl, enum intr_level level,
-               intr_handler_func *handler,
-               const char *name) 
+intr_register_int (uint8_t vec_no, int dpl, enum intr_level level,
+                   intr_handler_func *handler, const char *name)
 {
 {
-  /* Make sure this handler isn't already registered to someone
-     else. */
-  ASSERT (intr_handlers[vec_no] == NULL);
-
-  /* Interrupts generated by external hardware (0x20 <= VEC_NO <=
-     0x2f) should specify INTR_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 == INTR_OFF);
-
-  if (level == INTR_ON)
-    idt[vec_no] = make_trap_gate (intr_stubs[vec_no], dpl);
-  else
-    idt[vec_no] = make_intr_gate (intr_stubs[vec_no], dpl);
-  intr_handlers[vec_no] = handler;
-  intr_names[vec_no] = name;
+  ASSERT (vec_no < 0x20 || vec_no > 0x2f);
+  register_handler (vec_no, dpl, level, handler, name);
 }
 
 /* Returns true during processing of an external interrupt
 }
 
 /* Returns true during processing of an external interrupt
@@ -181,42 +222,35 @@ intr_yield_on_return (void)
 \f
 /* 8259A Programmable Interrupt Controller. */
 
 \f
 /* 8259A Programmable Interrupt Controller. */
 
-/* Every PC has two 8259A Programmable Interrupt Controller (PIC)
-   chips.  One is a "master" accessible at ports 0x20 and 0x21.
-   The other is a "slave" cascaded onto the master's IRQ 2 line
-   and accessible at ports 0xa0 and 0xa1.  Accesses to port 0x20
-   set the A0 line to 0 and accesses to 0x21 set the A1 line to
-   1.  The situation is similar for the slave PIC.
+/* Initializes the PICs.  Refer to [8259A] for details.
 
    By default, interrupts 0...15 delivered by the PICs will go to
 
    By default, interrupts 0...15 delivered by the PICs will go to
-   interrupt vectors 0...15.  Unfortunately, those vectors are
-   also used for CPU traps and exceptions.  We reprogram the PICs
-   so that interrupts 0...15 are delivered to interrupt vectors
-   32...47 (0x20...0x2f) instead. */
-
-/* Initializes the PICs.  Refer to [8259A] for details. */
+   interrupt vectors 0...15.  Those vectors are also used for CPU
+   traps and exceptions, so we reprogram the PICs so that
+   interrupts 0...15 are delivered to interrupt vectors 32...47
+   (0x20...0x2f) instead. */
 static void
 pic_init (void)
 {
   /* Mask all interrupts on both PICs. */
 static void
 pic_init (void)
 {
   /* Mask all interrupts on both PICs. */
-  outb (0x21, 0xff);
-  outb (0xa1, 0xff);
+  outb (PIC0_DATA, 0xff);
+  outb (PIC1_DATA, 0xff);
 
   /* Initialize master. */
 
   /* Initialize master. */
-  outb (0x20, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
-  outb (0x21, 0x20); /* ICW2: line IR0...7 -> irq 0x20...0x27. */
-  outb (0x21, 0x04); /* ICW3: slave PIC on line IR2. */
-  outb (0x21, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
+  outb (PIC0_CTRL, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
+  outb (PIC0_DATA, 0x20); /* ICW2: line IR0...7 -> irq 0x20...0x27. */
+  outb (PIC0_DATA, 0x04); /* ICW3: slave PIC on line IR2. */
+  outb (PIC0_DATA, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
 
   /* Initialize slave. */
 
   /* Initialize slave. */
-  outb (0xa0, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
-  outb (0xa1, 0x28); /* ICW2: line IR0...7 -> irq 0x28...0x2f. */
-  outb (0xa1, 0x02); /* ICW3: slave ID is 2. */
-  outb (0xa1, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
+  outb (PIC1_CTRL, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
+  outb (PIC1_DATA, 0x28); /* ICW2: line IR0...7 -> irq 0x28...0x2f. */
+  outb (PIC1_DATA, 0x02); /* ICW3: slave ID is 2. */
+  outb (PIC1_DATA, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */
 
   /* Unmask all interrupts. */
 
   /* Unmask all interrupts. */
-  outb (0x21, 0x00);
-  outb (0xa1, 0x00);
+  outb (PIC0_DATA, 0x00);
+  outb (PIC1_DATA, 0x00);
 }
 
 /* Sends an end-of-interrupt signal to the PIC for the given IRQ.
 }
 
 /* Sends an end-of-interrupt signal to the PIC for the given IRQ.
@@ -242,25 +276,33 @@ pic_end_of_interrupt (int irq)
    or lower-numbered ring.  In practice, DPL==3 allows user mode
    to call into the gate and DPL==0 prevents such calls.  Faults
    and exceptions that occur in user mode still cause gates with
    or lower-numbered ring.  In practice, DPL==3 allows user mode
    to call into the gate and DPL==0 prevents such calls.  Faults
    and exceptions that occur in user mode still cause gates with
-   DPL==0 to be invoked.  See [IA32-v3] sections 4.5 and 4.8.1.1
+   DPL==0 to be invoked.  See [IA32-v3a] sections 4.5 "Privilege
+   Levels" and 4.8.1.1 "Accessing Nonconforming Code Segments"
    for further discussion.
 
    for further discussion.
 
-   TYPE must be either TYPE_INT_32 (for an interrupt gate) or
-   TYPE_TRAP_32 (for a trap gate).  The difference is that
-   entering an interrupt gate disables interrupts, but entering a
-   trap gate does not.  See [IA32-v3] section 5.12.1.2 for
-   discussion. */
+   TYPE must be either 14 (for an interrupt gate) or 15 (for a
+   trap gate).  The difference is that entering an interrupt gate
+   disables interrupts, but entering a trap gate does not.  See
+   [IA32-v3a] section 5.12.1.2 "Flag Usage By Exception- or
+   Interrupt-Handler Procedure" for discussion. */
 static uint64_t
 static uint64_t
-make_gate (void (*function) (void), int dpl, enum seg_type type)
+make_gate (void (*function) (void), int dpl, int type)
 {
 {
-  uint32_t offset = (uint32_t) function;
-  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. */
-                 | ((uint32_t) dpl << 13)     /* Descriptor privilege. */
-                 | (SYS_SYSTEM << 12)         /* System. */
-                 | ((uint32_t) type << 8));   /* Gate type. */
+  uint32_t e0, e1;
+
+  ASSERT (function != NULL);
+  ASSERT (dpl >= 0 && dpl <= 3);
+  ASSERT (type >= 0 && type <= 15);
+
+  e0 = (((uint32_t) function & 0xffff)     /* Offset 15:0. */
+        | (SEL_KCSEG << 16));              /* Target code segment. */
+
+  e1 = (((uint32_t) function & 0xffff0000) /* Offset 31:16. */
+        | (1 << 15)                        /* Present. */
+        | ((uint32_t) dpl << 13)           /* Descriptor privilege level. */
+        | (0 << 12)                        /* System. */
+        | ((uint32_t) type << 8));         /* Gate type. */
+
   return e0 | ((uint64_t) e1 << 32);
 }
 
   return e0 | ((uint64_t) e1 << 32);
 }
 
@@ -269,7 +311,7 @@ make_gate (void (*function) (void), int dpl, enum seg_type type)
 static uint64_t
 make_intr_gate (void (*function) (void), int dpl)
 {
 static uint64_t
 make_intr_gate (void (*function) (void), int dpl)
 {
-  return make_gate (function, dpl, TYPE_INT_32);
+  return make_gate (function, dpl, 14);
 }
 
 /* Creates a trap gate that invokes FUNCTION with the given
 }
 
 /* Creates a trap gate that invokes FUNCTION with the given
@@ -277,24 +319,34 @@ make_intr_gate (void (*function) (void), int dpl)
 static uint64_t
 make_trap_gate (void (*function) (void), int dpl)
 {
 static uint64_t
 make_trap_gate (void (*function) (void), int dpl)
 {
-  return make_gate (function, dpl, TYPE_TRAP_32);
+  return make_gate (function, dpl, 15);
+}
+
+/* Returns a descriptor that yields the given LIMIT and BASE when
+   used as an operand for the LIDT instruction. */
+static inline uint64_t
+make_idtr_operand (uint16_t limit, void *base)
+{
+  return limit | ((uint64_t) (uint32_t) base << 16);
 }
 \f
 /* Interrupt handlers. */
 
 }
 \f
 /* Interrupt handlers. */
 
-static void dump_intr_frame (struct intr_frame *);
-
 /* Handler for all interrupts, faults, and exceptions.  This
    function is called by the assembly language interrupt stubs in
 /* Handler for all interrupts, faults, and exceptions.  This
    function is called by the assembly language interrupt stubs in
-   intr-stubs.S (see intr-stubs.pl).  ARGS describes the
-   interrupt and the interrupted thread's registers. */
+   intr-stubs.S.  FRAME describes the interrupt and the
+   interrupted thread's registers. */
 void
 void
-intr_handler (struct intr_frame *args
+intr_handler (struct intr_frame *frame
 {
   bool external;
   intr_handler_func *handler;
 
 {
   bool external;
   intr_handler_func *handler;
 
-  external = args->vec_no >= 0x20 && args->vec_no < 0x30;
+  /* External interrupts are special.
+     We only handle one at a time (so interrupts must be off)
+     and they need to be acknowledged on the PIC (see below).
+     An external interrupt handler cannot sleep. */
+  external = frame->vec_no >= 0x20 && frame->vec_no < 0x30;
   if (external) 
     {
       ASSERT (intr_get_level () == INTR_OFF);
   if (external) 
     {
       ASSERT (intr_get_level () == INTR_OFF);
@@ -304,13 +356,23 @@ intr_handler (struct intr_frame *args)
       yield_on_return = false;
     }
 
       yield_on_return = false;
     }
 
-  /* Invoke the interrupt's handler.
-     If there is no handler, invoke the unexpected interrupt
-     handler. */
-  handler = intr_handlers[args->vec_no];
-  if (handler == NULL)
-    handler = panic;
-  handler (args);
+  /* Invoke the interrupt's handler. */
+  handler = intr_handlers[frame->vec_no];
+  if (handler != NULL)
+    handler (frame);
+  else if (frame->vec_no == 0x27 || frame->vec_no == 0x2f)
+    {
+      /* There is no handler, but this interrupt can trigger
+         spuriously due to a hardware fault or hardware race
+         condition.  Ignore it. */
+    }
+  else 
+    {
+      /* No handler and not spurious.  Invoke the unexpected
+         interrupt handler. */
+      intr_dump_frame (frame);
+      PANIC ("Unexpected interrupt"); 
+    }
 
   /* Complete the processing of an external interrupt. */
   if (external) 
 
   /* Complete the processing of an external interrupt. */
   if (external) 
@@ -319,78 +381,40 @@ intr_handler (struct intr_frame *args)
       ASSERT (intr_context ());
 
       in_external_intr = false;
       ASSERT (intr_context ());
 
       in_external_intr = false;
-      pic_end_of_interrupt (args->vec_no); 
+      pic_end_of_interrupt (frame->vec_no); 
 
       if (yield_on_return) 
         thread_yield (); 
     }
 }
 
 
       if (yield_on_return) 
         thread_yield (); 
     }
 }
 
-/* Handler for an interrupt that should not have been invoked. */
-static void
-panic (struct intr_frame *regs) 
-{
-  dump_intr_frame (regs);
-  PANIC ("Panic!");
-}
-
-/* Handler for an exception (probably) caused by a user process. */
-static void
-kill (struct intr_frame *f) 
-{
-  /* This interrupt is one (probably) caused by a user process.
-     For example, the process might have tried to access unmapped
-     virtual memory (a page fault).  For now, we simply kill the
-     user process.  Later, we'll want to handle page faults in
-     the kernel.  Real Unix-like operating systems pass most
-     exceptions back to the process via signals, but we don't
-     implement them. */
-     
-  /* The interrupt frame's code segment value tells us where the
-     exception originated. */
-  switch (f->cs)
-    {
-    case SEL_UCSEG:
-      /* User's code segment, so it's a user exception, as we
-         expected. */
-      printk ("%s: dying due to interrupt %#04x (%s).\n",
-              thread_name (thread_current ()),
-              f->vec_no, intr_names[f->vec_no]);
-      dump_intr_frame (f);
-      thread_exit (); 
-
-    case SEL_KCSEG:
-      /* Kernel's code segment, which indicates a kernel bug.
-         Kernel code shouldn't throw exceptions.  (Page faults
-         may cause kernel exceptions--but they shouldn't arrive
-         here.) */
-      printk ("Kernel bug - unexpected interrupt in kernel\n");
-      panic (f);
-
-    default:
-      /* Some other code segment?  Shouldn't happen. */
-      printk ("Interrupt %#04x (%s) in unknown segment %04x\n",
-             f->vec_no, intr_names[f->vec_no], f->cs);
-      thread_exit ();
-    }
-}
-
 /* Dumps interrupt frame F to the console, for debugging. */
 /* Dumps interrupt frame F to the console, for debugging. */
-static void
-dump_intr_frame (struct intr_frame *f) 
+void
+intr_dump_frame (const struct intr_frame *f) 
 {
 {
-  uint32_t cr2, ss;
+  uint32_t cr2;
+
+  /* Store current value of CR2 into `cr2'.
+     CR2 is the linear address of the last page fault.
+     See [IA32-v2a] "MOV--Move to/from Control Registers" and
+     [IA32-v3a] 5.14 "Interrupt 14--Page Fault Exception
+     (#PF)". */
   asm ("movl %%cr2, %0" : "=r" (cr2));
   asm ("movl %%cr2, %0" : "=r" (cr2));
-  asm ("movl %%ss, %0" : "=r" (ss));
 
 
-  printk ("Interrupt %#04x (%s) at eip=%p\n",
+  printf ("Interrupt %#04x (%s) at eip=%p\n",
           f->vec_no, intr_names[f->vec_no], f->eip);
           f->vec_no, intr_names[f->vec_no], f->eip);
-  printk (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
-  printk (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
+  printf (" cr2=%08"PRIx32" error=%08"PRIx32"\n", cr2, f->error_code);
+  printf (" eax=%08"PRIx32" ebx=%08"PRIx32" ecx=%08"PRIx32" edx=%08"PRIx32"\n",
           f->eax, f->ebx, f->ecx, f->edx);
           f->eax, f->ebx, f->ecx, f->edx);
-  printk (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
+  printf (" esi=%08"PRIx32" edi=%08"PRIx32" esp=%08"PRIx32" ebp=%08"PRIx32"\n",
           f->esi, f->edi, (uint32_t) f->esp, f->ebp);
           f->esi, f->edi, (uint32_t) f->esp, f->ebp);
-  printk (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
-          f->cs, f->ds, f->es, f->cs != SEL_KCSEG ? f->ss : ss);
+  printf (" cs=%04"PRIx16" ds=%04"PRIx16" es=%04"PRIx16" ss=%04"PRIx16"\n",
+          f->cs, f->ds, f->es, f->ss);
 }
 
 }
 
+/* Returns the name of interrupt VEC. */
+const char *
+intr_name (uint8_t vec) 
+{
+  return intr_names[vec];
+}