# 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.
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
--- /dev/null
+#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));
+}
--- /dev/null
+#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 */
#include <stddef.h>
#include <limits.h>
#include "debug.h"
+#include "gdt.h"
#include "interrupt.h"
#include "io.h"
#include "kbd.h"
#endif
static void ram_init (void);
-static void gdt_init (void);
static void argv_init (void);
static 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)
/* Physical memory size, in 4 kB pages. */
size_t ram_pages;
-struct tss *tss;
-
#endif /* init.h */
#include <stdint.h>
#include "intr-stubs.h"
#include "debug.h"
+#include "gdt.h"
#include "io.h"
#include "lib.h"
#include "mmu.h"
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);
}
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
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. */
#! /usr/bin/perl
print <<'EOF';
-#include "mmu.h"
+#include "gdt.h"
.data
.globl intr_stubs
-#include "mmu.h"
#include "loader.h"
+#include "mmu.h"
+#include "gdt.h"
##############################################################################
# Kernel loader.
#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. */
#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_ */
#include "interrupt.h"
#include "intr-stubs.h"
#include "lib.h"
+#include "gdt.h"
#include "mmu.h"
#include "palloc.h"
#include "random.h"
#include "debug.h"
#include "file.h"
#include "filesys.h"
+#include "gdt.h"
#include "init.h"
#include "lib.h"
#include "mmu.h"