VMM: Manually save/restore certain registers [1/2]
[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 void x86_advance_ip(struct hw_trapframe *hw_tf, size_t bytes)
24 {
25         hw_tf->tf_rip += bytes;
26 }
27
28 static inline void x86_fake_rdtscp(struct hw_trapframe *hw_tf)
29 {
30         uint64_t tsc_time = read_tsc();
31         hw_tf->tf_rip += 3;
32         hw_tf->tf_rax = tsc_time & 0xffffffff;
33         hw_tf->tf_rdx = tsc_time >> 32;
34         hw_tf->tf_rcx = core_id();
35 }
36
37 #define AKAROS_MSR_STAR (((((uint64_t)GD_UD - 8) | 0x3) << 48) |             \
38                              ((uint64_t)GD_KT << 32))
39 #define AKAROS_MSR_LSTAR ((uintptr_t)&sysenter_handler)
40 /* Masking all flags.  when we syscall, we'll get rflags = 0 */
41 #define AKAROS_MSR_SFMASK 0xffffffff
42
43 static inline void x86_sysenter_init(void)
44 {
45         /* check amd 2:6.1.1 for details.  they have some expectations about the GDT
46          * layout. */
47         write_msr(MSR_STAR, AKAROS_MSR_STAR);
48         write_msr(MSR_LSTAR, AKAROS_MSR_LSTAR);
49         write_msr(MSR_SFMASK, AKAROS_MSR_SFMASK);
50         write_msr(IA32_EFER_MSR, read_msr(IA32_EFER_MSR) | IA32_EFER_SYSCALL);
51 }
52
53 /* these are used for both sysenter and traps on 32 bit */
54 static inline void x86_set_sysenter_stacktop(uintptr_t stacktop)
55 {
56         asm volatile ("movq %0, %%gs:0" : : "r"(stacktop));
57 }
58
59 static inline long x86_get_sysenter_arg0(struct hw_trapframe *hw_tf)
60 {
61         return hw_tf->tf_rdi;
62 }
63
64 static inline long x86_get_sysenter_arg1(struct hw_trapframe *hw_tf)
65 {
66         return hw_tf->tf_rsi;
67 }
68
69 static inline long x86_get_systrap_arg0(struct hw_trapframe *hw_tf)
70 {
71         return hw_tf->tf_rdi;
72 }
73
74 static inline long x86_get_systrap_arg1(struct hw_trapframe *hw_tf)
75 {
76         return hw_tf->tf_rsi;
77 }
78
79 static inline uintptr_t x86_get_stacktop_tss(struct taskstate *tss)
80 {
81         return tss->ts_rsp0;
82 }
83
84 static inline void x86_set_stacktop_tss(struct taskstate *tss, uintptr_t top)
85 {
86         tss->ts_rsp0 = top;
87 }
88
89 /* Keep tf_padding0 in sync with trapentry64.S */
90 static inline bool x86_hwtf_is_partial(struct hw_trapframe *tf)
91 {
92         return tf->tf_padding0 == 1;
93 }
94
95 static inline bool x86_swtf_is_partial(struct sw_trapframe *tf)
96 {
97         return tf->tf_padding0 == 1;
98 }
99
100 static inline bool x86_vmtf_is_partial(struct vm_trapframe *tf)
101 {
102         return tf->tf_flags & VMCTX_FL_PARTIAL ? TRUE : FALSE;
103 }
104
105 static inline void x86_hwtf_clear_partial(struct hw_trapframe *tf)
106 {
107         tf->tf_padding0 = 0;
108 }
109
110 static inline void x86_swtf_clear_partial(struct sw_trapframe *tf)
111 {
112         tf->tf_padding0 = 0;
113 }
114
115 static inline void x86_vmtf_clear_partial(struct vm_trapframe *tf)
116 {
117         tf->tf_flags &= ~VMCTX_FL_PARTIAL;
118 }
119
120 static inline bool arch_ctx_is_partial(struct user_context *ctx)
121 {
122         switch (ctx->type) {
123         case ROS_HW_CTX:
124                 return x86_hwtf_is_partial(&ctx->tf.hw_tf);
125         case ROS_SW_CTX:
126                 return x86_swtf_is_partial(&ctx->tf.sw_tf);
127         case ROS_VM_CTX:
128                 return x86_vmtf_is_partial(&ctx->tf.vm_tf);
129         }
130         return FALSE;
131 }