Break GDT, TSS out of init.c, mmu.h.
authorBen Pfaff <blp@cs.stanford.edu>
Wed, 1 Sep 2004 22:13:26 +0000 (22:13 +0000)
committerBen Pfaff <blp@cs.stanford.edu>
Wed, 1 Sep 2004 22:13:26 +0000 (22:13 +0000)
src/Makefile.inc
src/threads/gdt.c [new file with mode: 0644]
src/threads/gdt.h [new file with mode: 0644]
src/threads/init.c
src/threads/init.h
src/threads/interrupt.c
src/threads/intr-stubs.pl
src/threads/loader.S
src/threads/mmu.h
src/threads/thread.c
src/userprog/addrspace.c

index 137beaab2a20a3f87111ed33174ebeca4d9abf8b..d6b9519edd9052672a8b97daedcabbea5de3b5d3 100644 (file)
@@ -16,7 +16,8 @@ ASFLAGS = -Wa,--gstabs+ $(INCLUDES) $(DEFINES)
 
 # Core kernel.
 THREADS_SRC  = start.S         # Must be linked first.
-THREADS_SRC += init.c          # Start-up code.
+THREADS_SRC += init.c          # Main program.
+THREADS_SRC += gdt.c           # GDT initialization.
 THREADS_SRC += thread.c                # Thread management core.
 THREADS_SRC += switch.S                # Thread switch routine.
 THREADS_SRC += interrupt.c     # Interrupt core.
@@ -55,7 +56,7 @@ OBJECTS = $(patsubst %.c,%.o,$(patsubst %.S,%.o,$(SOURCES)))
 
 all: diskimage.bin
 
-intr-stubs.S: $(TOP_SRCDIR)/threads/intr-stubs.pl
+intr-stubs.S: $(TOP_SRCDIR)/threads/intr-stubs.pl $(TOP_SRCDIR)/threads/gdt.h
        $< > $@
 
 kernel.lds.s: $(TOP_SRCDIR)/threads/kernel.lds.S $(TOP_SRCDIR)/threads/loader.h
