github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/memory/ept/ept_hw_layer.c (about) 1 /* 2 * Copyright (c) 2013 Intel Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 * See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 15 #include "vmm_defs.h" 16 #include "vmcs_init.h" 17 #include "ept_hw_layer.h" 18 #include "hw_utils.h" 19 #include "guest_cpu.h" 20 #include "vmcs_api.h" 21 #include "vmm_phys_mem_types.h" 22 #include "libc.h" 23 #include "scheduler.h" 24 #include "guest_cpu_internal.h" 25 #include "file_codes.h" 26 #define VMM_DEADLOOP() VMM_DEADLOOP_LOG(EPT_HW_LAYER_C) 27 #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(EPT_HW_LAYER_C, __condition) 28 #ifdef JLMDEBUG 29 #include "jlmdebug.h" 30 #endif 31 32 #define ENABLE_VPID 33 34 BOOLEAN ept_hw_is_ept_supported(void) 35 { 36 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 37 38 return (hw_constraints->may1_processor_based_exec_ctrl.Bits.SecondaryControls 39 && hw_constraints->may1_processor_based_exec_ctrl2.Bits.EnableEPT); 40 } 41 42 void ept_hw_set_pdtprs(GUEST_CPU_HANDLE gcpu, UINT64 pdptr[]) 43 { 44 VMCS_OBJECT *vmcs = gcpu_get_vmcs(gcpu); 45 46 CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu); 47 vmcs_write(vmcs, VMCS_GUEST_PDPTR0, pdptr[0]); 48 vmcs_write(vmcs, VMCS_GUEST_PDPTR1, pdptr[1]); 49 vmcs_write(vmcs, VMCS_GUEST_PDPTR2, pdptr[2]); 50 vmcs_write(vmcs, VMCS_GUEST_PDPTR3, pdptr[3]); 51 } 52 #ifdef INCLUDE_UNUSED_CODE 53 void ept_hw_get_pdtprs(GUEST_CPU_HANDLE gcpu, UINT64 pdptr[]) 54 { 55 VMCS_OBJECT *vmcs = gcpu_get_vmcs(gcpu); 56 57 CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu); 58 pdptr[0] = vmcs_read(vmcs, VMCS_GUEST_PDPTR0); 59 pdptr[1] = vmcs_read(vmcs, VMCS_GUEST_PDPTR1); 60 pdptr[2] = vmcs_read(vmcs, VMCS_GUEST_PDPTR2); 61 pdptr[3] = vmcs_read(vmcs, VMCS_GUEST_PDPTR3); 62 } 63 #endif 64 65 UINT32 ept_hw_get_guest_address_width(UINT32 actual_gaw) 66 { 67 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 68 if(actual_gaw <= 21 && hw_constraints->ept_vpid_capabilities.Bits.GAW_21_bit) { 69 return 21; 70 } 71 if(actual_gaw <= 30 && hw_constraints->ept_vpid_capabilities.Bits.GAW_30_bit) { 72 return 30; 73 } 74 if(actual_gaw <= 39 && hw_constraints->ept_vpid_capabilities.Bits.GAW_39_bit) { 75 return 39; 76 } 77 if(actual_gaw <= 48 && hw_constraints->ept_vpid_capabilities.Bits.GAW_48_bit) { 78 return 48; 79 } 80 if(actual_gaw <= 57 && hw_constraints->ept_vpid_capabilities.Bits.GAW_57_bit) { 81 return 57; 82 } 83 VMM_ASSERT(0); 84 return (UINT32) -1; 85 } 86 87 UINT32 ept_hw_get_guest_address_width_encoding(UINT32 width) 88 { 89 UINT32 gaw_encoding = (UINT32) -1; 90 91 VMM_ASSERT(width == 21 || width == 30 || width == 39 || width == 48 || width == 57); 92 gaw_encoding = (width - 21) / 9; 93 return gaw_encoding; 94 } 95 96 UINT32 ept_hw_get_guest_address_width_from_encoding(UINT32 gaw_encoding) 97 { 98 VMM_ASSERT(gaw_encoding <= 4); 99 return 21 + (gaw_encoding * 9); 100 } 101 102 VMM_PHYS_MEM_TYPE ept_hw_get_ept_memory_type(void) 103 { 104 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 105 106 if(hw_constraints->ept_vpid_capabilities.Bits.WB) { 107 return VMM_PHYS_MEM_WRITE_BACK; 108 } 109 if(hw_constraints->ept_vpid_capabilities.Bits.WP) { 110 return VMM_PHYS_MEM_WRITE_PROTECTED; 111 } 112 if(hw_constraints->ept_vpid_capabilities.Bits.WT) { 113 return VMM_PHYS_MEM_WRITE_THROUGH; 114 } 115 if(hw_constraints->ept_vpid_capabilities.Bits.WC) { 116 return VMM_PHYS_MEM_WRITE_COMBINING; 117 } 118 if(hw_constraints->ept_vpid_capabilities.Bits.UC) { 119 return VMM_PHYS_MEM_UNCACHABLE; 120 } 121 VMM_ASSERT(0); 122 return VMM_PHYS_MEM_UNDEFINED; 123 } 124 125 UINT64 ept_hw_get_eptp(GUEST_CPU_HANDLE gcpu) 126 { 127 VMCS_OBJECT* vmcs = gcpu_get_vmcs(gcpu); 128 UINT64 eptp = 0; 129 130 VMM_ASSERT(gcpu); 131 CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu); 132 if(! ept_hw_is_ept_supported()) { 133 return eptp; 134 } 135 eptp = vmcs_read( vmcs, VMCS_EPTP_ADDRESS); 136 return eptp; 137 } 138 139 BOOLEAN ept_hw_set_eptp(GUEST_CPU_HANDLE gcpu, HPA ept_root_hpa, UINT32 gaw) 140 { 141 VMCS_OBJECT* vmcs = gcpu_get_vmcs(gcpu); 142 EPTP eptp; 143 UINT32 ept_gaw = 0; 144 145 VMM_ASSERT(gcpu); 146 VMM_ASSERT(vmcs); 147 CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu); 148 if(! ept_hw_is_ept_supported() || ept_root_hpa == 0) { 149 return FALSE; 150 } 151 ept_gaw = ept_hw_get_guest_address_width(gaw); 152 if(ept_gaw == (UINT32) -1) { 153 return FALSE; 154 } 155 eptp.Uint64 = ept_root_hpa; 156 eptp.Bits.ETMT = ept_hw_get_ept_memory_type(); 157 eptp.Bits.GAW = ept_hw_get_guest_address_width_encoding(ept_gaw); 158 eptp.Bits.Reserved = 0; 159 vmcs_write( vmcs, VMCS_EPTP_ADDRESS, eptp.Uint64); 160 return TRUE; 161 } 162 163 BOOLEAN ept_hw_is_ept_enabled(GUEST_CPU_HANDLE gcpu) 164 { 165 PROCESSOR_BASED_VM_EXECUTION_CONTROLS2 proc_ctrls2; 166 167 CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu); 168 proc_ctrls2.Uint32 = (UINT32) vmcs_read(gcpu_get_vmcs(gcpu), VMCS_CONTROL2_VECTOR_PROCESSOR_EVENTS); 169 return proc_ctrls2.Bits.EnableEPT; 170 } 171 172 // invalidate EPT 173 BOOLEAN ept_hw_is_invept_supported(void) 174 { 175 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 176 177 if(ept_hw_is_ept_supported() && hw_constraints->ept_vpid_capabilities.Bits.InveptSupported) { 178 return TRUE; 179 } 180 return FALSE; 181 } 182 183 // invalidate VPID 184 BOOLEAN ept_hw_is_invvpid_supported(void) 185 { 186 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 187 188 if(ept_hw_is_ept_supported() && hw_constraints->ept_vpid_capabilities.Bits.InvvpidSupported) { 189 return TRUE; 190 } 191 #ifdef JLMDEBUG 192 bprint("ept_hw_is_invvpid_supported is returning false\n"); 193 #endif 194 return FALSE; 195 } 196 197 BOOLEAN ept_hw_invept_all_contexts(void) 198 { 199 INVEPT_ARG arg; 200 UINT64 rflags; 201 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 202 BOOLEAN status = FALSE; 203 204 if(! ept_hw_is_invept_supported()) { 205 return TRUE; 206 } 207 vmm_zeromem(&arg, sizeof(arg)); 208 if(hw_constraints->ept_vpid_capabilities.Bits.InveptAllContexts) { 209 vmm_asm_invept(&arg, INVEPT_ALL_CONTEXTS, &rflags); 210 status = ((rflags & 0x8d5) == 0); 211 if(! status) { 212 VMM_LOG(mask_anonymous, level_trace,"ept_hw_invept_all_contexts ERROR: rflags = %p\r\n", rflags); 213 } 214 } 215 return status; 216 } 217 218 BOOLEAN ept_hw_invept_context(UINT64 eptp) 219 { 220 INVEPT_ARG arg; 221 UINT64 rflags; 222 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 223 BOOLEAN status = FALSE; 224 225 if(! ept_hw_is_invept_supported()) { 226 return TRUE; 227 } 228 vmm_zeromem(&arg, sizeof(arg)); 229 VMM_ASSERT(eptp != 0); 230 arg.eptp = eptp; 231 if(hw_constraints->ept_vpid_capabilities.Bits.InveptContextWide) { 232 vmm_asm_invept(&arg, INVEPT_CONTEXT_WIDE, &rflags); 233 status = ((rflags & 0x8d5) == 0); 234 if(! status) { 235 VMM_LOG(mask_anonymous, level_trace,"ept_hw_invept_context ERROR: eptp = %p rflags = %p\r\n", eptp, rflags); 236 } 237 } 238 else { 239 ept_hw_invept_all_contexts(); 240 } 241 return status; 242 } 243 244 BOOLEAN ept_hw_invept_individual_address(UINT64 eptp, ADDRESS gpa) 245 { 246 INVEPT_ARG arg; 247 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 248 UINT64 rflags; 249 BOOLEAN status = FALSE; 250 251 if(! ept_hw_is_invept_supported()) { 252 return TRUE; 253 } 254 vmm_zeromem(&arg, sizeof(arg)); 255 VMM_ASSERT((eptp != 0) && (gpa != 0)); 256 arg.eptp = eptp; 257 arg.gpa = gpa; 258 if(hw_constraints->ept_vpid_capabilities.Bits.InveptIndividualAddress) { 259 vmm_asm_invept(&arg, INVEPT_INDIVIDUAL_ADDRESS, &rflags); 260 status = ((rflags & 0x8d5) == 0); 261 if(! status) { 262 VMM_LOG(mask_anonymous, level_trace, 263 "ept_hw_invept_individual_address ERROR: eptp = %p gpa = %p rflags = %p\r\n", 264 eptp, gpa, rflags); 265 } 266 } 267 else { 268 ept_hw_invept_context(eptp); 269 } 270 return status; 271 } 272 273 BOOLEAN ept_hw_invvpid_individual_address(UINT64 vpid, ADDRESS gva) 274 { 275 INVVPID_ARG arg; 276 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 277 UINT64 rflags; 278 BOOLEAN status = FALSE; 279 280 if(!ept_hw_is_invvpid_supported()) { 281 VMM_ASSERT(0); 282 return TRUE; 283 } 284 arg.vpid = vpid; 285 arg.gva = gva; 286 if(hw_constraints->ept_vpid_capabilities.Bits.InvvpidIndividualAddress) { 287 vmm_asm_invvpid(&arg, INVVPID_INDIVIDUAL_ADDRESS, &rflags); 288 status = ((rflags & 0x8d5) == 0); 289 if(! status) { 290 VMM_LOG(mask_anonymous, level_trace, 291 "ept_hw_invvpid_individual_address ERROR: vpid = %d gva = %p rflags = %p\r\n", 292 vpid, gva, rflags); 293 VMM_ASSERT(0); 294 } 295 } 296 return status; 297 } 298 299 BOOLEAN ept_hw_invvpid_all_contexts(void) 300 { 301 INVVPID_ARG arg; 302 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 303 UINT64 rflags; 304 BOOLEAN status = FALSE; 305 306 if(! ept_hw_is_invvpid_supported()) { 307 VMM_ASSERT(0); 308 return TRUE; 309 } 310 arg.vpid = 0; // vpid; 311 //arg.gva = gva; 312 313 if(hw_constraints->ept_vpid_capabilities.Bits.InvvpidAllContexts) { 314 vmm_asm_invvpid(&arg, INVVPID_ALL_CONTEXTS, &rflags); 315 status = ((rflags & 0x8d5) == 0); 316 if(! status) { 317 VMM_LOG(mask_anonymous, level_trace,"ept_hw_invvpid_all_contexts ERROR: rflags = %p\r\n", rflags); 318 VMM_ASSERT(0); 319 } 320 } 321 return status; 322 } 323 324 325 BOOLEAN ept_hw_invvpid_single_context(UINT64 vpid) 326 { 327 INVVPID_ARG arg; 328 const VMCS_HW_CONSTRAINTS *hw_constraints = vmcs_hw_get_vmx_constraints(); 329 UINT64 rflags; 330 BOOLEAN status = FALSE; 331 332 #ifdef JLMDEBUG1 333 bprint("ept_hw_invvpid_single_context\n"); 334 #endif 335 if(!ept_hw_is_invvpid_supported()) { 336 VMM_ASSERT(0); 337 return TRUE; 338 } 339 arg.vpid = vpid; 340 if(hw_constraints->ept_vpid_capabilities.Bits.InvvpidContextWide) { 341 vmm_asm_invvpid(&arg, INVVPID_SINGLE_CONTEXT, &rflags); 342 status = ((rflags & 0x8d5) == 0); 343 if(!status) { 344 #ifdef JLMDEBUG 345 bprint("vmm_asm_invvpid failed\n"); 346 #endif 347 VMM_LOG(mask_anonymous, level_trace, 348 "ept_hw_invvpid_all_contexts ERROR: rflags = %p\r\n", rflags); 349 VMM_ASSERT(0); 350 } 351 } 352 return status; 353 } 354 355 BOOLEAN ept_hw_enable_ept(GUEST_CPU_HANDLE gcpu) 356 { 357 PROCESSOR_BASED_VM_EXECUTION_CONTROLS2 proc_ctrls2; 358 VMEXIT_CONTROL vmexit_request; 359 360 CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu); 361 VMM_ASSERT(gcpu); 362 if(! ept_hw_is_ept_supported()) { 363 return FALSE; 364 } 365 proc_ctrls2.Uint32 = 0; 366 vmm_zeromem(&vmexit_request, sizeof(vmexit_request)); 367 368 proc_ctrls2.Bits.EnableEPT = 1; 369 #ifdef ENABLE_VPID 370 proc_ctrls2.Bits.EnableVPID = 1; 371 vmcs_write(gcpu_get_vmcs(gcpu), VMCS_VPID, 1 + gcpu->vcpu.guest_id); 372 #endif 373 vmexit_request.proc_ctrls2.bit_mask = proc_ctrls2.Uint32; 374 vmexit_request.proc_ctrls2.bit_request = UINT64_ALL_ONES; 375 // FIXME 376 gcpu_control_setup( gcpu, &vmexit_request ); 377 return TRUE; 378 } 379 380 void ept_hw_disable_ept(GUEST_CPU_HANDLE gcpu) 381 { 382 PROCESSOR_BASED_VM_EXECUTION_CONTROLS2 proc_ctrls2; 383 VMEXIT_CONTROL vmexit_request; 384 CHECK_EXECUTION_ON_LOCAL_HOST_CPU(gcpu); 385 ept_hw_invvpid_single_context(1 + gcpu->vcpu.guest_id); 386 proc_ctrls2.Uint32 = 0; 387 vmm_zeromem(&vmexit_request, sizeof(vmexit_request)); 388 proc_ctrls2.Bits.EnableEPT = 1; 389 #ifdef ENABLE_VPID 390 proc_ctrls2.Bits.EnableVPID = 1; 391 vmcs_write(gcpu_get_vmcs(gcpu), VMCS_VPID, 0); 392 #endif 393 vmexit_request.proc_ctrls2.bit_mask = proc_ctrls2.Uint32; 394 vmexit_request.proc_ctrls2.bit_request = 0; 395 // FIXME 396 gcpu_control_setup( gcpu, &vmexit_request ); 397 }