Add comments.
authorBen Pfaff <blp@cs.stanford.edu>
Sun, 5 Sep 2004 07:59:21 +0000 (07:59 +0000)
committerBen Pfaff <blp@cs.stanford.edu>
Sun, 5 Sep 2004 07:59:21 +0000 (07:59 +0000)
src/userprog/gdt.c
src/userprog/tss.c

index e3e1ddea4a3e82baa10cbc318230fc6c2d380fac..c1228495499c664a00b60092c57003a5c6cef23f 100644 (file)
@@ -44,7 +44,7 @@ gdt_init (void)
   gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
   gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss_get ());
 
-  /* Load GDTR, TR. */
+  /* Load GDTR, TR.  See [IA32-v3] 2.4.1, 2.4.4, 6.2.3.  */
   gdtr_operand = make_gdtr_operand (sizeof gdt - 1, gdt);
   asm volatile ("lgdt %0" :: "m" (gdtr_operand));
   asm volatile ("ltr %w0" :: "r" (SEL_TSS));
@@ -125,7 +125,8 @@ make_data_desc (int dpl)
 
 /* Returns a descriptor for an "available" 32-bit Task-State
    Segment with its base at the given linear address, a limit of
-   0x67 bytes (the size of a 32-bit TSS), and a DPL of 0. */
+   0x67 bytes (the size of a 32-bit TSS), and a DPL of 0.
+   See [IA32-v3] 6.2.2. */
 static uint64_t
 make_tss_desc (void *laddr)
 {
index 37d075b22ac5594a31d624ffe72cb0ecda751897..4b32d8507976f6995d8c242bdc8664b9ce034fbb 100644 (file)
@@ -5,11 +5,52 @@
 #include "mmu.h"
 #include "palloc.h"
 
+/* The Task-State Segment (TSS).
+
+   Instances of the TSS, an x86-specific structure, are used to
+   define "tasks", a form of support for multitasking built right
+   into the processor.  However, for various reasons including
+   portability, speed, and flexibility, most x86 OSes almost
+   completely ignore the TSS.  We are no exception.
+
+   Unfortunately, there is one thing that can only be done using
+   a TSS: stack switching for interrupts that occur in user mode.
+   When an interrupt occurs in user mode (ring 3), the processor
+   consults the ss0 and esp0 members of the current TSS to
+   determine the stack to use for handling the interrupt.  Thus,
+   we must create a TSS and initialize at least these fields, and
+   this is precisely what this file does.
+
+   When an interrupt is handled by an interrupt or trap gate
+   (which applies to all interrupts we handle), an x86 processor
+   works like this:
+
+     - If the code interrupted by the interrupt is in the same
+       ring as the interrupt handler, then no stack switch takes
+       place.  This is the case for interrupts that happen when
+       we're running in the kernel.  The contents of the TSS are
+       irrelevant for this case.
+
+     - If the interrupted code is in a different ring from the
+       handler, then the processor switches to the stack
+       specified in the TSS for the new ring.  This is the case
+       for interrupts that happen when we're in user space.  It's
+       important that we switch to a stack that's not already in
+       use, to avoid corruption.  Because we're running in user
+       space, we know that the current process's kernel stack is
+       not in use, so we can always use that.  Thus, when the
+       scheduler switches threads, it also changes the TSS's
+       stack pointer to point to the new thread's kernel stack.
+       (The call is in schedule_tail() in thread.c.)
+
+   See [IA32-v3] 6.2.1 for a description of the TSS and 5.12.1
+   for a description of when and how stack switching occurs
+   during an interrupt. */
 struct tss
   {
     uint16_t back_link, :16;
-    void *esp0;
-    uint16_t ss0, :16;
+    void *esp0;                         /* Ring 0 stack virtual address. */
+    uint16_t ss0, :16;                  /* Ring 0 stack segment selector. */
     void *esp1;
     uint16_t ss1, :16;
     void *esp2;
@@ -29,8 +70,10 @@ struct tss
     uint16_t trace, bitmap;
   };
 
+/* Kernel TSS. */
 static struct tss *tss;
 
+/* Initializes the kernel TSS. */
 void
 tss_init (void) 
 {
@@ -43,6 +86,7 @@ tss_init (void)
   tss->bitmap = 0xdfff;
 }
 
+/* Returns the kernel TSS. */
 struct tss *
 tss_get (void) 
 {
@@ -50,6 +94,7 @@ tss_get (void)
   return tss;
 }
 
+/* Sets the ring 0 stack pointer in the TSS to ESP0. */
 void
 tss_set_esp0 (uint8_t *esp0) 
 {