Set up a frame pointer on interrupt entry, to improve backtraces of
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 21 Jan 2005 22:17:37 +0000 (22:17 +0000)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 21 Jan 2005 22:17:37 +0000 (22:17 +0000)
system calls, page faults, etc., whether they come from user space or
the kernel.

Get rid of intr-stubs.pl, replacing it by equivalent all-assembler + C
preprocessor code.

doc/threads.texi
doc/tour.texi
src/Makefile.build
src/threads/interrupt.c
src/threads/interrupt.h
src/threads/intr-stubs.S [new file with mode: 0644]
src/threads/intr-stubs.h
src/threads/intr-stubs.pl [deleted file]
src/userprog/process.c

index 6659732b20fd4d6a1eeb5e1e5fb0388803e50023..bc2ccb548de6c278b0085b4bf08a098d3dcca4b5 100644 (file)
@@ -157,9 +157,9 @@ the kernel.
 Basic interrupt handling and functions for turning interrupts on and
 off.
 
 Basic interrupt handling and functions for turning interrupts on and
 off.
 
-@item intr-stubs.pl
+@item intr-stubs.S
 @itemx intr-stubs.h
 @itemx intr-stubs.h
-A Perl program that outputs assembly for low-level interrupt handling.
+Assembly code for low-level interrupt handling.
 
 @item synch.c
 @itemx synch.h
 
 @item synch.c
 @itemx synch.h
index 39483a32011d6f64c0a43ac13277105d10436f0b..d1147dde6b0e91d891d5192cbf6bcc841781b920 100644 (file)
@@ -782,11 +782,7 @@ In Pintos, @func{intr_init} in @file{threads/interrupt.c} sets up the
 IDT so that each entry points to a unique entry point in
 @file{threads/intr-stubs.S} named @func{intr@var{NN}_stub}, where
 @var{NN} is the interrupt number in
 IDT so that each entry points to a unique entry point in
 @file{threads/intr-stubs.S} named @func{intr@var{NN}_stub}, where
 @var{NN} is the interrupt number in
-hexadecimal.@footnote{@file{threads/intr-stubs.S} is so repetitive
-that it is actually generated by a Perl script,
-@file{threads/intr-stubs.pl}.  Thus, you will actually find
-@file{threads/intr-stubs.S} in your @file{threads/build/threads}
-directory, not in plain @file{threads}.}  Because the CPU doesn't give
+hexadecimal.  Because the CPU doesn't give
 us any other way to find out the interrupt number, this entry point
 pushes the interrupt number on the stack.  Then it jumps to
 @func{intr_entry}, which pushes all the registers that the processor
 us any other way to find out the interrupt number, this entry point
 pushes the interrupt number on the stack.  Then it jumps to
 @func{intr_entry}, which pushes all the registers that the processor
index aa8e650dffb18ea253398ef642e345e1edc6e178..d4c6d659d0afc5af2da03dbe67751d10beff0324 100644 (file)
@@ -67,9 +67,6 @@ DEPENDS = $(patsubst %.o,%.d,$(OBJECTS))
 
 all: os.dsk
 
 
 all: os.dsk
 
-threads/intr-stubs.S: threads/intr-stubs.pl threads/loader.h
-       $< > $@.tmp && mv $@.tmp $@
-
 threads/kernel.lds.s: CPPFLAGS += -P
 threads/kernel.lds.s: threads/kernel.lds.S threads/loader.h
 
 threads/kernel.lds.s: CPPFLAGS += -P
 threads/kernel.lds.s: threads/kernel.lds.S threads/loader.h
 
@@ -92,7 +89,7 @@ os.dsk: loader.bin kernel.bin
 
 clean:
        $(RM) -f $(OBJECTS) $(DEPENDS) 
 
 clean:
        $(RM) -f $(OBJECTS) $(DEPENDS) 
-       $(RM) -f threads/intr-stubs.S threads/loader.o
+       $(RM) -f threads/loader.o
        $(RM) -f kernel.o kernel.lds.s
        $(RM) -f kernel.bin loader.bin
 
        $(RM) -f kernel.o kernel.lds.s
        $(RM) -f kernel.bin loader.bin
 
