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.
 
-@item intr-stubs.pl
+@item intr-stubs.S
 @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
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
-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
index aa8e650dffb18ea253398ef642e345e1edc6e178..d4c6d659d0afc5af2da03dbe67751d10beff0324 100644 (file)
@@ -67,9 +67,6 @@ DEPENDS = $(patsubst %.o,%.d,$(OBJECTS))
 
 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
 
@@ -92,7 +89,7 @@ os.dsk: loader.bin kernel.bin
 
 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
 
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
-   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) 
 {
index 99abf8e3a92ddecff94064dd7bbaf5f0086e774d..b805671e626d6891f1b43aa06de64674f15a91d6 100644 (file)
@@ -19,7 +19,7 @@ enum intr_level intr_disable (void);
 /* 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. */
@@ -34,13 +34,18 @@ struct intr_frame
     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,
-       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. */
 
+    /* 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. */
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
-   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. */
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
-     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. */