Fixup of some headers.
[barrelfish] / kernel / include / arch / x86_64 / vmx_vmkit.h
1 /**
2  * \file
3  * \brief Contains VMKit kernel interface for version using VMX extensions.
4  */
5
6 /*
7  * Copyright (c) 2014, University of Washington.
8  * All rights reserved.
9  *
10  * This file is distributed under the terms in the attached LICENSE file.
11  * If you do not find this file, copies can be found by writing to:
12  * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich.
13  * Attn: Systems Group.
14  */
15
16 #ifndef VMX_VMKIT_H
17 #define VMX_VMKIT_H
18
19 #include <arch/x86/x86.h>
20 #include <arch/x86_64/x86.h>
21 #include <barrelfish_kpi/vmkit.h>
22 #include <barrelfish_kpi/vmx_controls.h>
23 #include <barrelfish_kpi/vmx_encodings.h>
24 #include <barrelfish_kpi/vmx_exit_reasons.h>
25
26 #include <dev/ia32_dev.h>
27
28 // Number of MSRs that are loaded on VM-exit
29 #define VMX_MSR_COUNT 5
30
31 // Size of the host MSR-load area
32 #define VMX_MSR_AREA_SIZE (VMX_MSR_COUNT * 16)
33
34 #define MSR_KERNEL_GS_BASE 0xc0000102
35 #define MSR_STAR           0xc0000081
36 #define MSR_LSTAR          0xc0000082
37 #define MSR_CSTAR          0xc0000083
38 #define MSR_SFMASK         0xc0000084
39
40 #define CPUID_PA_WIDTH (0x80000008)
41 #define VMX_PA_WIDTH_MASK (0xFF)
42 #define CPUID_VMX (0x1)
43 #define VMX_SUPPORT (1 << 5)
44
45 #define TYPE_EXT_INTR (0)
46 #define TYPE_NMI (2)
47 #define TYPE_HW_EXCP (3)
48 #define TYPE_SW_EXCP (6)
49
50 #define RFLAGS_IF (1 << 9)
51 #define RFLAGS_VM (1 << 17)
52
53 #define EFER_LME (1UL << 8)
54 #define EFER_LMA (1UL << 10)
55 #define EFER_NXE (1UL << 11)
56
57 #define CR0_PE (1 << 0)
58 #define CR0_NW (1 << 29)
59 #define CR0_CD (1 << 30)
60 #define CR0_PG (1 << 31)
61
62 #define CR4_PAE (1UL << 5)
63 #define CR4_MCE (1UL << 6)
64 #define CR4_PGE (1UL << 7)
65 #define CR4_PCE (1UL << 8)
66 #define CR4_VMXE (1UL << 13)
67 #define CR4_PCIDE (1UL << 17)
68
69 #define DWORD_MS(val) ((val >> 32) & 0xFFFFFFFF)
70 #define DWORD_LS(val) (val & 0xFFFFFFFF)
71
72 union vmcs_prelude {
73     uint32_t raw;
74     struct {
75         uint32_t revision_id :31;
76         uint32_t shadow      :1;
77     } p;
78 };
79
80 // Represents a VMCS structure which is comprised of up to 4-KB,
81 // the data portion of the structure is implemenation-specific.
82 struct vmcs {
83     union vmcs_prelude prelude;
84     uint32_t vmx_abort;
85     char data[PAGE_SIZE - 8];
86 } __attribute__ ((aligned(PAGE_SIZE)));
87
88 static const int benign_exceptions[] = {1,2,3,4,5,6,7,9,16,17,18,19};
89 static inline bool benign_exception(int vector)
90 {
91     for (int i = 0; i < sizeof(benign_exceptions); i++) {
92         if (benign_exceptions[i] == vector) return true;
93     }
94     return false;
95 }
96
97 static const int contributory_exceptions[] = {0,10,11,12,13};
98 static inline bool contributory_exception(int vector)
99 {
100     for (int i = 0; i < sizeof(contributory_exceptions); i++) {
101         if (contributory_exceptions[i] == vector) return true;
102     }
103     return false;
104 }
105
106 // Returns true if secondary processor-based VM-execution controls
107 // are used.
108 static inline bool sec_ctls_used(uint64_t pp_controls)
109 {
110     return !!(pp_controls & PP_CLTS_SEC_CTLS);
111 }
112
113 // Returns the canonical form of the address addr.
114 static inline uint64_t canonical_form(uint64_t addr)
115 {
116     if ((addr >> 47) & 0x1) {
117         return (addr | ~0xffffffffffffUL);
118     } else {
119         return (addr & 0xffffffffffffUL);
120     }
121 }
122
123 // Functions for reading segment registers are used in saving the
124 // host state (via vmwrite instructions) prior to VM-entry
125
126 static inline uint16_t rd_es(void)
127 {
128     uint16_t es;
129     __asm volatile("mov %%es, %[es]" : [es] "=r" (es));
130     return es;
131 }
132
133 static inline uint16_t rd_cs(void)
134 {
135     uint16_t cs;
136     __asm volatile("mov %%cs, %[cs]" : [cs] "=r" (cs));
137     return cs;
138 }
139
140 static inline uint16_t rd_ss(void)
141 {
142     uint16_t ss;
143     __asm volatile("mov %%ss, %[ss]" : [ss] "=r" (ss));
144     return ss;
145 }
146
147 static inline uint16_t rd_ds(void)
148 {
149     uint16_t ds;
150     __asm volatile("mov %%ds, %[ds]" : [ds] "=r" (ds));
151     return ds;
152 }
153
154 static inline uint16_t rd_fs(void)
155 {
156     uint16_t fs;
157     __asm volatile("mov %%fs, %[fs]" : [fs] "=r" (fs));
158     return fs;
159 }
160
161 static inline uint16_t rd_gs(void)
162 {
163     uint16_t gs;
164     __asm volatile("mov %%gs, %[gs]" : [gs] "=r" (gs));
165     return gs;
166 }
167
168 static inline uint16_t rd_tr(void)
169 {
170     uint16_t tr;
171     __asm volatile("str %[tr]" : [tr] "=r" (tr));
172     return tr;
173 }
174
175 static inline uint64_t rd_idtr(void)
176 {
177     uint64_t idtr;
178     __asm volatile("sidt %[idtr]" : [idtr] "=m" (idtr));
179     return idtr;
180 }
181
182 static inline uint16_t rd_ldtr(void)
183 {
184     uint16_t ldtr;
185     __asm volatile("sldt %[ldtr]" : [ldtr] "=r" (ldtr));
186     return ldtr;
187 }
188
189 static inline void wr_ldtr(uint16_t val)
190 {
191   __asm volatile("lldt %[val]" :: [val] "m" (val) : "memory");
192 }
193
194 static inline uint64_t rd_gdtr(void)
195 {
196     uint64_t gdtr;
197     __asm volatile("sgdt %[gdtr]" : [gdtr] "=m" (gdtr));
198     return gdtr;
199 }
200
201 static inline uint64_t gdtr_addr(uint64_t gdtr)
202 {
203     return canonical_form(gdtr >> 16);
204 }
205
206 static inline uint64_t idtr_addr(uint64_t idtr)
207 {
208     return canonical_form(idtr >> 16);
209 }
210
211 // Return true if the segment selector is in the the LDT (the TI flag
212 // is set), else false, meaning that it's contained in the GDT.
213 static inline int seg_in_ldt(uint16_t seg_sel)
214 {
215     return ((seg_sel >> 2) & 0x1);
216 }
217
218 // The index of corresponding segment descriptor in the LDT or GDT.
219 static inline int seg_sel_index(uint16_t seg_sel)
220 {
221     return ((seg_sel >> 3) & 0x1FFF);
222 }
223
224 static inline uint64_t tr_addr(uint16_t tr_sel, uint64_t gdtr_base)
225 {
226     int tss_index_low  = seg_sel_index(tr_sel);
227     int tss_index_high = tss_index_low + 1;
228
229     uint64_t *gdt_new = (uint64_t *)gdtr_base;
230     uint64_t tss_low = gdt_new[tss_index_low];
231     uint64_t tss_high = gdt_new[tss_index_high];
232     
233     uint64_t tss_base = (((tss_low >> 16) & 0xFFFFFF)   |
234                          ((tss_low >> 32) & 0xFF000000) |
235                          (tss_high << 32));
236     return tss_base;
237 }
238
239 static inline void vmlaunch(void)
240 {
241     __asm volatile("vmlaunch");
242 }
243
244 static inline void vmresume(void)
245 {
246     __asm volatile("vmresume");
247 }
248
249 static inline void enable_vmx(void)
250 {
251     wrcr4(rdcr4() | CR4_VMXE);
252 }
253
254 static inline int vmx_enabled(void)
255 {
256     return (rdcr4() & CR4_VMXE);
257 }
258
259 static inline void disable_vmx(void)
260 {
261     wrcr4(rdcr4() & ~CR4_VMXE);
262 }
263
264 static inline uint64_t vmx_fixed_cr0(void)
265 {
266     uint64_t cr0_fixed0 = ia32_vmx_cr0_fixed0_rd(NULL);
267     uint64_t cr0_fixed1 = ia32_vmx_cr0_fixed1_rd(NULL);
268
269     uint64_t cr0_1s_mask = (cr0_fixed0 & cr0_fixed1);
270     uint64_t cr0_0s_mask = (~cr0_fixed0 & ~cr0_fixed1);
271     return ((rdcr0() | cr0_1s_mask) & ~cr0_0s_mask);
272 }
273
274 static inline uint64_t vmx_fixed_cr4(void)
275 {
276     uint64_t cr4_fixed0 = ia32_vmx_cr4_fixed0_rd(NULL);
277     uint64_t cr4_fixed1 = ia32_vmx_cr4_fixed1_rd(NULL);
278
279     uint64_t cr4_1s_mask = (cr4_fixed0 & cr4_fixed1);
280     uint64_t cr4_0s_mask = (~cr4_fixed0 & ~cr4_fixed1);
281     return ((rdcr4() | cr4_1s_mask) & ~cr4_0s_mask);
282 }
283
284 static inline bool is_canonical(uint64_t addr)
285 {
286     uint64_t canonical_addr = canonical_form(addr);
287     return (canonical_addr == addr);
288 }
289
290 // Returns the physical-address width supported by the logical
291 // processor.
292 static inline uint64_t physical_address_width(void)
293 {
294     uint32_t cpuid_eax;
295     cpuid(CPUID_PA_WIDTH, &cpuid_eax, NULL, NULL, NULL);
296     return (cpuid_eax & VMX_PA_WIDTH_MASK);
297 }
298
299 // Returns a mask for the bits 0:N-1, where N is the physical-address
300 // width supported by the logical processor.
301 static inline uint64_t pa_width_mask(void)
302 {
303     uint64_t pa_width = physical_address_width();
304     uint64_t physical_addr_width_mask = (1UL << pa_width) - 1;
305     return physical_addr_width_mask;
306 }
307
308 errval_t vmptrld(lpaddr_t vmcs_base);
309 lpaddr_t vmptrst(void);
310 errval_t vmclear(lpaddr_t vmcs_base);
311 errval_t vmread(uintptr_t encoding, lvaddr_t *dest_addr);
312 errval_t vmwrite(uintptr_t encoding, uintptr_t source);
313 errval_t vmxon(lpaddr_t base_addr);
314 errval_t vmxoff(void);
315
316 errval_t initialize_vmcs(lpaddr_t vmcs_base);
317 void vmx_set_exec_ctls(void);
318
319 errval_t vmx_enable_virtualization (void);
320 void __attribute__ ((noreturn)) vmx_vmkit_vmenter (struct dcb *dcb);
321
322 #endif // VMX_VMKIT_H