Update Intel architecture guide references to latest.
[pintos-anon] / src / userprog / exception.c
index 4e9d28ffd321204709afaabc0ea22f023e53296f..19aca125e331783bad87330e8e7213f72072e580 100644 (file)
@@ -5,6 +5,9 @@
 #include "threads/interrupt.h"
 #include "threads/thread.h"
 
 #include "threads/interrupt.h"
 #include "threads/thread.h"
 
+/* Number of page faults processed. */
+static long long page_fault_cnt;
+
 static void kill (struct intr_frame *);
 static void page_fault (struct intr_frame *);
 
 static void kill (struct intr_frame *);
 static void page_fault (struct intr_frame *);
 
@@ -21,8 +24,8 @@ static void page_fault (struct intr_frame *);
    way as other exceptions, but this will need to change to
    implement virtual memory.
 
    way as other exceptions, but this will need to change to
    implement virtual memory.
 
-   Refer to [IA32-v3] section 5.14 for a description of each of
-   these exceptions. */
+   Refer to [IA32-v3a] section 5.15 "Exception and Interrupt
+   Reference" for a description of each of these exceptions. */
 void
 exception_init (void) 
 {
 void
 exception_init (void) 
 {
@@ -30,28 +33,38 @@ exception_init (void)
      e.g. via the INT, INT3, INTO, and BOUND instructions.  Thus,
      we set DPL==3, meaning that user programs are allowed to
      invoke them via these instructions. */
      e.g. via the INT, INT3, INTO, and BOUND instructions.  Thus,
      we set DPL==3, meaning that user programs are allowed to
      invoke them via these instructions. */
-  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_int (3, 3, INTR_ON, kill, "#BP Breakpoint Exception");
+  intr_register_int (4, 3, INTR_ON, kill, "#OF Overflow Exception");
+  intr_register_int (5, 3, INTR_ON, kill,
+                     "#BR BOUND Range Exceeded Exception");
 
   /* These exceptions have DPL==0, preventing user processes from
      invoking them via the INT instruction.  They can still be
      caused indirectly, e.g. #DE can be caused by dividing by
      0.  */
 
   /* These exceptions have DPL==0, preventing user processes from
      invoking them via the INT instruction.  They can still be
      caused indirectly, e.g. #DE can be caused by dividing by
      0.  */
-  intr_register (0, 0, INTR_ON, kill, "#DE Divide Error");
-  intr_register (1, 0, INTR_ON, kill, "#DB Debug 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 (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 (19, 0, INTR_ON, kill, "#XF SIMD Floating-Point Exception");
+  intr_register_int (0, 0, INTR_ON, kill, "#DE Divide Error");
+  intr_register_int (1, 0, INTR_ON, kill, "#DB Debug Exception");
+  intr_register_int (6, 0, INTR_ON, kill, "#UD Invalid Opcode Exception");
+  intr_register_int (7, 0, INTR_ON, kill,
+                     "#NM Device Not Available Exception");
+  intr_register_int (11, 0, INTR_ON, kill, "#NP Segment Not Present");
+  intr_register_int (12, 0, INTR_ON, kill, "#SS Stack Fault Exception");
+  intr_register_int (13, 0, INTR_ON, kill, "#GP General Protection Exception");
+  intr_register_int (16, 0, INTR_ON, kill, "#MF x87 FPU Floating-Point Error");
+  intr_register_int (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. */
 
   /* 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, page_fault, "#PF Page-Fault Exception");
+  intr_register_int (14, 0, INTR_OFF, page_fault, "#PF Page-Fault Exception");
+}
+
+/* Prints exception statistics. */
+void
+exception_print_stats (void) 
+{
+  printf ("Exception: %lld page faults\n", page_fault_cnt);
 }
 
 /* Handler for an exception (probably) caused by a user process. */
 }
 
 /* Handler for an exception (probably) caused by a user process. */
@@ -74,8 +87,7 @@ kill (struct intr_frame *f)
       /* User's code segment, so it's a user exception, as we
          expected.  Kill the user process.  */
       printf ("%s: dying due to interrupt %#04x (%s).\n",
       /* User's code segment, so it's a user exception, as we
          expected.  Kill the user process.  */
       printf ("%s: dying due to interrupt %#04x (%s).\n",
-              thread_name (thread_current ()),
-              f->vec_no, intr_name (f->vec_no));
+              thread_name (), f->vec_no, intr_name (f->vec_no));
       intr_dump_frame (f);
       thread_exit (); 
 
       intr_dump_frame (f);
       thread_exit (); 
 
@@ -96,39 +108,41 @@ kill (struct intr_frame *f)
     }
 }
 
     }
 }
 