diff --git a/src/threads/gdt.c b/src/threads/gdt.c
new file mode 100644 (file)
index 0000000..2fd6948
--- /dev/null
@@ -0,0 +1,119 @@
+#include "gdt.h"
+#include "debug.h"
+#include "mmu.h"
+#include "palloc.h"
+
+/* System segment or code/data segment? */
+enum seg_class
+  {
+    CLS_SYSTEM = 0,             /* System segment. */
+    CLS_CODE_DATA = 1           /* Code or data segment. */
+  };
+
+/* Limit has byte or 4 kB page granularity? */
+enum seg_granularity
+  {
+    GRAN_BYTE = 0,              /* Limit has 1-byte granularity. */
+    GRAN_PAGE = 1               /* Limit has 4 kB granularity. */
+  };
+
+/* Returns a segment descriptor with the given 32-bit BASE and
+   20-bit LIMIT (whose interpretation depends on GRANULARITY).
+   The descriptor represents a system or code/data segment
+   according to CLASS, and TYPE is its type (whose interpretation
+   depends on the class).
+
+   The segment has descriptor privilege level DPL, meaning that
+   it can be used in rings numbered DPL or lower.  In practice,
+   DPL==3 means that user processes can use the segment and
+   DPL==0 means that only the kernel can use the segment.  See
+   [IA32-v3] section 4.5 for further discussion. */
+static uint64_t
+make_seg_desc (uint32_t base,
+               uint32_t limit,
+               enum seg_class class,
+               int type,
+               int dpl,
+               enum seg_granularity granularity)
+{
+  uint32_t e0, e1;
+
+  ASSERT (limit <= 0xfffff);
+  ASSERT (class == CLS_SYSTEM || class == CLS_CODE_DATA);
+  ASSERT (type >= 0 && type <= 15);
+  ASSERT (dpl >= 0 && dpl <= 3);
+  ASSERT (granularity == GRAN_BYTE || granularity == GRAN_PAGE);
+
+  e0 = ((limit & 0xffff)             /* Limit 15:0. */
+        | (base << 16));             /* Base 15:0. */
+
+  e1 = (((base >> 16) & 0xff)        /* Base 23:16. */
+        | (type << 8)                /* Segment type. */
+        | (class << 12)              /* 0=system, 1=code/data. */
+        | (dpl << 13)                /* Descriptor privilege. */
+        | (1 << 15)                  /* Present. */
+        | (limit & 0xf0000)          /* Limit 16:19. */
+        | (1 << 22)                  /* 32-bit segment. */
+        | (granularity << 23)        /* Byte/page granularity. */
+        | (base & 0xff000000));      /* Base 31:24. */
+
+  return e0 | ((uint64_t) e1 << 32);
+}
+
+/* Returns a descriptor for a readable code segment with base at
+   0, a limit of 4 GB, and the given DPL. */
+static uint64_t
+make_code_desc (int dpl)
+{
+  return make_seg_desc (0, 0xfffff, CLS_CODE_DATA, 10, dpl, GRAN_PAGE);
+}
+
+/* Returns a descriptor for a writable data segment with base at
+   0, a limit of 4 GB, and the given DPL. */
+static uint64_t
+make_data_desc (int dpl)
+{
+  return make_seg_desc (0, 0xfffff, CLS_CODE_DATA, 2, dpl, GRAN_PAGE);
+}
+
+/* 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. */
+static uint64_t
+make_tss_desc (void *laddr)
+{
+  return make_seg_desc ((uint32_t) laddr, 0x67, CLS_SYSTEM, 9, 0, GRAN_BYTE);
+}
+
+static uint64_t gdt[SEL_CNT];
+
+struct tss *tss;
+
+/* Sets up a proper GDT.  The bootstrap loader's GDT didn't
+   include user-mode selectors or a TSS. */
+void
+gdt_init (void)
+{
+  uint64_t gdtr_operand;
+
+  /* Our TSS is never used in a call gate or task gate, so only a
+     few fields of it are ever referenced, and those are the only
+     ones we initialize. */
+  tss = palloc_get (PAL_ASSERT | PAL_ZERO);
+  tss->esp0 = (uint32_t) ptov(0x20000);
+  tss->ss0 = SEL_KDSEG;
+  tss->bitmap = 0xdfff;
+
+  /* Initialize GDT. */
+  gdt[SEL_NULL / sizeof *gdt] = 0;
+  gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
+  gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
+  gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
+  gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
+  gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss);
+
+  /* Load GDTR, TR. */
+  gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
+  asm volatile ("lgdt %0" :: "m" (gdtr_operand));
+  asm volatile ("ltr %w0" :: "r" (SEL_TSS));
+}
diff --git a/src/threads/gdt.h b/src/threads/gdt.h
new file mode 100644 (file)
index 0000000..68507bc
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef HEADER_GDT_H
+#define HEADER_GDT_H 1
+
+/* Segment selectors. */
+#define SEL_NULL        0x00    /* Null selector. */
+#define SEL_KCSEG       0x08    /* Kernel code selector. */
+#define SEL_KDSEG       0x10    /* Kernel data selector. */
+#define SEL_UCSEG       0x1B    /* User code selector. */
+#define SEL_UDSEG       0x23    /* User data selector. */
+#define SEL_TSS         0x28    /* Task-state segment. */
+#define SEL_CNT         6       /* Number of segments. */
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+struct tss
+  {
+    uint16_t back_link, :16;
+    uint32_t esp0;
+    uint16_t ss0, :16;
+    uint32_t esp1;
+    uint16_t ss1, :16;
+    uint32_t esp2;
+    uint16_t ss2, :16;
+    uint32_t cr3;
+    uint32_t eip;
+    uint32_t eflags;
+    uint32_t eax, ecx, edx, ebx;
+    uint32_t esp, ebp, esi, edi;
+    uint16_t es, :16;
+    uint16_t cs, :16;
+    uint16_t ss, :16;
+    uint16_t ds, :16;
+    uint16_t fs, :16;
+    uint16_t gs, :16;
+    uint16_t ldt, :16;
+    uint16_t trace, bitmap;
+  };
+
+
+static inline uint64_t
+make_dtr_operand (uint16_t limit, void *base)
+{
+  return limit | ((uint64_t) (uint32_t) base << 16);
+}
+
+extern struct tss *tss;
+
+void gdt_init (void);
+#endif
+
+#endif /* gdt.h */
index 8d354d43fdda51c5f9fbe2b0177f84b2e526f9f8..b70c16c43bee2046f4b134427dc60e811953b4e5 100644 (file)
@@ -3,6 +3,7 @@
 #include <stddef.h>
 #include <limits.h>
 #include "debug.h"