index 380544a1779e6a75a2e08baa8b81ceb5ad68c67e..3e522280a5b76ea5baae93e5daf8ecd4746b0028 100644 (file)
@@ -310,8 +310,8 @@ make_idtr_operand (uint16_t limit, void *base)
 
 /* 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).  FRAME describes the
-   interrupt and the interrupted thread's registers. */
+   intr-stubs.S.  FRAME describes the interrupt and the
+   interrupted thread's registers. */
 void
 intr_handler (struct intr_frame *frame) 
 {
 void
 intr_handler (struct intr_frame *frame) 
 {
index 99abf8e3a92ddecff94064dd7bbaf5f0086e774d..b805671e626d6891f1b43aa06de64674f15a91d6 100644 (file)
@@ -19,7 +19,7 @@ enum intr_level intr_disable (void);
 /* Interrupt stack frame. */
 struct intr_frame
   {
 /* Interrupt stack frame. */
 struct intr_frame
   {
-    /* Pushed by intr_entry in intr-stubs.S (see intr-stubs.pl).
+    /* Pushed by intr_entry in intr-stubs.S.
        These are the interrupted task's saved registers. */
     uint32_t edi;               /* Saved EDI. */
     uint32_t esi;               /* Saved ESI. */
        These are the interrupted task's saved registers. */
     uint32_t edi;               /* Saved EDI. */
     uint32_t esi;               /* Saved ESI. */
@@ -34,13 +34,18 @@ struct intr_frame
     uint16_t es, :16;           /* Saved ES segment register. */
     uint16_t ds, :16;           /* Saved DS segment register. */
 
     uint16_t es, :16;           /* Saved ES segment register. */
     uint16_t ds, :16;           /* Saved DS segment register. */
 
-    /* Pushed by intrXX_stub in intr-stubs.S (see intr-stubs.pl). */
+    /* Pushed by intrNN_stub in intr-stubs.S. */
     uint32_t vec_no;            /* Interrupt vector number. */
 
     /* Sometimes pushed by the CPU,
     uint32_t vec_no;            /* Interrupt vector number. */
 
     /* Sometimes pushed by the CPU,
-       otherwise for consistency pushed as 0 by intrXX_stub. */
+       otherwise for consistency pushed as 0 by intrNN_stub.
+       The CPU puts it just under `eip', but we move it here. */
     uint32_t error_code;        /* Error code. */
 
     uint32_t error_code;        /* Error code. */
 
+    /* Pushed by intrNN_stub in intr-stubs.S.
+       This frame pointer eases interpretation of backtraces. */
+    void *frame_pointer;        /* Saved EBP (frame pointer). */
+
     /* Pushed by the CPU.
        These are the interrupted task's saved registers. */
     void (*eip) (void);         /* Next instruction to execute. */
     /* Pushed by the CPU.
        These are the interrupted task's saved registers. */
     void (*eip) (void);         /* Next instruction to execute. */
diff --git a/src/threads/intr-stubs.S b/src/threads/intr-stubs.S
new file mode 100644 (file)
index 0000000..d250777
--- /dev/null
@@ -0,0 +1,205 @@
+#include "threads/loader.h"
+
+       .intel_syntax noprefix
+        .text
+
+/* Main interrupt entry point.
+
+   An internal or external interrupt starts in one of the
+   intrNN_stub routines, which push the `struct intr_frame'
+   frame_pointer, error_code, and vec_no members on the stack,
+   then jump here.
+
+   We save the rest of the `struct intr_frame' members to the
+   stack, set up some registers as needed by the kernel, and then
+   call intr_handler(), which actually handles the interrupt.
+
+   We "fall through" to intr_exit to return from the interrupt.
+*/
+.func intr_entry
+intr_entry:
+       /* Save caller's registers. */
+       push ds
+       push es
+       push fs
+       push gs
+       pusha
+        
+       /* Set up kernel environment. */
+       cld                     /* String instructions go upward. */
+       mov eax, SEL_KDSEG      /* Initialize segment registers. */
+       mov ds, eax
+       mov es, eax
+       lea ebp, [esp + 56]     /* Set up frame pointer. */
+
+       /* Call interrupt handler. */
+       push esp
+.globl intr_handler
+       call intr_handler
+       add esp, 4
+.endfunc
+
+/* Interrupt exit.
+
+   Restores the caller's registers, discards extra data on the
+   stack, and returns to the caller.
+
+   This is a separate function because it is called directly when
+   we launch a new user process (see execute_thread() in
+   userprog/process.c). */
+.globl intr_exit
+.func intr_exit
+intr_exit:
+        /* Restore caller's registers. */
+       popa
+       pop gs
+       pop fs
+       pop es
+       pop ds
+
+        /* Discard `struct intr_frame' vec_no, error_code,
+           frame_pointer members. */
+       add esp, 12
+
+        /* Return to caller. */
+       iret
+.endfunc
+
+/* Interrupt stubs.
+
+   This defines 256 fragments of code, named `intr00_stub'
+   through `intrff_stub', each of which is used as the entry
+   point for the corresponding interrupt vector.  It also puts
+   the address of each of these functions in the correct spot in
+   `intr_stubs', an array of function pointers.
+
+   Most of the stubs do this:
+
+        1. Push EBP on the stack (frame_pointer in `struct intr_frame').
+
+        2. Push 0 on the stack (error_code).
+
+        3. Push the interrupt number on the stack (vec_no).
+
+   The CPU pushes an extra "error code" on the stack for a few
+   interrupts.  Because we want EBP to be where the error code
+   is, we follow a different path:
+
+        1. Push a duplicate copy of the error code on the stack.
+
+        2. Replace the original copy of the error code by EBP.
+
+        3. Push the interrupt number on the stack. */
+
+       .data
+.globl intr_stubs
+intr_stubs:
+
+/* This implements steps 1 and 2, described above, in the common
+   case where we just push a 0 error code. */
+#define zero                                    \
+       push ebp;                               \
+       push 0
+
+/* This implements steps 1 and 2, described above, in the case
+   where the CPU already pushed an error code. */
+#define REAL                                    \
+        push dword ptr [esp];                   \
+        mov [esp + 4], ebp
+
+/* Emits a stub for interrupt vector NUMBER.
+   TYPE is `zero', for the case where we push a 0 error code,
+   or `REAL', if the CPU pushes an error code for us. */
+#define STUB(NUMBER, TYPE)                      \
+       .text;                                  \
+.globl intr##NUMBER##_stub;                     \
+.func intr##NUMBER##_stub;                     \
+intr##NUMBER##_stub:                            \
+       TYPE;                                   \
+       push 0x##NUMBER;                        \
+        jmp intr_entry;                         \
+.endfunc;                                      \
+                                                \
+       .data;                                  \
+       .long intr##NUMBER##_stub;
+
+/* All the stubs. */
+STUB(00, zero) STUB(01, zero) STUB(02, zero) STUB(03, zero)
+STUB(04, zero) STUB(05, zero) STUB(06, zero) STUB(07, zero)
+STUB(08, REAL) STUB(09, zero) STUB(0a, REAL) STUB(0b, REAL)
+STUB(0c, zero) STUB(0d, REAL) STUB(0e, REAL) STUB(0f, zero)
+
+STUB(10, zero) STUB(11, REAL) STUB(12, zero) STUB(13, zero)
+STUB(14, zero) STUB(15, zero) STUB(16, zero) STUB(17, zero)
+STUB(18, REAL) STUB(19, zero) STUB(1a, REAL) STUB(1b, REAL)
+STUB(1c, zero) STUB(1d, REAL) STUB(1e, REAL) STUB(1f, zero)
+
+STUB(20, zero) STUB(21, zero) STUB(22, zero) STUB(23, zero)
+STUB(24, zero) STUB(25, zero) STUB(26, zero) STUB(27, zero)
+STUB(28, zero) STUB(29, zero) STUB(2a, zero) STUB(2b, zero)
+STUB(2c, zero) STUB(2d, zero) STUB(2e, zero) STUB(2f, zero)
+
+STUB(30, zero) STUB(31, zero) STUB(32, zero) STUB(33, zero)
+STUB(34, zero) STUB(35, zero) STUB(36, zero) STUB(37, zero)
+STUB(38, zero) STUB(39, zero) STUB(3a, zero) STUB(3b, zero)
+STUB(3c, zero) STUB(3d, zero) STUB(3e, zero) STUB(3f, zero)
+
+STUB(40, zero) STUB(41, zero) STUB(42, zero) STUB(43, zero)
+STUB(44, zero) STUB(45, zero) STUB(46, zero) STUB(47, zero)
+STUB(48, zero) STUB(49, zero) STUB(4a, zero) STUB(4b, zero)
+STUB(4c, zero) STUB(4d, zero) STUB(4e, zero) STUB(4f, zero)
+
+STUB(50, zero) STUB(51, zero) STUB(52, zero) STUB(53, zero)
+STUB(54, zero) STUB(55, zero) STUB(56, zero) STUB(57, zero)
+STUB(58, zero) STUB(59, zero) STUB(5a, zero) STUB(5b, zero)
+STUB(5c, zero) STUB(5d, zero) STUB(5e, zero) STUB(5f, zero)
+
+STUB(60, zero) STUB(61, zero) STUB(62, zero) STUB(63, zero)
+STUB(64, zero) STUB(65, zero) STUB(66, zero) STUB(67, zero)
+STUB(68, zero) STUB(69, zero) STUB(6a, zero) STUB(6b, zero)
+STUB(6c, zero) STUB(6d, zero) STUB(6e, zero) STUB(6f, zero)
+
+STUB(70, zero) STUB(71, zero) STUB(72, zero) STUB(73, zero)
+STUB(74, zero) STUB(75, zero) STUB(76, zero) STUB(77, zero)
+STUB(78, zero) STUB(79, zero) STUB(7a, zero) STUB(7b, zero)
+STUB(7c, zero) STUB(7d, zero) STUB(7e, zero) STUB(7f, zero)
+
+STUB(80, zero) STUB(81, zero) STUB(82, zero) STUB(83, zero)
+STUB(84, zero) STUB(85, zero) STUB(86, zero) STUB(87, zero)
+STUB(88, zero) STUB(89, zero) STUB(8a, zero) STUB(8b, zero)
+STUB(8c, zero) STUB(8d, zero) STUB(8e, zero) STUB(8f, zero)
+
+STUB(90, zero) STUB(91, zero) STUB(92, zero) STUB(93, zero)
+STUB(94, zero) STUB(95, zero) STUB(96, zero) STUB(97, zero)
+STUB(98, zero) STUB(99, zero) STUB(9a, zero) STUB(9b, zero)
+STUB(9c, zero) STUB(9d, zero) STUB(9e, zero) STUB(9f, zero)
+
+STUB(a0, zero) STUB(a1, zero) STUB(a2, zero) STUB(a3, zero)
+STUB(a4, zero) STUB(a5, zero) STUB(a6, zero) STUB(a7, zero)
+STUB(a8, zero) STUB(a9, zero) STUB(aa, zero) STUB(ab, zero)
+STUB(ac, zero) STUB(ad, zero) STUB(ae, zero) STUB(af, zero)
+
+STUB(b0, zero) STUB(b1, zero) STUB(b2, zero) STUB(b3, zero)
+STUB(b4, zero) STUB(b5, zero) STUB(b6, zero) STUB(b7, zero)
+STUB(b8, zero) STUB(b9, zero) STUB(ba, zero) STUB(bb, zero)
+STUB(bc, zero) STUB(bd, zero) STUB(be, zero) STUB(bf, zero)
+
+STUB(c0, zero) STUB(c1, zero) STUB(c2, zero) STUB(c3, zero)
+STUB(c4, zero) STUB(c5, zero) STUB(c6, zero) STUB(c7, zero)
+STUB(c8, zero) STUB(c9, zero) STUB(ca, zero) STUB(cb, zero)
+STUB(cc, zero) STUB(cd, zero) STUB(ce, zero) STUB(cf, zero)
+
+STUB(d0, zero) STUB(d1, zero) STUB(d2, zero) STUB(d3, zero)
+STUB(d4, zero) STUB(d5, zero) STUB(d6, zero) STUB(d7, zero)
+STUB(d8, zero) STUB(d9, zero) STUB(da, zero) STUB(db, zero)
+STUB(dc, zero) STUB(dd, zero) STUB(de, zero) STUB(df, zero)
+
+STUB(e0, zero) STUB(e1, zero) STUB(e2, zero) STUB(e3, zero)
+STUB(e4, zero) STUB(e5, zero) STUB(e6, zero) STUB(e7, zero)
+STUB(e8, zero) STUB(e9, zero) STUB(ea, zero) STUB(eb, zero)
+STUB(ec, zero) STUB(ed, zero) STUB(ee, zero) STUB(ef, zero)
+
+STUB(f0, zero) STUB(f1, zero) STUB(f2, zero) STUB(f3, zero)
+STUB(f4, zero) STUB(f5, zero) STUB(f6, zero) STUB(f7, zero)
+STUB(f8, zero) STUB(f9, zero) STUB(fa, zero) STUB(fb, zero)
+STUB(fc, zero) STUB(fd, zero) STUB(fe, zero) STUB(ff, zero)
index 116b637e3cd0b7560f4a5d3dae57b475f80ba0db..9ceba157e27e57d74a9096a2f35f0ff3008ffb10 100644 (file)
@@ -4,10 +4,9 @@
 /* Interrupt stubs.
 
    These are little snippets of code in intr-stubs.S, one for
 /* Interrupt stubs.
 
    These are little snippets of code in intr-stubs.S, one for
-   each of the 256 possible x86 interrupts.  They just push the
-   interrupt vector number on the stack (and, for interrupts that
-   don't have an error code, a fake error code), then jump to
-   intr_entry().
+   each of the 256 possible x86 interrupts.  Each one does a
+   little bit of stack manipulation, then jumps to intr_entry().
+   See intr-stubs.S for more information.
 
    This array points to each of the interrupt stub entry points
    so that intr_init() can easily find them. */
 
    This array points to each of the interrupt stub entry points
    so that intr_init() can easily find them. */
diff --git a/src/threads/intr-stubs.pl b/src/threads/intr-stubs.pl
deleted file mode 100755 (executable)
index 75cde7b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#! /usr/bin/perl
-
-print <<'EOF';
-#include "threads/loader.h"
-
-       .data
-       .intel_syntax noprefix
-.globl intr_stubs
-intr_stubs:
-EOF
-
-for $i (0...255) {
-    $x = sprintf ("%02x", $i);
-    print "\t.long intr${x}_stub\n";
-}
-
-print <<'EOF';
-
-       .text
-EOF
-
-for $i (0...255) {
-    $x = sprintf ("%02x", $i);
-    print ".globl intr${x}_stub\n";
-    print "intr${x}_stub:\n";
-    print "\tpush 0\n"
-       if ($i != 8 && $i != 10 && $i != 11
-           && $i != 13 && $i != 14 && $i != 17);
-    print "\tpush 0x$x\n";
-    print "\tjmp intr_entry\n";
-}
-
-print <<'EOF';
-intr_entry:
-       # Save caller's registers.
-       push ds
-       push es
-       push fs
-       push gs
-       pusha
-
-       # Set up kernel environment.
-       cld
-       mov eax, SEL_KDSEG
-       mov ds, eax
-       mov es, eax
-
-       # Call interrupt handler.
-       push esp
-.globl intr_handler
-       call intr_handler
-       add esp, 4
-
-.globl intr_exit
-intr_exit:
-       # Restore caller's registers.
-       popa
-       pop gs
-       pop fs
-       pop es
-       pop ds
-       add esp, 8
-
-        # Return to caller.
-       iret
-EOF
index c0a6547acb0e09a7717d43ab8fb7199e8ae7248b..88c9d8dcae20995bb5e7dc3b4b2d5a42ca5b8e6e 100644 (file)
@@ -73,7 +73,7 @@ execute_thread (void *filename_)
 
   /* Start the user process by simulating a return from an
      interrupt, implemented by intr_exit (in
 
   /* Start the user process by simulating a return from an
      interrupt, implemented by intr_exit (in
-     threads/intr-stubs.pl).  Because intr_exit takes all of its
+     threads/intr-stubs.S).  Because intr_exit takes all of its
      arguments on the stack in the form of a `struct intr_frame',
      we just point the stack pointer (%esp) to our stack frame
      and jump to it. */
      arguments on the stack in the form of a `struct intr_frame',
      we just point the stack pointer (%esp) to our stack frame
      and jump to it. */