AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
gdt.c
Go to the documentation of this file.
1
9
10
11#include <core/system.h>
12#include <core/panic.h>
13#include <core/assert.h>
14#include <core/string.h>
15
16#include <cpu/msr.h>
17#include <sys/cpu.h>
18
19#include "cpu.h"
20
21#define RW_DATA 0x2
22#define XR_CODE 0xA
23#define TSS_AVL 0x9
24
25#define BASE 0
26#define LIMIT -1
27
28#define DPL0 0
29#define DPL3 3
30
31#if ARCH_BITS==32
32#define L 0
33#define D 1
34#else
35#define L 1
36#define D 0
37#endif
38
39/* The segments every CPU has; its TSS and its own segment come after. */
40static const struct x86_gdt_entry gdt_template[X86_GDT_TSS] = {
41 /* the null segment */
42 {0},
43
44 /* the kernel's code segment */
45 {LIMIT, BASE, BASE, XR_CODE, 1, DPL0, 1, LIMIT, 0, L, D, 1, BASE},
46
47 /* the kernel's data segment */
48 {LIMIT, BASE, BASE, RW_DATA, 1, DPL0, 1, LIMIT, 0, L, D, 1, BASE},
49
50 /* user mode's code segment */
51 {LIMIT, BASE, BASE, XR_CODE, 1, DPL3, 1, LIMIT, 0, L, D, 1, BASE},
52
53 /* user mode's data segment */
54 {LIMIT, BASE, BASE, RW_DATA, 1, DPL3, 1, LIMIT, 0, L, D, 1, BASE},
55};
56
57#define MSR_GS_BASE 0xC0000101
58#define MSR_KERNEL_GS_BASE 0xC0000102
59
62static void segment_set(struct x86_gdt_entry *e, uintptr_t base, size_t limit)
63{
64 e->limit_lo = limit & 0xFFFF;
65 e->base_lo = base & 0xFFFF;
66 e->base_mid = (base >> 16) & 0xFF;
67 e->limit_hi = (limit >> 16) & 0xF;
68 e->base_hi = (base >> 24) & 0xFF;
69}
70
79void x86_gdt_setup(struct cpu *cpu, uintptr_t sp)
80{
81 struct arch_cpu *arch = &cpu->arch;
82 struct x86_tss *tss = &arch->tss;
83
85 assert_sizeof(struct x86_tss, 104);
86 assert_alignof(arch->gdt, 8);
87 assert_alignof(tss, 8);
88
89 memset(arch->gdt, 0, sizeof(arch->gdt));
90 memcpy(arch->gdt, gdt_template, sizeof(gdt_template));
91
92 memset(tss, 0, sizeof(*tss));
93#if ARCH_BITS==32
94 tss->ss = 0x10;
95#endif
96 tss->sp = sp;
97
98 /*
99 * The I/O map base (the upper half of the dword at offset 100) must
100 * point past the TSS's limit. Otherwise the TSS's own bytes are used
101 * as the I/O permission bitmap, and user mode could use random I/O
102 * ports.
103 */
104#if ARCH_BITS==32
105 tss->_[22] = (uint32_t) sizeof(*tss) << 16;
106#else
107 tss->__[22] = (uint32_t) sizeof(*tss) << 16;
108#endif
109
110 /* the TSS's segment */
111 struct x86_gdt_entry *e = &arch->gdt[X86_GDT_TSS];
112 segment_set(e, (uintptr_t) tss, sizeof(*tss) - 1);
113 e->type = TSS_AVL;
114 e->dpl = DPL3;
115 e->p = 1;
116
117#if ARCH_BITS==64
118 uint32_t *base_high = (uint32_t *) &arch->gdt[X86_GDT_TSS + 1];
119 *base_high = (uintptr_t) tss >> 32;
120#else
121 /* the CPU's own segment: %gs:0 is cpu->self */
122 e = &arch->gdt[X86_GDT_CPU];
123 segment_set(e, (uintptr_t) cpu, sizeof(*cpu) - 1);
124 e->type = RW_DATA;
125 e->s = 1;
126 e->dpl = DPL0;
127 e->p = 1;
128 e->db = 1;
129#endif
130
131 cpu->self = cpu;
132
133 x86_lgdt(sizeof(arch->gdt) - 1, (uintptr_t) arch->gdt);
134 x86_ltr((X86_GDT_TSS << 3) | DPL3);
135
136#if ARCH_BITS==32
137 asm volatile("movw %w0, %%gs" :: "r"(X86_SEL_CPU));
138#else
139 /* the kernel's GS base; user mode's (none yet) is swapped in on the
140 * way out to user mode */
141 msr_write(MSR_GS_BASE, (uintptr_t) cpu);
142 msr_write(MSR_KERNEL_GS_BASE, 0);
143#endif
144}
145
153{
154 curcpu()->arch.tss.sp = sp;
155}
void x86_ltr(uintptr_t)
void x86_lgdt(uint16_t, uintptr_t)
#define X86_GDT_CPU
Definition cpu.h:115
#define X86_GDT_TSS
Definition cpu.h:114
#define X86_SEL_CPU
Definition cpu.h:118
#define assert_alignof(o, al)
Definition assert.h:21
#define assert_sizeof(o, sz)
Definition assert.h:15
static void segment_set(struct x86_gdt_entry *e, uintptr_t base, size_t limit)
Sets the base and limit of a system or data segment descriptor, with byte granularity.
Definition gdt.c:62
#define TSS_AVL
Definition gdt.c:23
static const struct x86_gdt_entry gdt_template[X86_GDT_TSS]
Definition gdt.c:40
void x86_kernel_stack_set(uintptr_t sp)
Sets the kernel stack that interrupts from user mode switch to, on the running CPU: the thread that i...
Definition gdt.c:152
#define LIMIT
Definition gdt.c:26
#define DPL0
Definition gdt.c:28
#define DPL3
Definition gdt.c:29
#define BASE
Definition gdt.c:25
#define XR_CODE
Definition gdt.c:22
#define L
Definition gdt.c:35
#define MSR_GS_BASE
Definition gdt.c:57
#define MSR_KERNEL_GS_BASE
Definition gdt.c:58
#define D
Definition gdt.c:36
#define RW_DATA
Definition gdt.c:21
void x86_gdt_setup(struct cpu *cpu, uintptr_t sp)
Sets up and loads the running CPU's GDT and TSS, and points gs (or the GS base, on x86_64) at its str...
Definition gdt.c:79
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
__SIZE_TYPE__ uintptr_t
Definition stddef.h:12
unsigned int uint32_t
Definition stddef.h:22
A CPU's aarch64 state (struct cpu's arch).
Definition cpu.h:51
struct x86_tss tss
Definition cpu.h:127
struct x86_gdt_entry gdt[X86_GDT_NR]
Definition cpu.h:126
A processor, and what runs on it.
Definition cpu.h:11
struct cpu * self
Definition cpu.h:12
struct arch_cpu arch
Definition cpu.h:17
A segment descriptor, an entry of the GDT.
Definition cpu.h:74
uint32_t s
Definition cpu.h:80
uint32_t base_lo
Definition cpu.h:76
uint32_t dpl
Definition cpu.h:81
uint32_t limit_lo
Definition cpu.h:75
uint32_t base_mid
Definition cpu.h:78
uint32_t type
Definition cpu.h:79
uint32_t base_hi
Definition cpu.h:89
uint32_t p
Definition cpu.h:82
uint32_t db
Definition cpu.h:87
uint32_t limit_hi
Definition cpu.h:84
Definition cpu.h:102
uint32_t __[23]
Definition cpu.h:105
uint32_t _
Definition cpu.h:103
uint64_t sp
Definition cpu.h:104