summaryrefslogtreecommitdiff
path: root/src/kernel/arch/amd64/sysenter.s
blob: c1af69f8c119974318870623bd001e64850f61f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// gdt.h
.set SEG_r0code, 1
.set SEG_r3code32, 3
.set SEG_r3data, 4

.set IA32_STAR, 0xC0000081
.set IA32_LSTAR, 0xC0000082
.set IA32_CSTAR, 0xC0000083
.set IA32_FMASK, 0xC0000084

.section .text
.global sysenter_setup
.type sysenter_setup, @function
sysenter_setup:

	// the intel docs don't mention the lower 32 bits
	mov $0, %eax
	mov $( ((SEG_r3code32 << 3 | 3) << 16) | (SEG_r0code << 3) ), %edx
	mov $IA32_STAR, %rcx
	wrmsr

	mov $sysenter_stage1, %eax
	mov $0, %edx
	mov $IA32_LSTAR, %rcx
	wrmsr

	// hoping that the default RFLAGS mask is fine...

	ret


.section .shared

.global stored_rsp
stored_rsp:
	.skip 8

.global pagedir_current
// TODO make into an argument of sysexit
pagedir_current:
	.skip 8

.global _sysexit_real
.type _sysexit_real, @function
_sysexit_real:
	/* TODO check if SYSRET correctly sets segments
	mov $(SEG_r3data << 3 | 3), %ax
	mov %ax, %ds
	mov %ax, %es
	mov %ax, %fs
	mov %ax, %gs
	*/

	/* The state image referenced with an FXRSTOR instruction must have
	 * been saved using an  FXSAVE instruction or be in the same format
	 * as required [...] will result in an incorrect state restoration. */
	// TODO will probably end up fucking something up in a hard to debug way
	// sorry, future me. hopefully you have learned something from this
	fxrstor (_sysexit_regs + 128)
	mov $_sysexit_regs, %rsp
	pop %r15
	pop %r14
	pop %r13
	pop %r12

	pop %r11
	pop %r10
	pop %r9
	pop %r8

	pop %rdi
	pop %rsi
	pop %rbp
	pop (stored_rsp)

	pop %rbx
	pop %rdx
	pop %rcx
	pop %rax

	// enable paging
	mov (pagedir_current), %rsp
	mov %rsp, %cr3
	mov (stored_rsp), %rsp
	sysretq

sysenter_stage1:
	cli

	mov %rsp, (stored_rsp)

	mov $pml4_identity, %rsp
	mov %rsp, %cr3

	fxsave (_sysexit_regs + 128)
	mov $(_sysexit_regs + 128), %rsp
	push %rax
	push %rcx
	push %rdx
	push %rbx

	push (stored_rsp)
	push %rbp
	push %rsi
	push %rdi

	push %r8
	push %r9
	push %r10
	push %r11

	push %r12
	push %r13
	push %r14
	push %r15

	mov $_bss_end, %rsp
	push $0 // for stacktraces
	jmp sysenter_stage2