]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4sys/include/__vm-vmx.h
update
[l4.git] / l4 / pkg / l4sys / include / __vm-vmx.h
1 /**
2  * \internal
3  * \file
4  * \brief X86 virtualization interface.
5  */
6 /*
7  * (c) 2010-2013 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8  *               Alexander Warg <warg@os.inf.tu-dresden.de>
9  *     economic rights: Technische Universität Dresden (Germany)
10  *
11  * This file is part of TUD:OS and distributed under the terms of the
12  * GNU General Public License 2.
13  * Please see the COPYING-GPL-2 file for details.
14  *
15  * As a special exception, you may use this file as part of a free software
16  * library without restriction.  Specifically, if other files instantiate
17  * templates or use macros or inline functions from this file, or you compile
18  * this file and link it with other files to produce an executable, this
19  * file does not by itself cause the resulting executable to be covered by
20  * the GNU General Public License.  This exception does not however
21  * invalidate any other reasons why the executable file might be covered by
22  * the GNU General Public License.
23  */
24 #pragma once
25
26 #include <l4/sys/vcpu.h>
27
28 /**
29  * \defgroup l4_vm_vmx_api VM API for VMX
30  * \brief Virtual machine API for VMX.
31  * \ingroup l4_vm_api
32  */
33
34
35 /**
36  * \brief Exported VMX capability regsiters.
37  * \ingroup l4_vm_vmx_api
38  */
39 enum L4_vm_vmx_caps_regs
40 {
41   L4_VM_VMX_BASIC_REG               = 0,    /**< Basic VMX capabilities */
42   L4_VM_VMX_TRUE_PINBASED_CTLS_REG  = 1,    /**< True pin-based control caps */
43   L4_VM_VMX_TRUE_PROCBASED_CTLS_REG = 2,    /**< True processor based control caps */
44   L4_VM_VMX_TRUE_EXIT_CTLS_REG      = 3,    /**< True exit control caps */
45   L4_VM_VMX_TRUE_ENTRY_CTLS_REG     = 4,    /**< True entry control caps */
46   L4_VM_VMX_MISC_REG                = 5,    /**< Misc caps */
47   L4_VM_VMX_CR0_FIXED0_REG          = 6,    /**< Fixed to 0 bits of CR0 */
48   L4_VM_VMX_CR0_FIXED1_REG          = 7,    /**< Fixed to 1 bits of CR0 */
49   L4_VM_VMX_CR4_FIXED0_REG          = 8,    /**< Fixed to 0 bits of CR4 */
50   L4_VM_VMX_CR4_FIXED1_REG          = 9,    /**< Fixed to 1 bits of CR4 */
51   L4_VM_VMX_VMCS_ENUM_REG           = 0xa,  /**< VMCS enumeration info */
52   L4_VM_VMX_PROCBASED_CTLS2_REG     = 0xb,  /**< Processor based control 2 caps */
53   L4_VM_VMX_EPT_VPID_CAP_REG        = 0xc,  /**< EPT and VPID caps */
54   L4_VM_VMX_NUM_CAPS_REGS                   /**< Total number of VMX capability registers */
55 };
56
57
58 /**
59  * \brief Exported VMX capability regsiters (default to 1 bits).
60  * \ingroup l4_vm_vmx_api
61  */
62 enum L4_vm_vmx_dfl1_regs
63 {
64   L4_VM_VMX_PINBASED_CTLS_DFL1_REG  = 0x1, /**< Default 1 bits in pin-based controls */
65   L4_VM_VMX_PROCBASED_CTLS_DFL1_REG = 0x2, /**< Default 1 bits in processor-based controls */
66   L4_VM_VMX_EXIT_CTLS_DFL1_REG      = 0x3, /**< Default 1 bits in exit controls */
67   L4_VM_VMX_ENTRY_CTLS_DFL1_REG     = 0x4, /**< Default 1 bits in entry controls */
68   L4_VM_VMX_NUM_DFL1_REGS                  /**< Total number of default on registers */
69 };
70
71 /**
72  * \brief Get a capability register for VMX.
73  * \ingroup l4_vm_vmx_api
74  *
75  * \param vcpu_state  Pointer to the VCPU state of the VCPU.
76  * \param cap_msr     Caps register index (\see L4_vm_vmx_caps_regs).
77  * \return The value of the capability register.
78  */
79 L4_INLINE
80 l4_uint64_t
81 l4_vm_vmx_get_caps(void const *vcpu_state, unsigned cap_msr) L4_NOTHROW;
82
83 /**
84  * \brief Get a default to one capability register for VMX.
85  * \ingroup l4_vm_vmx_api
86  *
87  * \param vcpu_state  Pointer to the VCPU state of the VCPU.
88  * \param cap_msr     Default 1 caps register index (\see L4_vm_vmx_dfl1_regs).
89  * \return The value of the capability register.
90  */
91 L4_INLINE
92 l4_uint32_t
93 l4_vm_vmx_get_caps_default1(void const *vcpu_state, unsigned cap_msr) L4_NOTHROW;
94
95
96 /**
97  * \brief Additional VMCS fields.
98  * \ingroup l4_vm_vmx_api
99  */
100 enum
101 {
102   /**
103    * \brief (virtual) VMCS offset for CR2.
104    *
105    * The CR2 register is actually not in the hardware VMCS, however our VMMs
106    * run in user mode and need to have access to this register so we put it
107    * into our version of the VMCS.
108    *
109    * \note You usually need to check this value against the value you get from
110    *       l4_vm_vmx_get_cr2_index() to make sure you are running on a
111    *       compatible kernel.
112    */
113   L4_VM_VMX_VMCS_CR2              = 0x683e,
114 };
115
116 /**
117  * \brief Return length in bytes of a VMCS field.
118  * \ingroup l4_vm_vmx_api
119  *
120  * \param field  Field number.
121  * \return Width of field in bytes.
122  */
123 L4_INLINE
124 unsigned
125 l4_vm_vmx_field_len(unsigned field) L4_NOTHROW;
126
127 /**
128  * \brief Return length in power of two (bytes) of a VMCS field.
129  * \ingroup l4_vm_vmx_api
130  *
131  * \param field  Field number.
132  * \return Width of field in power of two (bytes).
133  */
134 L4_INLINE
135 unsigned
136 l4_vm_vmx_field_order(unsigned field) L4_NOTHROW;
137
138 /**
139  * \brief Get pointer into VMCS.
140  * \internal
141  * \ingroup l4_vm_vmx_api
142  *
143  * \param vmcs   Pointer to VMCS buffer.
144  * \param field  Field number.
145  *
146  * \param Pointer to field in the VMCS.
147  */
148 L4_INLINE
149 void *
150 l4_vm_vmx_field_ptr(void *vmcs, unsigned field) L4_NOTHROW;
151
152 /**
153  * \brief Saves cached state from the kernel VMCS to the user VMCS.
154  * \ingroup l4_vm_vmx_api
155  * \param vmcs Pointer to the kernel VMCS.
156  * \param user_vmcs Pointer to the user VMCS.
157  *
158  * This function is comparable to VMX vmclear.
159  */
160 L4_INLINE
161 void
162 l4_vm_vmx_clear(void *vmcs, void *user_vmcs) L4_NOTHROW;
163
164 /**
165  * \brief Loades the user_vmcs as the current VMCS.
166  * \ingroup l4_vm_vmx_api
167  * \param vmcs Pointer to the kernel VMCS.
168  * \param user_vmcs Pointer to the user VMCS.
169  *
170  * This function is comparable to VMX vmptrld.
171  */
172 L4_INLINE
173 void
174 l4_vm_vmx_ptr_load(void *vmcs, void *user_vmcs) L4_NOTHROW;
175
176
177 /**
178  * \brief Get the VMCS field index of the virtual CR2 register.
179  * \ingroup l4_vm_vmx_api
180  *
181  * \param vmcs  Pointer to the software VMCS.
182  * \return The field index used for the virtual CR2 register as used by the
183  *         current Fiasco.OC interface.
184  *
185  * The CR2 register is actually not in the hardware VMCS, however our VMMs run
186  * in user mode and need to have access to this register so we put it into our
187  * software version of the VMCS.
188  *
189  * \see #L4_VM_VMX_VMCS_CR2
190  */
191 L4_INLINE
192 l4_uint32_t
193 l4_vm_vmx_get_cr2_index(void const *vmcs) L4_NOTHROW;
194
195 /**
196  * \brief Read a natural width VMCS field.
197  * \ingroup l4_vm_vmx_api
198  *
199  * \param vmcs Pointer to the software VMCS.
200  * \param field The VMCS field index as used on VMX hardware.
201  * \return The value of the VMCS field with the given index.
202  */
203 L4_INLINE
204 l4_umword_t
205 l4_vm_vmx_read_nat(void *vmcs, unsigned field) L4_NOTHROW;
206
207 /**
208  * \brief Read a 16bit VMCS field.
209  * \ingroup l4_vm_vmx_api
210  *
211  * \param vmcs Pointer to the software VMCS.
212  * \param field The VMCS field index as used on VMX hardware.
213  * \return The value of the VMCS field with the given index.
214  */
215 L4_INLINE
216 l4_uint16_t
217 l4_vm_vmx_read_16(void *vmcs, unsigned field) L4_NOTHROW;
218
219 /**
220  * \brief Read a 32bit VMCS field.
221  * \ingroup l4_vm_vmx_api
222  *
223  * \param vmcs Pointer to the software VMCS.
224  * \param field The VMCS field index as used on VMX hardware.
225  * \return The value of the VMCS field with the given index.
226  */
227 L4_INLINE
228 l4_uint32_t
229 l4_vm_vmx_read_32(void *vmcs, unsigned field) L4_NOTHROW;
230
231 /**
232  * \brief Read a 64bit VMCS field.
233  * \ingroup l4_vm_vmx_api
234  *
235  * \param vmcs Pointer to the software VMCS.
236  * \param field The VMCS field index as used on VMX hardware.
237  * \return The value of the VMCS field with the given index.
238  */
239 L4_INLINE
240 l4_uint64_t
241 l4_vm_vmx_read_64(void *vmcs, unsigned field) L4_NOTHROW;
242
243 /**
244  * \brief Read any VMCS field.
245  * \ingroup l4_vm_vmx_api
246  *
247  * \param vmcs Pointer to the software VMCS.
248  * \param field The VMCS field index as used on VMX hardware.
249  * \return The value of the VMCS field with the given index.
250  */
251 L4_INLINE
252 l4_uint64_t
253 L4_vm_vmx_read(void *vmcs, unsigned field) L4_NOTHROW;
254
255 /**
256  * \brief Write to a natural width VMCS field.
257  * \ingroup l4_vm_vmx_api
258  *
259  * \param vmcs   Pointer to the software VMCS.
260  * \param field  The VMCS field index as used on VMX hardware.
261  * \param val    The value that shall be written to the given field.
262  */
263 L4_INLINE
264 void
265 l4_vm_vmx_write_nat(void *vmcs, unsigned field, l4_umword_t val) L4_NOTHROW;
266
267 /**
268  * \brief Write to a 16bit VMCS field.
269  * \ingroup l4_vm_vmx_api
270  *
271  * \param vmcs   Pointer to the software VMCS.
272  * \param field  The VMCS field index as used on VMX hardware.
273  * \param val    The value that shall be written to the given field.
274  */
275 L4_INLINE
276 void
277 l4_vm_vmx_write_16(void *vmcs, unsigned field, l4_uint16_t val) L4_NOTHROW;
278
279 /**
280  * \brief Write to a 32bit VMCS field.
281  * \ingroup l4_vm_vmx_api
282  *
283  * \param vmcs   Pointer to the software VMCS.
284  * \param field  The VMCS field index as used on VMX hardware.
285  * \param val    The value that shall be written to the given field.
286  */
287 L4_INLINE
288 void
289 l4_vm_vmx_write_32(void *vmcs, unsigned field, l4_uint32_t val) L4_NOTHROW;
290
291 /**
292  * \brief Write to a 64bit VMCS field.
293  * \ingroup l4_vm_vmx_api
294  *
295  * \param vmcs   Pointer to the software VMCS.
296  * \param field  The VMCS field index as used on VMX hardware.
297  * \param val    The value that shall be written to the given field.
298  */
299 L4_INLINE
300 void
301 l4_vm_vmx_write_64(void *vmcs, unsigned field, l4_uint64_t val) L4_NOTHROW;
302
303 /**
304  * \brief Write to an arbitrary VMCS field.
305  * \ingroup l4_vm_vmx_api
306  *
307  * \param vmcs   Pointer to the software VMCS.
308  * \param field  The VMCS field index as used on VMX hardware.
309  * \param val    The value that shall be written to the given field.
310  */
311 L4_INLINE
312 void
313 l4_vm_vmx_write(void *vmcs, unsigned field, l4_uint64_t val) L4_NOTHROW;
314
315
316 /* Implementations */
317
318 L4_INLINE
319 unsigned
320 l4_vm_vmx_field_order(unsigned field) L4_NOTHROW
321 {
322   switch (field >> 13)
323     {
324     case 0: return 1;
325     case 1: return 3;
326     case 2: return 2;
327     case 3: if (sizeof(l4_umword_t) == 8) return 3; else return 2;
328     default: return 0;
329     }
330 }
331
332
333 L4_INLINE
334 unsigned
335 l4_vm_vmx_field_len(unsigned field) L4_NOTHROW
336 {
337   return 1 << l4_vm_vmx_field_order(field);
338 }
339
340
341 /* Internal VCPU state layout:
342  *
343  * VCPU State:
344  * 0 - xxx: normal IA32 VCPU state (l4_vcpu_state_t)
345  *    200h: VMX capabilities (see l4_vm_vmx_get_caps)
346  *    400h: Fiasco.OC VMCS
347  *
348  * Fiasco.OC VMCS:
349  *  0h -   7h: Reserved
350  *  8h -   Fh: ignored by kernel, stores current VMCS for l4_vm_vmx_clear...
351  * 10h -  13h: L4_VM_VMX_VMCS_CR2 value used by the kernel
352  * 14h -  1Fh: Reserved
353  * 20h -  3Fh: VMCS field offset table
354  * 40h - BFFh: Data (VMCS field data)
355  *
356  * VMCS field offset table:
357  *  0h -  2h: 3 offsets for 16bit fields:
358  *            0: Control fields, 1: read-only fields, 2: guest state
359  *            all offsets in 64byte granules relative to the start of the VMCS
360  *        3h: Reserved
361  *  4h -  7h: Index shift values for 16bit, 64bit, 32bit, and natural width fields
362  *  8h -  Ah: 3 offsets for 64bit fields
363  *  Bh -  Fh: Reserved
364  * 10h - 12h: 3 offsets for 32bit fields
365  * 13h - 17h: Reserved
366  * 18h - 1Ah: 3 offsets for natural width fields
367  *       1Bh: Reserved
368  *       1Ch: Offset of first VMCS field
369  *       1Dh: Full size of VMCS fields
370  * 1Eh - 1Fh: Reserved
371  *
372  */
373
374 L4_INLINE
375 unsigned
376 l4_vm_vmx_field_offset(void const *vmcs, unsigned field) L4_NOTHROW
377 {
378   // the offset table is at 0x20 offset
379   enum { Si = 4 };
380   l4_uint8_t const *offsets = (l4_uint8_t const *)vmcs;
381   offsets += 0x20;
382   return (unsigned)offsets[field >> 10] * 64 + ((field & 0x3ff) << offsets[Si + (field >> 13)]);
383 }
384
385 L4_INLINE
386 void *
387 l4_vm_vmx_field_ptr(void *vmcs, unsigned field) L4_NOTHROW
388 {
389   return (void *)((char *)vmcs + l4_vm_vmx_field_offset(vmcs, field));
390 }
391
392 /**
393  * \brief Copy full vmcs state
394  * \internal
395  */
396 L4_INLINE
397 void
398 l4_vm_vmx_copy_state(void const *vmcs, void *_dst, void const *_src) L4_NOTHROW
399 {
400   l4_uint8_t const *offsets = (l4_uint8_t const *)vmcs + 0x20;
401
402   unsigned offs = offsets[28] * 64;
403   unsigned size = offsets[29] * 64;
404   char *const dst = (char*)_dst + offs;
405   char const *const src = (char const *)_src + offs;
406   __builtin_memcpy(dst, src, size);
407 }
408
409 L4_INLINE
410 void
411 l4_vm_vmx_clear(void *vmcs, void *user_vmcs) L4_NOTHROW
412 {
413   void **current_vmcs = (void **)((char *)vmcs + 8);
414   if (*current_vmcs != user_vmcs)
415     return;
416
417   l4_vm_vmx_copy_state(vmcs, user_vmcs, vmcs);
418   *current_vmcs = 0;
419 }
420
421 L4_INLINE
422 void
423 l4_vm_vmx_ptr_load(void *vmcs, void *user_vmcs) L4_NOTHROW
424 {
425   void **current_vmcs = (void **)((char *)vmcs + 8);
426   if (*current_vmcs == user_vmcs)
427     return;
428
429   if (*current_vmcs && *current_vmcs != user_vmcs)
430     l4_vm_vmx_clear(vmcs, *current_vmcs);
431
432   *current_vmcs = user_vmcs;
433   l4_vm_vmx_copy_state(vmcs, vmcs, user_vmcs);
434 }
435
436
437 L4_INLINE
438 l4_umword_t
439 l4_vm_vmx_read_nat(void *vmcs, unsigned field) L4_NOTHROW
440 { return *(l4_umword_t*)(l4_vm_vmx_field_ptr(vmcs, field)); }
441
442 L4_INLINE
443 l4_uint16_t
444 l4_vm_vmx_read_16(void *vmcs, unsigned field) L4_NOTHROW
445 { return *(l4_uint16_t*)(l4_vm_vmx_field_ptr(vmcs, field)); }
446
447 L4_INLINE
448 l4_uint32_t
449 l4_vm_vmx_read_32(void *vmcs, unsigned field) L4_NOTHROW
450 { return *(l4_uint32_t*)(l4_vm_vmx_field_ptr(vmcs, field)); }
451
452 L4_INLINE
453 l4_uint64_t
454 l4_vm_vmx_read_64(void *vmcs, unsigned field) L4_NOTHROW
455 { return *(l4_uint64_t*)(l4_vm_vmx_field_ptr(vmcs, field)); }
456
457 L4_INLINE
458 l4_uint64_t
459 L4_vm_vmx_read(void *vmcs, unsigned field) L4_NOTHROW
460 {
461   switch(field >> 13)
462     {
463     case 0: return l4_vm_vmx_read_16(vmcs, field);
464     case 1: return l4_vm_vmx_read_64(vmcs, field);
465     case 2: return l4_vm_vmx_read_32(vmcs, field);
466     case 3: return l4_vm_vmx_read_nat(vmcs, field);
467     }
468 }
469
470 L4_INLINE
471 void
472 l4_vm_vmx_write_nat(void *vmcs, unsigned field, l4_umword_t val) L4_NOTHROW
473 { *(l4_umword_t*)(l4_vm_vmx_field_ptr(vmcs, field)) = val; }
474
475 L4_INLINE
476 void
477 l4_vm_vmx_write_16(void *vmcs, unsigned field, l4_uint16_t val) L4_NOTHROW
478 { *(l4_uint16_t*)(l4_vm_vmx_field_ptr(vmcs, field)) = val; }
479
480 L4_INLINE
481 void
482 l4_vm_vmx_write_32(void *vmcs, unsigned field, l4_uint32_t val) L4_NOTHROW
483 { *(l4_uint32_t*)(l4_vm_vmx_field_ptr(vmcs, field)) = val; }
484
485 L4_INLINE
486 void
487 l4_vm_vmx_write_64(void *vmcs, unsigned field, l4_uint64_t val) L4_NOTHROW
488 { *(l4_uint64_t*)(l4_vm_vmx_field_ptr(vmcs, field)) = val; }
489
490
491 L4_INLINE
492 void
493 l4_vm_vmx_write(void *vmcs, unsigned field, l4_uint64_t val) L4_NOTHROW
494 {
495   switch(field >> 13)
496     {
497     case 0: l4_vm_vmx_write_16(vmcs, field, val); break;
498     case 1: l4_vm_vmx_write_64(vmcs, field, val); break;
499     case 2: l4_vm_vmx_write_32(vmcs, field, val); break;
500     case 3: l4_vm_vmx_write_nat(vmcs, field, val); break;
501     }
502 }
503
504 L4_INLINE
505 l4_uint64_t
506 l4_vm_vmx_get_caps(void const *vcpu_state, unsigned cap_msr) L4_NOTHROW
507 {
508   l4_uint64_t const *caps = (l4_uint64_t const *)((char const *)(vcpu_state) + L4_VCPU_OFFSET_EXT_INFOS);
509   return caps[cap_msr & 0xf];
510 }
511
512 L4_INLINE
513 l4_uint32_t
514 l4_vm_vmx_get_caps_default1(void const *vcpu_state, unsigned cap_msr) L4_NOTHROW
515 {
516   l4_uint32_t const *caps = (l4_uint32_t const *)((char const *)(vcpu_state) + L4_VCPU_OFFSET_EXT_INFOS);
517   return caps[L4_VM_VMX_NUM_CAPS_REGS * 2 + ((cap_msr & 0xf) - L4_VM_VMX_PINBASED_CTLS_DFL1_REG)];
518 }
519
520 L4_INLINE
521 l4_uint32_t
522 l4_vm_vmx_get_cr2_index(void const *vmcs) L4_NOTHROW
523 {
524   l4_uint32_t const *infos = (l4_uint32_t const *)vmcs;
525   return infos[3];
526 }