Irq 7 is special. It is not just the parallel port. It can also be a
[pintos-anon] / src / threads / interrupt.c
index 3e522280a5b76ea5baae93e5daf8ecd4746b0028..72b37837dcf420f98110b4e1ab23c838b3704a29 100644 (file)
@@ -6,15 +6,17 @@
 #include "threads/flags.h"
 #include "threads/intr-stubs.h"
 #include "threads/io.h"
 #include "threads/flags.h"
 #include "threads/intr-stubs.h"
 #include "threads/io.h"
-#include "threads/mmu.h"
 #include "threads/thread.h"
 #include "threads/thread.h"
+#include "threads/vaddr.h"
 #include "devices/timer.h"
 
 /* Number of x86 interrupts. */
 #define INTR_CNT 256
 
 /* The Interrupt Descriptor Table (IDT).  The format is fixed by
 #include "devices/timer.h"
 
 /* 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. */
@@ -53,8 +55,9 @@ intr_get_level (void)
 
   /* Push the flags register on the processor stack, then pop the
      value off the stack into `flags'.  See [IA32-v2b] "PUSHF"
 
   /* 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-v3] 5.8.1. */
-  asm volatile ("pushf; pop %0" : "=g" (flags));
+     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;
 }
@@ -75,7 +78,9 @@ intr_enable (void)
   ASSERT (!intr_context ());
 
   /* Enable interrupts by setting the interrupt flag.
   ASSERT (!intr_context ());
 
   /* Enable interrupts by setting the interrupt flag.
-     See [IA32-v2b] "STI" and [IA32-v3] 5.8.1. */
+
+     See [IA32-v2b] "STI" and [IA32-v3a] 5.8.1 "Masking Maskable
+     Hardware Interrupts". */
   asm volatile ("sti");
 
   return old_level;
   asm volatile ("sti");
 
   return old_level;
@@ -88,7 +93,8 @@ intr_disable (void)
   enum intr_level old_level = intr_get_level ();
 
   /* Disable interrupts by clearing the interrupt flag.
   enum intr_level old_level = intr_get_level ();
 
   /* Disable interrupts by clearing the interrupt flag.
-     See [IA32-v2b] "CLI" and [IA32-v3] 5.8.1. */
+     See [IA32-v2b] "CLI" and [IA32-v3a] 5.8.1 "Masking Maskable
+     Hardware Interrupts". */
   asm volatile ("cli");
 
   return old_level;
   asm volatile ("cli");
 
   return old_level;
@@ -109,7 +115,8 @@ intr_init (void)
     idt[i] = make_intr_gate (intr_stubs[i], 0);
 
   /* Load IDT register.
     idt[i] = make_intr_gate (intr_stubs[i], 0);
 
   /* Load IDT register.
-     See [IA32-v2a] "LIDT" and [IA32-v3] 5.10. */
+     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));
 
   idtr_operand = make_idtr_operand (sizeof idt - 1, idt);
   asm volatile ("lidt %0" :: "m" (idtr_operand));
 
@@ -137,9 +144,37 @@ intr_init (void)
   intr_names[19] = "#XF SIMD Floating-Point Exception";
 }
 
   intr_names[19] = "#XF SIMD Floating-Point Exception";
 }
 
-/* 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 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 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
@@ -147,29 +182,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
@@ -254,13 +275,15 @@ 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.
 
    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
    for further 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-v3] section 5.12.1.2 for discussion. */
+   [IA32-v3a] section 5.12.1.2 "Flag Usage By Exception- or
+   Interrupt-Handler Procedure" for discussion. */
 static uint64_t
 make_gate (void (*function) (void), int dpl, int type)
 {
 static uint64_t
 make_gate (void (*function) (void), int dpl, int type)
 {
@@ -332,16 +355,23 @@ intr_handler (struct intr_frame *frame)
       yield_on_return = false;
     }
 
       yield_on_return = false;
     }
 
-  /* Invoke the interrupt's handler.
-     If there is no handler, invoke the unexpected interrupt
-     handler. */
+  /* Invoke the interrupt's handler. */
   handler = intr_handlers[frame->vec_no];
   handler = intr_handlers[frame->vec_no];
-  if (handler == NULL)
+  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);
       intr_dump_frame (frame);
-      PANIC ("Unexpected interrupt");
+      PANIC ("Unexpected interrupt"); 
     }
     }
-  handler (frame);
 
   /* Complete the processing of an external interrupt. */
   if (external) 
 
   /* Complete the processing of an external interrupt. */
   if (external) 
@@ -366,9 +396,9 @@ intr_dump_frame (const struct intr_frame *f)
   /* 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
   /* 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-v3] 5.14 "Interrupt 14--Page Fault Exception
+     [IA32-v3a] 5.14 "Interrupt 14--Page Fault Exception
      (#PF)". */
      (#PF)". */
-  asm ("mov %0, %%cr2" : "=r" (cr2));
+  asm ("movl %%cr2, %0" : "=r" (cr2));
 
   printf ("Interrupt %#04x (%s) at eip=%p\n",
           f->vec_no, intr_names[f->vec_no], f->eip);
 
   printf ("Interrupt %#04x (%s) at eip=%p\n",
           f->vec_no, intr_names[f->vec_no], f->eip);