1 /*
2 * Copyright (c) 2009 Corey Tabaka
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8 #include <arch/x86/descriptor.h>
9
10 #include <assert.h>
11 #include <lk/compiler.h>
12
13 extern uint64_t _gdt[];
14
x86_set_gdt_descriptor(seg_sel_t sel,void * base,uint32_t limit,uint8_t present,uint8_t ring,uint8_t sys,uint8_t type,uint8_t gran,uint8_t bits)15 void x86_set_gdt_descriptor(seg_sel_t sel, void *base, uint32_t limit,
16 uint8_t present, uint8_t ring, uint8_t sys, uint8_t type, uint8_t gran, uint8_t bits) {
17 typedef struct {
18 struct {
19 uint16_t limit_15_0;
20 uint16_t base_15_0;
21 uint8_t base_23_16;
22
23 uint8_t type : 4;
24 uint8_t s : 1;
25 uint8_t dpl : 2;
26 uint8_t p : 1;
27
28 uint8_t limit_19_16 : 4;
29 uint8_t avl : 1;
30 uint8_t reserved : 1;
31 uint8_t d_b : 1;
32 uint8_t g : 1;
33
34 uint8_t base_31_24;
35 } seg_desc_legacy;
36
37 #if ARCH_X86_64
38 // some descriptors have additional fields for x86-64
39 struct {
40 uint32_t base_63_32;
41 uint32_t reserved;
42 } seg_desc_64;
43 #endif
44 } seg_desc_t;
45
46 #if ARCH_X86_64
47 static_assert(sizeof(seg_desc_t) == 16, "seg_desc_t size mismatch");
48 #else
49 static_assert(sizeof(seg_desc_t) == 8, "seg_desc_t size mismatch");
50 #endif
51
52 seg_desc_t desc = {0};
53
54 desc.seg_desc_legacy.limit_15_0 = limit & 0x0000ffff;
55 desc.seg_desc_legacy.limit_19_16 = (limit & 0x000f0000) >> 16;
56
57 desc.seg_desc_legacy.base_15_0 = ((uintptr_t) base) & 0x0000ffff;
58 desc.seg_desc_legacy.base_23_16 = (((uintptr_t) base) & 0x00ff0000) >> 16;
59 desc.seg_desc_legacy.base_31_24 = ((uintptr_t) base) >> 24;
60
61 desc.seg_desc_legacy.type = type & 0x0f; // segment type
62 desc.seg_desc_legacy.s = sys != 0; // system / non-system
63 desc.seg_desc_legacy.dpl = ring & 0x03; // descriptor privilege level
64 desc.seg_desc_legacy.p = present != 0; // present
65 desc.seg_desc_legacy.avl = 0;
66 desc.seg_desc_legacy.reserved = 0;
67 desc.seg_desc_legacy.d_b = bits != 0; // 16 / 32 bit
68 desc.seg_desc_legacy.g = gran != 0; // granularity
69
70 // convert selector into index, which are always 8 byte indexed
71 uint16_t index = sel >> 3;
72 seg_desc_t *entry = (seg_desc_t *)&_gdt[index];
73 entry->seg_desc_legacy = desc.seg_desc_legacy;
74
75 #ifdef ARCH_X86_64
76 if (sys == 0) {
77 // some of the system descriptors have two more words
78 switch (type) {
79 case SEG_TYPE_TSS:
80 case SEG_TYPE_TSS_BUSY:
81 case SEG_TYPE_LDT:
82 case SEG_TYPE_CALL_GATE:
83 // copy the lower 32 bits of the descriptor (base and limit)
84 desc.seg_desc_64.base_63_32 = (uint32_t)((uintptr_t) base >> 32);
85 desc.seg_desc_64.reserved = 0;
86
87 // copy the upper 64 bits of the descriptor
88 entry->seg_desc_64 = desc.seg_desc_64;
89 break;
90 }
91 }
92 #endif
93 }
94