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