+#include "gdt.h"
 #include "interrupt.h"
 #include "io.h"
 #include "kbd.h"
@@ -37,7 +38,6 @@ static char *initial_program;
 #endif
 
 static void ram_init (void);
-static void gdt_init (void);
 static void argv_init (void);
 
 static void
@@ -90,81 +90,6 @@ main (void)
   thread_start ();
 }
 
-static uint64_t
-make_seg_desc (uint32_t base,
-               uint32_t limit,
-               enum seg_system system,
-               enum seg_type type,
-               int dpl,
-               enum seg_granularity granularity)
-{
-  uint32_t e0 = ((limit & 0xffff)             /* Limit 15:0. */
-                 | (base << 16));             /* Base 15:0. */
-  uint32_t e1 = (((base >> 16) & 0xff)        /* Base 23:16. */
-                 | (system << 12)             /* 0=system, 1=code/data. */
-                 | (type << 8)                /* Segment type. */
-                 | (dpl << 13)                /* Descriptor privilege. */
-                 | (1 << 15)                  /* Present. */
-                 | (limit & 0xf0000)          /* Limit 16:19. */
-                 | (1 << 22)                  /* 32-bit segment. */
-                 | (granularity << 23)        /* Byte/page granularity. */
-                 | (base & 0xff000000));      /* Base 31:24. */
-  return e0 | ((uint64_t) e1 << 32);
-}
-
-static uint64_t
-make_code_desc (int dpl)
-{
-  return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_CODE | TYPE_READABLE,
-                        dpl, GRAN_PAGE);
-}
-
-static uint64_t
-make_data_desc (int dpl)
-{
-  return make_seg_desc (0, 0xfffff, SYS_CODE_DATA, TYPE_WRITABLE,
-                        dpl, GRAN_PAGE);
-}
-
-static uint64_t
-make_tss_desc (void *vaddr)
-{
-  return make_seg_desc ((uint32_t) vaddr,
-                        0x67, SYS_SYSTEM, TYPE_TSS_32_A, 0, GRAN_BYTE);
-}
-
-static uint64_t gdt[SEL_CNT];
-
-struct tss *tss;
-
-/* Sets up a proper GDT.  The bootstrap loader's GDT didn't
-   include user-mode selectors or a TSS. */
-static void
-gdt_init (void)
-{
-  uint64_t gdtr_operand;
-
-  /* Our TSS is never used in a call gate or task gate, so only a
-     few fields of it are ever referenced, and those are the only
-     ones we initialize. */
-  tss = palloc_get (PAL_ASSERT | PAL_ZERO);
-  tss->esp0 = (uint32_t) ptov(0x20000);
-  tss->ss0 = SEL_KDSEG;
-  tss->bitmap = 0xdfff;
-
-  /* Initialize GDT. */
-  gdt[SEL_NULL / sizeof *gdt] = 0;
-  gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
-  gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
-  gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
-  gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
-  gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss);
-
-  /* Load GDTR, TR. */
-  gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
-  asm volatile ("lgdt %0" :: "m" (gdtr_operand));
-  asm volatile ("ltr %w0" :: "r" (SEL_TSS));
-}
 
 static void
 ram_init (void) 
index 1d6c5c6fdd2d88bdaf765e672f8924687d42f32a..fed649bb60e08a93b4c7c97ac3f1d02b04535653 100644 (file)
@@ -6,6 +6,4 @@
 /* Physical memory size, in 4 kB pages. */
 size_t ram_pages;
 
-struct tss *tss;
-
 #endif /* init.h */
index 268e3b530c4c5ab16034e134db28f49ad3bf41f0..7559447307db9ee59f672bf042e7e5f88a5b868c 100644 (file)
@@ -3,6 +3,7 @@
 #include <stdint.h>
 #include "intr-stubs.h"
 #include "debug.h"
+#include "gdt.h"
 #include "io.h"
 #include "lib.h"
 #include "mmu.h"
