Virtualization changes to handle X2APIC mode.
[akaros.git] / kern / arch / x86 / vmm / intel / vmx.h
1 #pragma once
2
3 /*
4  * vmx.h: VMX Architecture related definitions
5  * Copyright (c) 2004, Intel Corporation.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU General Public License,
9  * version 2, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18  * Place - Suite 330, Boston, MA 02111-1307 USA.
19  *
20  * A few random additions are:
21  * Copyright (C) 2006 Qumranet
22  *    Avi Kivity <avi@qumranet.com>
23  *    Yaniv Kamay <yaniv@qumranet.com>
24  *
25  */
26
27 #include <ros/arch/vmx.h>
28
29 #define INTEL_MSR_WRITE_OFFSET                  2048
30
31 #define INTEL_X2APIC_MSR_START                  0x100
32 #define INTEL_X2APIC_MSR_LENGTH                 (0x40/8)
33
34 int vmx_init(void);
35 void vmx_exit(void);
36 int intel_vmm_init(void);
37 int intel_vmm_pcpu_init(void);
38 int ept_fault_pages(void *dir, uint32_t start, uint32_t end);
39 int ept_check_page(void *dir, unsigned long addr);
40 int vmx_do_ept_fault(void *dir, unsigned long gpa, unsigned long gva, int fault_flags);
41
42 static inline void native_store_idt(pseudodesc_t *dtr);
43 static inline unsigned long get_desc_base(const struct desc_struct *desc);
44 static inline void native_store_gdt(pseudodesc_t *dtr);
45 static inline bool cpu_has_secondary_exec_ctrls(void);
46 static inline bool cpu_has_vmx_vpid(void);
47 static inline bool cpu_has_vmx_invpcid(void);
48 static inline bool cpu_has_vmx_invvpid_single(void);
49 static inline bool cpu_has_vmx_invvpid_global(void);
50 static inline bool cpu_has_vmx_ept(void);
51 static inline bool cpu_has_vmx_invept(void);
52 static inline bool cpu_has_vmx_invept_individual_addr(void);
53 static inline bool cpu_has_vmx_invept_context(void);
54 static inline bool cpu_has_vmx_invept_global(void);
55 static inline bool cpu_has_vmx_ept_ad_bits(void);
56 static inline bool cpu_has_vmx_ept_execute_only(void);
57 static inline bool cpu_has_vmx_eptp_uncacheable(void);
58 static inline bool cpu_has_vmx_eptp_writeback(void);
59 static inline bool cpu_has_vmx_ept_2m_page(void);
60 static inline bool cpu_has_vmx_ept_1g_page(void);
61 static inline bool cpu_has_vmx_ept_4levels(void);
62 static inline void __invept(int ext, uint64_t eptp, gpa_t gpa);
63 static inline void ept_sync_global(void);
64 static inline void ept_sync_context(uint64_t eptp);
65 static inline void ept_sync_individual_addr(uint64_t eptp, gpa_t gpa);
66 static inline void __vmxon(uint64_t addr);
67 static inline void __vmxoff(void);
68 static inline void __invvpid(int ext, uint16_t vpid, gva_t gva);
69 static inline void vpid_sync_gpc_single(uint16_t vpid);
70 static inline void vpid_sync_gpc_global(void);
71 static inline void vpid_sync_context(uint16_t vpid);
72 static inline uint64_t gpc_get_eptp(struct guest_pcore *gpc);
73
74 /* no way to get around some of this stuff. */
75 /* we will do the bare minimum required. */
76 static inline void native_store_idt(pseudodesc_t *dtr)
77 {
78         asm volatile("sidt %0":"=m" (*dtr));
79 }
80
81 static inline unsigned long get_desc_base(const struct desc_struct *desc)
82 {
83         return (unsigned)(desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24));
84 }
85
86 #define store_gdt(dtr)                          native_store_gdt(dtr)
87 static inline void native_store_gdt(pseudodesc_t *dtr)
88 {
89         asm volatile("sgdt %0":"=m" (*dtr));
90 }
91
92 static inline bool cpu_has_secondary_exec_ctrls(void)
93 {
94         return vmcs_config.cpu_based_exec_ctrl &
95                 CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
96 }
97
98 static inline bool cpu_has_vmx_vpid(void)
99 {
100         return vmcs_config.cpu_based_2nd_exec_ctrl &
101                 SECONDARY_EXEC_ENABLE_VPID;
102 }
103
104 static inline bool cpu_has_vmx_invpcid(void)
105 {
106         return vmcs_config.cpu_based_2nd_exec_ctrl &
107                 SECONDARY_EXEC_ENABLE_INVPCID;
108 }
109
110 static inline bool cpu_has_vmx_invvpid_single(void)
111 {
112         return vmx_capability.vpid & VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT;
113 }
114
115 static inline bool cpu_has_vmx_invvpid_global(void)
116 {
117         return vmx_capability.vpid & VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
118 }
119
120 static inline bool cpu_has_vmx_ept(void)
121 {
122         return vmcs_config.cpu_based_2nd_exec_ctrl &
123                 SECONDARY_EXEC_ENABLE_EPT;
124 }
125
126 static inline bool cpu_has_vmx_invept(void)
127 {
128         return vmx_capability.ept & VMX_EPT_INVEPT_BIT;
129 }
130
131 /* the SDM (2015-01) doesn't mention this ability (still?) */
132 static inline bool cpu_has_vmx_invept_individual_addr(void)
133 {
134         return vmx_capability.ept & VMX_EPT_EXTENT_INDIVIDUAL_BIT;
135 }
136
137 static inline bool cpu_has_vmx_invept_context(void)
138 {
139         return vmx_capability.ept & VMX_EPT_EXTENT_CONTEXT_BIT;
140 }
141
142 static inline bool cpu_has_vmx_invept_global(void)
143 {
144         return vmx_capability.ept & VMX_EPT_EXTENT_GLOBAL_BIT;
145 }
146
147 static inline bool cpu_has_vmx_ept_ad_bits(void)
148 {
149         return vmx_capability.ept & VMX_EPT_AD_BIT;
150 }
151
152 static inline bool cpu_has_vmx_ept_execute_only(void)
153 {
154         return vmx_capability.ept & VMX_EPT_EXECUTE_ONLY_BIT;
155 }
156
157 static inline bool cpu_has_vmx_eptp_uncacheable(void)
158 {
159         return vmx_capability.ept & VMX_EPTP_UC_BIT;
160 }
161
162 static inline bool cpu_has_vmx_eptp_writeback(void)
163 {
164         return vmx_capability.ept & VMX_EPTP_WB_BIT;
165 }
166
167 static inline bool cpu_has_vmx_ept_2m_page(void)
168 {
169         return vmx_capability.ept & VMX_EPT_2MB_PAGE_BIT;
170 }
171
172 static inline bool cpu_has_vmx_ept_1g_page(void)
173 {
174         return vmx_capability.ept & VMX_EPT_1GB_PAGE_BIT;
175 }
176
177 static inline bool cpu_has_vmx_ept_4levels(void)
178 {
179         return vmx_capability.ept & VMX_EPT_PAGE_WALK_4_BIT;
180 }
181
182 static inline void __invept(int ext, uint64_t eptp, gpa_t gpa)
183 {
184         struct {
185                 uint64_t eptp, gpa;
186         } operand = {eptp, gpa};
187
188         asm volatile (ASM_VMX_INVEPT
189                         /* CF==1 or ZF==1 --> rc = -1 */
190                         "; ja 1f ; ud2 ; 1:\n"
191                         : : "a" (&operand), "c" (ext) : "cc", "memory");
192 }
193
194 /* We assert support for the global flush during ept_init() */
195 static inline void ept_sync_global(void)
196 {
197         __invept(VMX_EPT_EXTENT_GLOBAL, 0, 0);
198 }
199
200 static inline void ept_sync_context(uint64_t eptp)
201 {
202         if (cpu_has_vmx_invept_context())
203                 __invept(VMX_EPT_EXTENT_CONTEXT, eptp, 0);
204         else
205                 ept_sync_global();
206 }
207
208 static inline void ept_sync_individual_addr(uint64_t eptp, gpa_t gpa)
209 {
210         if (cpu_has_vmx_invept_individual_addr())
211                 __invept(VMX_EPT_EXTENT_INDIVIDUAL_ADDR,
212                                 eptp, gpa);
213         else
214                 ept_sync_context(eptp);
215 }
216
217 static inline void __vmxon(uint64_t addr)
218 {
219         asm volatile (ASM_VMX_VMXON_RAX
220                         : : "a"(&addr), "m"(addr)
221                         : "memory", "cc");
222 }
223
224 static inline void __vmxoff(void)
225 {
226         asm volatile (ASM_VMX_VMXOFF : : : "cc");
227 }
228
229 static inline void __invvpid(int ext, uint16_t vpid, gva_t gva)
230 {
231     struct {
232         uint64_t vpid : 16;
233         uint64_t rsvd : 48;
234         uint64_t gva;
235     } operand = { vpid, 0, gva };
236
237     asm volatile (ASM_VMX_INVVPID
238                   /* CF==1 or ZF==1 --> rc = -1 */
239                   "; ja 1f ; ud2 ; 1:"
240                   : : "a"(&operand), "c"(ext) : "cc", "memory");
241 }
242
243 static inline void vpid_sync_gpc_single(uint16_t vpid)
244 {
245         if (vpid == 0) {
246                 return;
247         }
248
249         if (cpu_has_vmx_invvpid_single())
250                 __invvpid(VMX_VPID_EXTENT_SINGLE_CONTEXT, vpid, 0);
251 }
252
253 static inline void vpid_sync_gpc_global(void)
254 {
255         if (cpu_has_vmx_invvpid_global())
256                 __invvpid(VMX_VPID_EXTENT_ALL_CONTEXT, 0, 0);
257 }
258
259 static inline void vpid_sync_context(uint16_t vpid)
260 {
261         if (cpu_has_vmx_invvpid_single())
262                 vpid_sync_gpc_single(vpid);
263         else
264                 vpid_sync_gpc_global();
265 }
266
267 static inline uint64_t gpc_get_eptp(struct guest_pcore *gpc)
268 {
269         return gpc->proc->env_pgdir.eptp;
270 }
271
272 static inline unsigned long vmcs_read(unsigned long field)
273 {
274         unsigned long value;
275
276         asm volatile (ASM_VMX_VMREAD_RDX_RAX : "=a"(value) : "d"(field) : "cc");
277         return value;
278 }
279
280 /* Returns true if the op succeeded.  It can fail if the field is unsupported */
281 static inline bool vmcs_write(unsigned long field, unsigned long value)
282 {
283         uint8_t error;
284
285         asm volatile (ASM_VMX_VMWRITE_RAX_RDX "; setna %0"
286                       : "=q"(error) : "a"(value), "d"(field) : "cc");
287         return error ? FALSE : TRUE;
288 }
289
290 /*
291  * VMX Execution Controls (vmxec)
292  * Some bits can be set, others can not (i.e. they are reserved).
293  *
294  * o all bits listed in here must set or clear all the bits in a word
295  *   that are not reserved (coverage).
296  * o no bits listed in one of these elements is listed in
297  *   another element (conflict)
298  * o you are allowed to specify a bit that matches a reserved value
299  *   (because it might be settable at some future time).
300  * o do your best to find symbolic names for the set_to_1 and set_to_0 values.
301  *   In the one case we could not find a name, it turned out to be an
302  *   error in kvm constants that went back to the earliest days.
303  * We're hoping you almost never have to change this. It's painful.
304  * The assumption going in is that the 5 MSRs that define the vmxec
305  * values are relatively static. This has been the case for a while.
306  */
307 struct vmxec {
308         char *name;
309         uint32_t msr;
310         uint32_t truemsr;
311         uint32_t must_be_1;
312         uint32_t must_be_0;
313         uint32_t try_set_1;
314         uint32_t try_set_0;
315 };
316
317 void vmx_load_guest_pcore(struct guest_pcore *gpc);
318 void vmx_unload_guest_pcore(struct guest_pcore *gpc);