1c9b8ae755ab0085f550ff6222515b388b2d372f
[akaros.git] / kern / arch / x86 / trap64.h
1 /* Copyright (c) 2009-13 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * x86 trap.h bit-specific functions.  This is included by trap.h, do not
6  * include it directly.  Any function beginning with x86_ is internal to x86,
7  * and not to be called by the main kernel.  Other functions are part of the
8  * kernel-arch interface. */
9
10 #pragma once
11
12 #ifndef ROS_KERN_ARCH_TRAP_H
13 #error "Do not include arch/trap64.h directly."
14 #endif
15
16 #include <arch/fsgsbase.h>
17
18 static inline bool in_kernel(struct hw_trapframe *hw_tf)
19 {
20         return (hw_tf->tf_cs & ~3) == GD_KT;
21 }
22
23 static inline uintptr_t get_hwtf_pc(struct hw_trapframe *hw_tf)
24 {
25         return hw_tf->tf_rip;
26 }
27
28 static inline uintptr_t get_hwtf_fp(struct hw_trapframe *hw_tf)
29 {
30         return hw_tf->tf_rbp;
31 }
32
33 static inline uintptr_t get_hwtf_sp(struct hw_trapframe *hw_tf)
34 {
35         return hw_tf->tf_rsp;
36 }
37
38 static inline uintptr_t get_swtf_pc(struct sw_trapframe *sw_tf)
39 {
40         return sw_tf->tf_rip;
41 }
42
43 static inline uintptr_t get_swtf_fp(struct sw_trapframe *sw_tf)
44 {
45         return sw_tf->tf_rbp;
46 }
47
48 static inline uintptr_t get_swtf_sp(struct sw_trapframe *sw_tf)
49 {
50         return sw_tf->tf_rsp;
51 }
52
53 static inline uintptr_t get_vmtf_pc(struct vm_trapframe *vm_tf)
54 {
55         return vm_tf->tf_rip;
56 }
57
58 static inline uintptr_t get_vmtf_fp(struct vm_trapframe *vm_tf)
59 {
60         return vm_tf->tf_rbp;
61 }
62
63 static inline uintptr_t get_vmtf_sp(struct vm_trapframe *vm_tf)
64 {
65         return vm_tf->tf_rsp;
66 }
67
68 static inline void x86_advance_ip(struct hw_trapframe *hw_tf, size_t bytes)
69 {
70         hw_tf->tf_rip += bytes;
71 }
72
73 static inline void x86_fake_rdtscp(struct hw_trapframe *hw_tf)
74 {
75         uint64_t tsc_time = read_tsc();
76         hw_tf->tf_rip += 3;
77         hw_tf->tf_rax = tsc_time & 0xffffffff;
78         hw_tf->tf_rdx = tsc_time >> 32;
79         hw_tf->tf_rcx = core_id();
80 }
81
82 static inline void x86_sysenter_init(uintptr_t stacktop)
83 {
84         /* check amd 2:6.1.1 for details.  they have some expectations about the GDT
85          * layout. */
86         write_msr(MSR_STAR, ((((uint64_t)GD_UD - 8) | 0x3) << 48) |
87                             ((uint64_t)GD_KT << 32));
88         write_msr(MSR_LSTAR, (uintptr_t)&sysenter_handler);
89         /* Masking all flags.  when we syscall, we'll get rflags = 0 */
90         write_msr(MSR_SFMASK, 0xffffffff);
91         write_msr(IA32_EFER_MSR, read_msr(IA32_EFER_MSR) | IA32_EFER_SYSCALL);
92         asm volatile ("movq %0, %%gs:0" : : "r"(stacktop));
93 }
94
95 /* these are used for both sysenter and traps on 32 bit */
96 static inline void x86_set_sysenter_stacktop(uintptr_t stacktop)
97 {
98         asm volatile ("movq %0, %%gs:0" : : "r"(stacktop));
99 }
100
101 static inline long x86_get_sysenter_arg0(struct hw_trapframe *hw_tf)
102 {
103         return hw_tf->tf_rdi;
104 }
105
106 static inline long x86_get_sysenter_arg1(struct hw_trapframe *hw_tf)
107 {
108         return hw_tf->tf_rsi;
109 }
110
111 static inline long x86_get_systrap_arg0(struct hw_trapframe *hw_tf)
112 {
113         return hw_tf->tf_rdi;
114 }
115
116 static inline long x86_get_systrap_arg1(struct hw_trapframe *hw_tf)
117 {
118         return hw_tf->tf_rsi;
119 }
120
121 static inline uintptr_t x86_get_stacktop_tss(struct taskstate *tss)
122 {
123         return tss->ts_rsp0;
124 }
125
126 static inline void x86_set_stacktop_tss(struct taskstate *tss, uintptr_t top)
127 {
128         tss->ts_rsp0 = top;
129 }
130
131 /* Keep tf_padding0 in sync with trapentry64.S */
132 static inline bool x86_hwtf_is_partial(struct hw_trapframe *tf)
133 {
134         return tf->tf_padding0 == 1;
135 }
136
137 static inline bool x86_swtf_is_partial(struct sw_trapframe *tf)
138 {
139         return tf->tf_padding0 == 1;
140 }
141
142 static inline bool x86_vmtf_is_partial(struct vm_trapframe *tf)
143 {
144         return tf->tf_flags & VMCTX_FL_PARTIAL ? TRUE : FALSE;
145 }
146
147 static inline void x86_hwtf_clear_partial(struct hw_trapframe *tf)
148 {
149         tf->tf_padding0 = 0;
150 }
151
152 static inline void x86_swtf_clear_partial(struct sw_trapframe *tf)
153 {
154         tf->tf_padding0 = 0;
155 }
156
157 static inline void x86_vmtf_clear_partial(struct vm_trapframe *tf)
158 {
159         tf->tf_flags &= ~VMCTX_FL_PARTIAL;
160 }
161
162 static inline bool arch_ctx_is_partial(struct user_context *ctx)
163 {
164         switch (ctx->type) {
165         case ROS_HW_CTX:
166                 return x86_hwtf_is_partial(&ctx->tf.hw_tf);
167         case ROS_SW_CTX:
168                 return x86_swtf_is_partial(&ctx->tf.sw_tf);
169         case ROS_VM_CTX:
170                 return x86_vmtf_is_partial(&ctx->tf.vm_tf);
171         }
172         return FALSE;
173 }
174
175 /* Partial contexts for HW and SW TFs have the user's gs in MSR_KERNEL_GS_BASE.
176  * The kernel's gs is loaded into gs.  We need to put the kernel's gs into
177  * KERNEL_GS_BASE so the core is ready to run another full context, save the
178  * user's {GS,FS}_BASE into their TF so it can run on another core, and keep GS
179  * loaded with the current GS (the kernel's). */
180 static inline void x86_finalize_hwtf(struct hw_trapframe *tf)
181 {
182         tf->tf_gsbase = read_msr(MSR_KERNEL_GS_BASE);
183         write_msr(MSR_KERNEL_GS_BASE, read_gsbase());
184         tf->tf_fsbase = read_fsbase();
185         x86_hwtf_clear_partial(tf);
186 }
187
188 static inline void x86_finalize_swtf(struct sw_trapframe *tf)
189 {
190         tf->tf_gsbase = read_msr(MSR_KERNEL_GS_BASE);
191         write_msr(MSR_KERNEL_GS_BASE, read_gsbase());
192         tf->tf_fsbase = read_fsbase();
193         x86_swtf_clear_partial(tf);
194 }
195
196 void x86_finalize_vmtf(struct vm_trapframe *tf);
197
198 /* Makes sure that the user context is fully saved into ctx and not split across
199  * the struct and HW, meaning it is not a "partial context". */
200 static inline void arch_finalize_ctx(struct user_context *ctx)
201 {
202         if (!arch_ctx_is_partial(ctx))
203                 return;
204         switch (ctx->type) {
205         case ROS_HW_CTX:
206                 x86_finalize_hwtf(&ctx->tf.hw_tf);
207                 break;
208         case ROS_SW_CTX:
209                 x86_finalize_swtf(&ctx->tf.sw_tf);
210                 break;
211         case ROS_VM_CTX:
212                 x86_finalize_vmtf(&ctx->tf.vm_tf);
213                 break;
214         }
215 }