Only call addrspace_destroy() if USERPROG.
[pintos-anon] / src / threads / gdt.c
1 #include "gdt.h"
2 #include "debug.h"
3 #include "mmu.h"
4 #include "palloc.h"
5 #include "tss.h"
6
7 /* The Global Descriptor Table (GDT).
8
9    The GDT, an x86-specific structure, defines segments that can
10    potentially be used by all processes in a system, subject to
11    their permissions.  There is also a per-process Local
12    Descriptor Table (LDT) but that is not used by modern
13    operating systems.
14
15    Each entry in the GDT, which is known by its byte offset in
16    the table, identifies a segment.  For our purposes only three
17    types of segments are of interest: code, data, and TSS or
18    Task-State Segment descriptors.  The former two types are
19    exactly what they sound like.  The TSS is used primarily for
20    stack switching on interrupts.
21
22    For more information on the GDT as used here, refer to
23    [IA32-v3] sections 3.2 through 3.5. */
24 static uint64_t gdt[SEL_CNT];
25
26 /* Creating descriptors. */
27 static uint64_t make_code_desc (int dpl);
28 static uint64_t make_data_desc (int dpl);
29 static uint64_t make_tss_desc (void *laddr);
30
31 /* Sets up a proper GDT.  The bootstrap loader's GDT didn't
32    include user-mode selectors or a TSS, but we need both now. */
33 void
34 gdt_init (void)
35 {
36   uint64_t gdtr_operand;
37
38   /* Initialize GDT. */
39   gdt[SEL_NULL / sizeof *gdt] = 0;
40   gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
41   gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
42   gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
43   gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
44   gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss_get ());
45
46   /* Load GDTR, TR. */
47   gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
48   asm volatile ("lgdt %0" :: "m" (gdtr_operand));
49   asm volatile ("ltr %w0" :: "r" (SEL_TSS));
50 }
51 \f
52 /* System segment or code/data segment? */
53 enum seg_class
54   {
55     CLS_SYSTEM = 0,             /* System segment. */
56     CLS_CODE_DATA = 1           /* Code or data segment. */
57   };
58
59 /* Limit has byte or 4 kB page granularity? */
60 enum seg_granularity
61   {
62     GRAN_BYTE = 0,              /* Limit has 1-byte granularity. */
63     GRAN_PAGE = 1               /* Limit has 4 kB granularity. */
64   };
65
66 /* Returns a segment descriptor with the given 32-bit BASE and
67    20-bit LIMIT (whose interpretation depends on GRANULARITY).
68    The descriptor represents a system or code/data segment
69    according to CLASS, and TYPE is its type (whose interpretation
70    depends on the class).
71
72    The segment has descriptor privilege level DPL, meaning that
73    it can be used in rings numbered DPL or lower.  In practice,
74    DPL==3 means that user processes can use the segment and
75    DPL==0 means that only the kernel can use the segment.  See
76    [IA32-v3] section 4.5 for further discussion. */
77 static uint64_t
78 make_seg_desc (uint32_t base,
79                uint32_t limit,
80                enum seg_class class,
81                int type,
82                int dpl,
83                enum seg_granularity granularity)
84 {
85   uint32_t e0, e1;
86
87   ASSERT (limit <= 0xfffff);
88   ASSERT (class == CLS_SYSTEM || class == CLS_CODE_DATA);
89   ASSERT (type >= 0 && type <= 15);
90   ASSERT (dpl >= 0 && dpl <= 3);
91   ASSERT (granularity == GRAN_BYTE || granularity == GRAN_PAGE);
92
93   e0 = ((limit & 0xffff)             /* Limit 15:0. */
94         | (base << 16));             /* Base 15:0. */
95
96   e1 = (((base >> 16) & 0xff)        /* Base 23:16. */
97         | (type << 8)                /* Segment type. */
98         | (class << 12)              /* 0=system, 1=code/data. */
99         | (dpl << 13)                /* Descriptor privilege. */
100         | (1 << 15)                  /* Present. */
101         | (limit & 0xf0000)          /* Limit 16:19. */
102         | (1 << 22)                  /* 32-bit segment. */
103         | (granularity << 23)        /* Byte/page granularity. */
104         | (base & 0xff000000));      /* Base 31:24. */
105
106   return e0 | ((uint64_t) e1 << 32);
107 }
108
109 /* Returns a descriptor for a readable code segment with base at
110    0, a limit of 4 GB, and the given DPL. */
111 static uint64_t
112 make_code_desc (int dpl)
113 {
114   return make_seg_desc (0, 0xfffff, CLS_CODE_DATA, 10, dpl, GRAN_PAGE);
115 }
116
117 /* Returns a descriptor for a writable data segment with base at
118    0, a limit of 4 GB, and the given DPL. */
119 static uint64_t
120 make_data_desc (int dpl)
121 {
122   return make_seg_desc (0, 0xfffff, CLS_CODE_DATA, 2, dpl, GRAN_PAGE);
123 }
124
125 /* Returns a descriptor for an "available" 32-bit Task-State
126    Segment with its base at the given linear address, a limit of
127    0x67 bytes (the size of a 32-bit TSS), and a DPL of 0. */
128 static uint64_t
129 make_tss_desc (void *laddr)
130 {
131   return make_seg_desc ((uint32_t) laddr, 0x67, CLS_SYSTEM, 9, 0, GRAN_BYTE);
132 }
133