6 /* System segment or code/data segment? */
9 CLS_SYSTEM = 0, /* System segment. */
10 CLS_CODE_DATA = 1 /* Code or data segment. */
13 /* Limit has byte or 4 kB page granularity? */
16 GRAN_BYTE = 0, /* Limit has 1-byte granularity. */
17 GRAN_PAGE = 1 /* Limit has 4 kB granularity. */
20 /* Returns a segment descriptor with the given 32-bit BASE and
21 20-bit LIMIT (whose interpretation depends on GRANULARITY).
22 The descriptor represents a system or code/data segment
23 according to CLASS, and TYPE is its type (whose interpretation
24 depends on the class).
26 The segment has descriptor privilege level DPL, meaning that
27 it can be used in rings numbered DPL or lower. In practice,
28 DPL==3 means that user processes can use the segment and
29 DPL==0 means that only the kernel can use the segment. See
30 [IA32-v3] section 4.5 for further discussion. */
32 make_seg_desc (uint32_t base,
37 enum seg_granularity granularity)
41 ASSERT (limit <= 0xfffff);
42 ASSERT (class == CLS_SYSTEM || class == CLS_CODE_DATA);
43 ASSERT (type >= 0 && type <= 15);
44 ASSERT (dpl >= 0 && dpl <= 3);
45 ASSERT (granularity == GRAN_BYTE || granularity == GRAN_PAGE);
47 e0 = ((limit & 0xffff) /* Limit 15:0. */
48 | (base << 16)); /* Base 15:0. */
50 e1 = (((base >> 16) & 0xff) /* Base 23:16. */
51 | (type << 8) /* Segment type. */
52 | (class << 12) /* 0=system, 1=code/data. */
53 | (dpl << 13) /* Descriptor privilege. */
54 | (1 << 15) /* Present. */
55 | (limit & 0xf0000) /* Limit 16:19. */
56 | (1 << 22) /* 32-bit segment. */
57 | (granularity << 23) /* Byte/page granularity. */
58 | (base & 0xff000000)); /* Base 31:24. */
60 return e0 | ((uint64_t) e1 << 32);
63 /* Returns a descriptor for a readable code segment with base at
64 0, a limit of 4 GB, and the given DPL. */
66 make_code_desc (int dpl)
68 return make_seg_desc (0, 0xfffff, CLS_CODE_DATA, 10, dpl, GRAN_PAGE);
71 /* Returns a descriptor for a writable data segment with base at
72 0, a limit of 4 GB, and the given DPL. */
74 make_data_desc (int dpl)
76 return make_seg_desc (0, 0xfffff, CLS_CODE_DATA, 2, dpl, GRAN_PAGE);
79 /* Returns a descriptor for an "available" 32-bit Task-State
80 Segment with its base at the given linear address, a limit of
81 0x67 bytes (the size of a 32-bit TSS), and a DPL of 0. */
83 make_tss_desc (void *laddr)
85 return make_seg_desc ((uint32_t) laddr, 0x67, CLS_SYSTEM, 9, 0, GRAN_BYTE);
88 static uint64_t gdt[SEL_CNT];
92 /* Sets up a proper GDT. The bootstrap loader's GDT didn't
93 include user-mode selectors or a TSS. */
97 uint64_t gdtr_operand;
99 /* Our TSS is never used in a call gate or task gate, so only a
100 few fields of it are ever referenced, and those are the only
101 ones we initialize. */
102 tss = palloc_get (PAL_ASSERT | PAL_ZERO);
103 tss->esp0 = (uint32_t) ptov(0x20000);
104 tss->ss0 = SEL_KDSEG;
105 tss->bitmap = 0xdfff;
107 /* Initialize GDT. */
108 gdt[SEL_NULL / sizeof *gdt] = 0;
109 gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
110 gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
111 gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
112 gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
113 gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss);
116 gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
117 asm volatile ("lgdt %0" :: "m" (gdtr_operand));
118 asm volatile ("ltr %w0" :: "r" (SEL_TSS));