@@ -245,22 +246,28 @@ pic_end_of_interrupt (int irq)
    DPL==0 to be invoked.  See [IA32-v3] sections 4.5 and 4.8.1.1
    for further discussion.
 
-   TYPE must be either TYPE_INT_32 (for an interrupt gate) or
-   TYPE_TRAP_32 (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. */
+   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. */
 static uint64_t
-make_gate (void (*function) (void), int dpl, enum seg_type type)
+make_gate (void (*function) (void), int dpl, int type)
 {
-  uint32_t offset = (uint32_t) function;
-  uint32_t e0 = ((offset & 0xffff)            /* Offset 15:0. */
-                 | (SEL_KCSEG << 16));        /* Target code segment. */
-  uint32_t e1 = ((offset & 0xffff0000)        /* Offset 31:16. */
-                 | (1 << 15)                  /* Present. */
-                 | ((uint32_t) dpl << 13)     /* Descriptor privilege. */
-                 | (SYS_SYSTEM << 12)         /* System. */
-                 | ((uint32_t) type << 8));   /* Gate type. */
+  uint32_t e0, e1;
+
+  ASSERT (function != NULL);
+  ASSERT (dpl >= 0 && dpl <= 3);
+  ASSERT (type >= 0 && type <= 15);
+
+  e0 = (((uint32_t) function & 0xffff)     /* Offset 15:0. */
+        | (SEL_KCSEG << 16));              /* Target code segment. */
+
+  e1 = (((uint32_t) function & 0xffff0000) /* Offset 31:16. */
+        | (1 << 15)                        /* Present. */
+        | ((uint32_t) dpl << 13)           /* Descriptor privilege level. */
+        | (0 << 12)                        /* System. */
+        | ((uint32_t) type << 8));         /* Gate type. */
+
   return e0 | ((uint64_t) e1 << 32);
 }
 
@@ -269,7 +276,7 @@ make_gate (void (*function) (void), int dpl, enum seg_type type)
 static uint64_t
 make_intr_gate (void (*function) (void), int dpl)
 {
-  return make_gate (function, dpl, TYPE_INT_32);
+  return make_gate (function, dpl, 14);
 }
 
 /* Creates a trap gate that invokes FUNCTION with the given
@@ -277,7 +284,7 @@ make_intr_gate (void (*function) (void), int dpl)
 static uint64_t
 make_trap_gate (void (*function) (void), int dpl)
 {
-  return make_gate (function, dpl, TYPE_TRAP_32);
+  return make_gate (function, dpl, 15);
 }
 \f
 /* Interrupt handlers. */
index 472b125b316d5176d567b81616c19335f5dd38e2..d9e0dd35508fee62e9d3f8b758525bf4855c82c6 100755 (executable)
@@ -1,7 +1,7 @@
 #! /usr/bin/perl
 
 print <<'EOF';
-#include "mmu.h"
+#include "gdt.h"
 
        .data
 .globl intr_stubs
index 5a8eacde275eeab9017b69385987193567d77694..535c442c4f1f39a0d59cf43aa51c0e3cc8beee33 100644 (file)
@@ -1,5 +1,6 @@
-#include "mmu.h"
 #include "loader.h"
+#include "mmu.h"
+#include "gdt.h"
        
 ##############################################################################
 # Kernel loader.
index 76073976f6534319aee21cbbc96e7f91a51da20d..a4f1b3618570f552edddb3d9c83deb66d5f5838a 100644 (file)
@@ -119,11 +119,6 @@ vtop (void *vaddr)
 #define PG_U 0x4               /* User */
 #define PG_A 0x20              /* Accessed */
 #define PG_D 0x40              /* Dirty */
-/*
- * The PG_USER bits are not used by the kernel and they are
- * not interpreted by the hardware.  The kernel allows 
- * user processes to set them arbitrarily.
- */
 
 /* EFLAGS Register. */
 #define FLAG_MBS  0x00000002    /* Must be set. */
@@ -146,86 +141,5 @@ vtop (void *vaddr)
 #define STA_W 0x2              /* Writeable (non-executable segments) */
 
 
-/* Segment selectors. */
-#define SEL_NULL        0x00    /* Null selector. */
-#define SEL_KCSEG       0x08    /* Kernel code selector. */
-#define SEL_KDSEG       0x10    /* Kernel data selector. */
-#define SEL_UCSEG       0x1B    /* User code selector. */
-#define SEL_UDSEG       0x23    /* User data selector. */
-#define SEL_TSS         0x28    /* Task-state segment. */
-#define SEL_CNT         6       /* Number of segments. */
-
-#ifndef __ASSEMBLER__
-struct tss
-  {
-    uint16_t back_link, :16;
-    uint32_t esp0;
-    uint16_t ss0, :16;
-    uint32_t esp1;
-    uint16_t ss1, :16;
-    uint32_t esp2;
-    uint16_t ss2, :16;
-    uint32_t cr3;
-    uint32_t eip;
-    uint32_t eflags;
-    uint32_t eax, ecx, edx, ebx;
-    uint32_t esp, ebp, esi, edi;
-    uint16_t es, :16;
-    uint16_t cs, :16;
-    uint16_t ss, :16;
-    uint16_t ds, :16;
-    uint16_t fs, :16;
-    uint16_t gs, :16;
-    uint16_t ldt, :16;
-    uint16_t trace, bitmap;
-  };
-
-enum seg_system
-  {
-    SYS_SYSTEM = 0,             /* System segment. */
-    SYS_CODE_DATA = 1           /* Code or data segment. */
-  };
-
-enum seg_granularity
-  {
-    GRAN_BYTE = 0,              /* Limit has 1-byte granularity. */
-    GRAN_PAGE = 1               /* Limit has 4 kB granularity. */
-  };
-
-enum seg_type
-  {
-    /* System segment types. */
-    TYPE_TSS_16_A = 1,          /* 16-bit TSS (available). */
-    TYPE_LDT = 2,               /* LDT. */
-    TYPE_TSS_16_B = 3,          /* 16-bit TSS (busy). */
-    TYPE_CALL_16 = 4,           /* 16-bit call gate. */
-    TYPE_TASK = 5,              /* Task gate. */
-    TYPE_INT_16 = 6,            /* 16-bit interrupt gate. */
-    TYPE_TRAP_16 = 7,           /* 16-bit trap gate. */
-    TYPE_TSS_32_A = 9,          /* 32-bit TSS (available). */
-    TYPE_TSS_32_B = 11,         /* 32-bit TSS (busy). */
-    TYPE_CALL_32 = 12,          /* 32-bit call gate. */
-    TYPE_INT_32 = 14,           /* 32-bit interrupt gate. */
-    TYPE_TRAP_32 = 15,          /* 32-bit trap gate. */
-
-    /* Code/data segment types. */
-    TYPE_CODE = 8,              /* 1=Code segment, 0=data segment. */
-    TYPE_ACCESSED = 1,          /* Set if accessed. */
-
-    /* Data segment types. */
-    TYPE_EXPAND_DOWN = 4,       /* 1=Expands up, 0=expands down. */
-    TYPE_WRITABLE = 2,          /* 1=Read/write, 0=read-only. */
-
-    /* Code segment types. */
-    TYPE_CONFORMING = 4,        /* 1=Conforming, 0=nonconforming. */
-    TYPE_READABLE = 2           /* 1=Exec/read, 0=exec-only. */
-  };
-
-static inline uint64_t
-make_dtr_operand (uint16_t limit, void *base)
-{
-  return limit | ((uint64_t) (uint32_t) base << 16);
-}
-#endif
 
 #endif /* !_MMU_H_ */
index 13b0b7e7f37367db09e5b8f30f0bda6b0ae57488..fed6b841aded48864edee8307fec6fb6090c87ae 100644 (file)
@@ -4,6 +4,7 @@
 #include "interrupt.h"
 #include "intr-stubs.h"
 #include "lib.h"
+#include "gdt.h"
 #include "mmu.h"
 #include "palloc.h"
 #include "random.h"
index dc6cb727f262df24b82685affe0078d0525270bf..519da93cc90ed302ddf5ab3ea684d5ff8f95e238 100644 (file)
@@ -3,6 +3,7 @@
 #include "debug.h"
 #include "file.h"
 #include "filesys.h"
+#include "gdt.h"
 #include "init.h"
 #include "lib.h"
 #include "mmu.h"