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 72union 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. 82struct vmcs { 83 union vmcs_prelude prelude; 84 uint32_t vmx_abort; 85 char data[PAGE_SIZE - 8]; 86} __attribute__ ((aligned(PAGE_SIZE))); 87 88static const int benign_exceptions[] = {1,2,3,4,5,6,7,9,16,17,18,19}; 89static 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 97static const int contributory_exceptions[] = {0,10,11,12,13}; 98static 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. 108static 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. 114static 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 126static 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 133static 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 140static 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 147static 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 154static 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 161static 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 168static inline uint16_t rd_tr(void) 169{ 170 uint16_t tr; 171 __asm volatile("str %[tr]" : [tr] "=r" (tr)); 172 return tr; 173} 174 175static inline uint64_t rd_idtr(void) 176{ 177 uint64_t idtr; 178 __asm volatile("sidt %[idtr]" : [idtr] "=m" (idtr)); 179 return idtr; 180} 181 182static inline uint16_t rd_ldtr(void) 183{ 184 uint16_t ldtr; 185 __asm volatile("sldt %[ldtr]" : [ldtr] "=r" (ldtr)); 186 return ldtr; 187} 188 189static inline void wr_ldtr(uint16_t val) 190{ 191 __asm volatile("lldt %[val]" :: [val] "m" (val) : "memory"); 192} 193 194static inline uint64_t rd_gdtr(void) 195{ 196 uint64_t gdtr; 197 __asm volatile("sgdt %[gdtr]" : [gdtr] "=m" (gdtr)); 198 return gdtr; 199} 200 201static inline uint64_t gdtr_addr(uint64_t gdtr) 202{ 203 return canonical_form(gdtr >> 16); 204} 205 206static 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. 213static 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. 219static inline int seg_sel_index(uint16_t seg_sel) 220{ 221 return ((seg_sel >> 3) & 0x1FFF); 222} 223 224static 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 239static inline void vmlaunch(void) 240{ 241 __asm volatile("vmlaunch"); 242} 243 244static inline void vmresume(void) 245{ 246 __asm volatile("vmresume"); 247} 248 249static inline void enable_vmx(void) 250{ 251 wrcr4(rdcr4() | CR4_VMXE); 252} 253 254static inline int vmx_enabled(void) 255{ 256 return (rdcr4() & CR4_VMXE); 257} 258 259static inline void disable_vmx(void) 260{ 261 wrcr4(rdcr4() & ~CR4_VMXE); 262} 263 264static 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 274static 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 284static 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. 292static 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. 301static 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 308errval_t vmptrld(lpaddr_t vmcs_base); 309lpaddr_t vmptrst(void); 310errval_t vmclear(lpaddr_t vmcs_base); 311errval_t vmread(uintptr_t encoding, lvaddr_t *dest_addr); 312errval_t vmwrite(uintptr_t encoding, uintptr_t source); 313errval_t vmxon(lpaddr_t base_addr); 314errval_t vmxoff(void); 315 316errval_t initialize_vmcs(lpaddr_t vmcs_base); 317void vmx_set_exec_ctls(void); 318 319errval_t vmx_enable_virtualization (void); 320void __attribute__ ((noreturn)) vmx_vmkit_vmenter (struct dcb *dcb); 321 322#endif // VMX_VMKIT_H 323