7 /* System segment or code/data segment? */
10 CLS_SYSTEM = 0, /* System segment. */
11 CLS_CODE_DATA = 1 /* Code or data segment. */
14 /* Limit has byte or 4 kB page granularity? */
17 GRAN_BYTE = 0, /* Limit has 1-byte granularity. */
18 GRAN_PAGE = 1 /* Limit has 4 kB granularity. */
21 /* Returns a segment descriptor with the given 32-bit BASE and
22 20-bit LIMIT (whose interpretation depends on GRANULARITY).
23 The descriptor represents a system or code/data segment
24 according to CLASS, and TYPE is its type (whose interpretation
25 depends on the class).
27 The segment has descriptor privilege level DPL, meaning that
28 it can be used in rings numbered DPL or lower. In practice,
29 DPL==3 means that user processes can use the segment and
30 DPL==0 means that only the kernel can use the segment. See
31 [IA32-v3] section 4.5 for further discussion. */
33 make_seg_desc (uint32_t base,
38 enum seg_granularity granularity)
42 ASSERT (limit <= 0xfffff);
43 ASSERT (class == CLS_SYSTEM || class == CLS_CODE_DATA);
44 ASSERT (type >= 0 && type <= 15);
45 ASSERT (dpl >= 0 && dpl <= 3);
46 ASSERT (granularity == GRAN_BYTE || granularity == GRAN_PAGE);
48 e0 = ((limit & 0xffff) /* Limit 15:0. */
49 | (base << 16)); /* Base 15:0. */
51 e1 = (((base >> 16) & 0xff) /* Base 23:16. */
52 | (type << 8) /* Segment type. */
53 | (class << 12) /* 0=system, 1=code/data. */
54 | (dpl << 13) /* Descriptor privilege. */
55 | (1 << 15) /* Present. */
56 | (limit & 0xf0000) /* Limit 16:19. */
57 | (1 << 22) /* 32-bit segment. */
58 | (granularity << 23) /* Byte/page granularity. */
59 | (base & 0xff000000)); /* Base 31:24. */
61 return e0 | ((uint64_t) e1 << 32);
64 /* Returns a descriptor for a readable code segment with base at
65 0, a limit of 4 GB, and the given DPL. */
67 make_code_desc (int dpl)
69 return make_seg_desc (0, 0xfffff, CLS_CODE_DATA, 10, dpl, GRAN_PAGE);
72 /* Returns a descriptor for a writable data segment with base at
73 0, a limit of 4 GB, and the given DPL. */
75 make_data_desc (int dpl)
77 return make_seg_desc (0, 0xfffff, CLS_CODE_DATA, 2, dpl, GRAN_PAGE);
80 /* Returns a descriptor for an "available" 32-bit Task-State
81 Segment with its base at the given linear address, a limit of
82 0x67 bytes (the size of a 32-bit TSS), and a DPL of 0. */
84 make_tss_desc (void *laddr)
86 return make_seg_desc ((uint32_t) laddr, 0x67, CLS_SYSTEM, 9, 0, GRAN_BYTE);
89 static uint64_t gdt[SEL_CNT];
91 /* Sets up a proper GDT. The bootstrap loader's GDT didn't
92 include user-mode selectors or a TSS. */
96 uint64_t gdtr_operand;
99 gdt[SEL_NULL / sizeof *gdt] = 0;
100 gdt[SEL_KCSEG / sizeof *gdt] = make_code_desc (0);
101 gdt[SEL_KDSEG / sizeof *gdt] = make_data_desc (0);
102 gdt[SEL_UCSEG / sizeof *gdt] = make_code_desc (3);
103 gdt[SEL_UDSEG / sizeof *gdt] = make_data_desc (3);
104 gdt[SEL_TSS / sizeof *gdt] = make_tss_desc (tss_get ());
107 gdtr_operand = make_dtr_operand (sizeof gdt - 1, gdt);
108 asm volatile ("lgdt %0" :: "m" (gdtr_operand));
109 asm volatile ("ltr %w0" :: "r" (SEL_TSS));