-/* Page fault error code bits that describe the cause of the exception.  */
-#define PF_P 0x1    /* 0: not-present page. 1: access rights violation. */
-#define PF_W 0x2    /* 0: read, 1: write. */
-#define PF_U 0x4    /* 0: kernel, 1: user process. */
-
 /* Page fault handler.  This is a skeleton that must be filled in
 /* Page fault handler.  This is a skeleton that must be filled in
-   to implement virtual memory.
+   to implement virtual memory.  Some solutions to project 2 may
+   also require modifying this code.
 
    At entry, the address that faulted is in CR2 (Control Register
    2) and information about the fault, formatted as described in
 
    At entry, the address that faulted is in CR2 (Control Register
    2) and information about the fault, formatted as described in
-   the PF_* macros above, is in F's error_code member.  The
+   the PF_* macros in exception.h, is in F's error_code member.  The
    example code here shows how to parse that information.  You
    can find more information about both of these in the
    description of "Interrupt 14--Page Fault Exception (#PF)" in
    example code here shows how to parse that information.  You
    can find more information about both of these in the
    description of "Interrupt 14--Page Fault Exception (#PF)" in
-   [IA32-v3] section 5.14, which is pages 5-46 to 5-49. */
+   [IA32-v3a] section 5.15 "Exception and Interrupt Reference". */
 static void
 page_fault (struct intr_frame *f) 
 {
 static void
 page_fault (struct intr_frame *f) 
 {
-  bool not_present, write, user;
-  uint32_t fault_addr;
-
-  /* Obtain faulting address, then turn interrupts back on.
-     (Interrupts were only off so that we could be assured of
-     reading CR2 before it changed.)
-
-     The faulting address is not necesarily the address of the
-     instruction that caused the fault--that's in F's eip
-     member.  Rather, it's the linear address that was accessed
-     to cause the fault, which is probably an address of data,
-     not code. */
+  bool not_present;  /* True: not-present page, false: writing r/o page. */
+  bool write;        /* True: access was write, false: access was read. */
+  bool user;         /* True: access by user, false: access by kernel. */
+  void *fault_addr;  /* Fault address. */
+
+  /* Obtain faulting address, the virtual address that was
+     accessed to cause the fault.  It may point to code or to
+     data.  It is not necessarily the address of the instruction
+     that caused the fault (that's f->eip).
+     See [IA32-v2a] "MOV--Move to/from Control Registers" and
+     [IA32-v3a] 5.15 "Interrupt 14--Page Fault Exception
+     (#PF)". */
   asm ("movl %%cr2, %0" : "=r" (fault_addr));
   asm ("movl %%cr2, %0" : "=r" (fault_addr));
+
+  /* Turn interrupts back on (they were only off so that we could
+     be assured of reading CR2 before it changed). */
   intr_enable ();
 
   intr_enable ();
 
+  /* Count page faults. */
+  page_fault_cnt++;
+
   /* Determine cause. */
   not_present = (f->error_code & PF_P) == 0;
   write = (f->error_code & PF_W) != 0;
   /* Determine cause. */
   not_present = (f->error_code & PF_P) == 0;
   write = (f->error_code & PF_W) != 0;
@@ -137,7 +151,7 @@ page_fault (struct intr_frame *f)
   /* To implement virtual memory, delete the rest of the function
      body, and replace it with code that brings in the page to
      which fault_addr refers. */
   /* To implement virtual memory, delete the rest of the function
      body, and replace it with code that brings in the page to
      which fault_addr refers. */
-  printf ("Page fault at %08"PRIx32": %s error %s page in %s context.\n",
+  printf ("Page fault at %p: %s error %s page in %s context.\n",
           fault_addr,
           not_present ? "not present" : "rights violation",
           write ? "writing" : "reading",
           fault_addr,
           not_present ? "not present" : "rights violation",
           write ? "writing" : "reading",