VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp@ 15733

Last change on this file since 15733 was 15733, checked in by vboxsync, 16 years ago

Experiment with the VT-x preemption timer for the 32/64 switcher.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 152.5 KB
Line 
1/* $Id: HWVMXR0.cpp 15733 2008-12-23 15:13:21Z vboxsync $ */
2/** @file
3 * HWACCM VMX - Host Context Ring 0.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_HWACCM
27#include <VBox/hwaccm.h>
28#include "HWACCMInternal.h"
29#include <VBox/vm.h>
30#include <VBox/x86.h>
31#include <VBox/pgm.h>
32#include <VBox/pdm.h>
33#include <VBox/err.h>
34#include <VBox/log.h>
35#include <VBox/selm.h>
36#include <VBox/iom.h>
37#include <iprt/param.h>
38#include <iprt/assert.h>
39#include <iprt/asm.h>
40#include <iprt/string.h>
41#include "HWVMXR0.h"
42
43/*******************************************************************************
44* Defined Constants And Macros *
45*******************************************************************************/
46#if defined(RT_ARCH_AMD64)
47# define VMX_IS_64BIT_HOST_MODE() (true)
48#elif defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
49# define VMX_IS_64BIT_HOST_MODE() (g_fVMXIs64bitHost != 0)
50#else
51# define VMX_IS_64BIT_HOST_MODE() (false)
52#endif
53
54/*******************************************************************************
55* Global Variables *
56*******************************************************************************/
57/* IO operation lookup arrays. */
58static uint32_t const g_aIOSize[4] = {1, 2, 0, 4};
59static uint32_t const g_aIOOpAnd[4] = {0xff, 0xffff, 0, 0xffffffff};
60
61#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
62/** See HWACCMR0A.asm. */
63extern "C" uint32_t g_fVMXIs64bitHost;
64#endif
65
66/*******************************************************************************
67* Local Functions *
68*******************************************************************************/
69static void VMXR0ReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, int rc, PCPUMCTX pCtx);
70static void vmxR0SetupTLBEPT(PVM pVM, PVMCPU pVCpu);
71static void vmxR0SetupTLBVPID(PVM pVM, PVMCPU pVCpu);
72static void vmxR0SetupTLBDummy(PVM pVM, PVMCPU pVCpu);
73static void vmxR0FlushEPT(PVM pVM, PVMCPU pVCpu, VMX_FLUSH enmFlush, RTGCPHYS GCPhys);
74static void vmxR0FlushVPID(PVM pVM, PVMCPU pVCpu, VMX_FLUSH enmFlush, RTGCPTR GCPtr);
75static void vmxR0UpdateExceptionBitmap(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx);
76#ifdef VBOX_STRICT
77static bool vmxR0IsValidReadField(uint32_t idxField);
78static bool vmxR0IsValidWriteField(uint32_t idxField);
79#endif
80
81static void VMXR0CheckError(PVM pVM, PVMCPU pVCpu, int rc)
82{
83 if (rc == VERR_VMX_GENERIC)
84 {
85 RTCCUINTREG instrError;
86
87 VMXReadVMCS(VMX_VMCS32_RO_VM_INSTR_ERROR, &instrError);
88 pVCpu->hwaccm.s.vmx.lasterror.ulInstrError = instrError;
89 }
90 pVM->hwaccm.s.lLastError = rc;
91}
92
93/**
94 * Sets up and activates VT-x on the current CPU
95 *
96 * @returns VBox status code.
97 * @param pCpu CPU info struct
98 * @param pVM The VM to operate on. (can be NULL after a resume!!)
99 * @param pvPageCpu Pointer to the global cpu page
100 * @param pPageCpuPhys Physical address of the global cpu page
101 */
102VMMR0DECL(int) VMXR0EnableCpu(PHWACCM_CPUINFO pCpu, PVM pVM, void *pvPageCpu, RTHCPHYS pPageCpuPhys)
103{
104 AssertReturn(pPageCpuPhys, VERR_INVALID_PARAMETER);
105 AssertReturn(pvPageCpu, VERR_INVALID_PARAMETER);
106
107#ifdef LOG_ENABLED
108 SUPR0Printf("VMXR0EnableCpu cpu %d page (%x) %x\n", pCpu->idCpu, pvPageCpu, (uint32_t)pPageCpuPhys);
109#endif
110 if (pVM)
111 {
112 /* Set revision dword at the beginning of the VMXON structure. */
113 *(uint32_t *)pvPageCpu = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hwaccm.s.vmx.msr.vmx_basic_info);
114 }
115
116 /** @todo we should unmap the two pages from the virtual address space in order to prevent accidental corruption.
117 * (which can have very bad consequences!!!)
118 */
119
120 /* Make sure the VMX instructions don't cause #UD faults. */
121 ASMSetCR4(ASMGetCR4() | X86_CR4_VMXE);
122
123 /* Enter VMX Root Mode */
124 int rc = VMXEnable(pPageCpuPhys);
125 if (RT_FAILURE(rc))
126 {
127 if (pVM)
128 VMXR0CheckError(pVM, &pVM->aCpus[0], rc);
129 ASMSetCR4(ASMGetCR4() & ~X86_CR4_VMXE);
130 return VERR_VMX_VMXON_FAILED;
131 }
132 return VINF_SUCCESS;
133}
134
135/**
136 * Deactivates VT-x on the current CPU
137 *
138 * @returns VBox status code.
139 * @param pCpu CPU info struct
140 * @param pvPageCpu Pointer to the global cpu page
141 * @param pPageCpuPhys Physical address of the global cpu page
142 */
143VMMR0DECL(int) VMXR0DisableCpu(PHWACCM_CPUINFO pCpu, void *pvPageCpu, RTHCPHYS pPageCpuPhys)
144{
145 AssertReturn(pPageCpuPhys, VERR_INVALID_PARAMETER);
146 AssertReturn(pvPageCpu, VERR_INVALID_PARAMETER);
147
148 /* Leave VMX Root Mode. */
149 VMXDisable();
150
151 /* And clear the X86_CR4_VMXE bit */
152 ASMSetCR4(ASMGetCR4() & ~X86_CR4_VMXE);
153
154#ifdef LOG_ENABLED
155 SUPR0Printf("VMXR0DisableCpu cpu %d\n", pCpu->idCpu);
156#endif
157 return VINF_SUCCESS;
158}
159
160/**
161 * Does Ring-0 per VM VT-x init.
162 *
163 * @returns VBox status code.
164 * @param pVM The VM to operate on.
165 */
166VMMR0DECL(int) VMXR0InitVM(PVM pVM)
167{
168 int rc;
169
170#ifdef LOG_ENABLED
171 SUPR0Printf("VMXR0InitVM %x\n", pVM);
172#endif
173
174 pVM->hwaccm.s.vmx.pMemObjAPIC = NIL_RTR0MEMOBJ;
175
176 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW)
177 {
178 /* Allocate one page for the virtual APIC mmio cache. */
179 rc = RTR0MemObjAllocCont(&pVM->hwaccm.s.vmx.pMemObjAPIC, 1 << PAGE_SHIFT, true /* executable R0 mapping */);
180 AssertRC(rc);
181 if (RT_FAILURE(rc))
182 return rc;
183
184 pVM->hwaccm.s.vmx.pAPIC = (uint8_t *)RTR0MemObjAddress(pVM->hwaccm.s.vmx.pMemObjAPIC);
185 pVM->hwaccm.s.vmx.pAPICPhys = RTR0MemObjGetPagePhysAddr(pVM->hwaccm.s.vmx.pMemObjAPIC, 0);
186 ASMMemZero32(pVM->hwaccm.s.vmx.pAPIC, PAGE_SIZE);
187 }
188 else
189 {
190 pVM->hwaccm.s.vmx.pMemObjAPIC = 0;
191 pVM->hwaccm.s.vmx.pAPIC = 0;
192 pVM->hwaccm.s.vmx.pAPICPhys = 0;
193 }
194
195 /* Allocate the MSR bitmap if this feature is supported. */
196 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_MSR_BITMAPS)
197 {
198 rc = RTR0MemObjAllocCont(&pVM->hwaccm.s.vmx.pMemObjMSRBitmap, 1 << PAGE_SHIFT, true /* executable R0 mapping */);
199 AssertRC(rc);
200 if (RT_FAILURE(rc))
201 return rc;
202
203 pVM->hwaccm.s.vmx.pMSRBitmap = (uint8_t *)RTR0MemObjAddress(pVM->hwaccm.s.vmx.pMemObjMSRBitmap);
204 pVM->hwaccm.s.vmx.pMSRBitmapPhys = RTR0MemObjGetPagePhysAddr(pVM->hwaccm.s.vmx.pMemObjMSRBitmap, 0);
205 memset(pVM->hwaccm.s.vmx.pMSRBitmap, 0xff, PAGE_SIZE);
206 }
207
208 /* Allocate VMCBs for all guest CPUs. */
209 for (unsigned i=0;i<pVM->cCPUs;i++)
210 {
211 PVMCPU pVCpu = &pVM->aCpus[i];
212
213 pVCpu->hwaccm.s.vmx.pMemObjVMCS = NIL_RTR0MEMOBJ;
214
215 /* Allocate one page for the VM control structure (VMCS). */
216 rc = RTR0MemObjAllocCont(&pVCpu->hwaccm.s.vmx.pMemObjVMCS, 1 << PAGE_SHIFT, true /* executable R0 mapping */);
217 AssertRC(rc);
218 if (RT_FAILURE(rc))
219 return rc;
220
221 pVCpu->hwaccm.s.vmx.pVMCS = RTR0MemObjAddress(pVCpu->hwaccm.s.vmx.pMemObjVMCS);
222 pVCpu->hwaccm.s.vmx.pVMCSPhys = RTR0MemObjGetPagePhysAddr(pVCpu->hwaccm.s.vmx.pMemObjVMCS, 0);
223 ASMMemZero32(pVCpu->hwaccm.s.vmx.pVMCS, PAGE_SIZE);
224
225 pVCpu->hwaccm.s.vmx.cr0_mask = 0;
226 pVCpu->hwaccm.s.vmx.cr4_mask = 0;
227
228 /* Current guest paging mode. */
229 pVCpu->hwaccm.s.vmx.enmLastSeenGuestMode = PGMMODE_REAL;
230
231#ifdef LOG_ENABLED
232 SUPR0Printf("VMXR0InitVM %x VMCS=%x (%x)\n", pVM, pVCpu->hwaccm.s.vmx.pVMCS, (uint32_t)pVCpu->hwaccm.s.vmx.pVMCSPhys);
233#endif
234 }
235
236 return VINF_SUCCESS;
237}
238
239/**
240 * Does Ring-0 per VM VT-x termination.
241 *
242 * @returns VBox status code.
243 * @param pVM The VM to operate on.
244 */
245VMMR0DECL(int) VMXR0TermVM(PVM pVM)
246{
247 for (unsigned i=0;i<pVM->cCPUs;i++)
248 {
249 if (pVM->aCpus[i].hwaccm.s.vmx.pMemObjVMCS != NIL_RTR0MEMOBJ)
250 {
251 RTR0MemObjFree(pVM->aCpus[i].hwaccm.s.vmx.pMemObjVMCS, false);
252 pVM->aCpus[i].hwaccm.s.vmx.pMemObjVMCS = NIL_RTR0MEMOBJ;
253 pVM->aCpus[i].hwaccm.s.vmx.pVMCS = 0;
254 pVM->aCpus[i].hwaccm.s.vmx.pVMCSPhys = 0;
255 }
256 }
257 if (pVM->hwaccm.s.vmx.pMemObjAPIC != NIL_RTR0MEMOBJ)
258 {
259 RTR0MemObjFree(pVM->hwaccm.s.vmx.pMemObjAPIC, false);
260 pVM->hwaccm.s.vmx.pMemObjAPIC = NIL_RTR0MEMOBJ;
261 pVM->hwaccm.s.vmx.pAPIC = 0;
262 pVM->hwaccm.s.vmx.pAPICPhys = 0;
263 }
264 if (pVM->hwaccm.s.vmx.pMemObjMSRBitmap != NIL_RTR0MEMOBJ)
265 {
266 RTR0MemObjFree(pVM->hwaccm.s.vmx.pMemObjMSRBitmap, false);
267 pVM->hwaccm.s.vmx.pMemObjMSRBitmap = NIL_RTR0MEMOBJ;
268 pVM->hwaccm.s.vmx.pMSRBitmap = 0;
269 pVM->hwaccm.s.vmx.pMSRBitmapPhys = 0;
270 }
271 return VINF_SUCCESS;
272}
273
274/**
275 * Sets up VT-x for the specified VM
276 *
277 * @returns VBox status code.
278 * @param pVM The VM to operate on.
279 */
280VMMR0DECL(int) VMXR0SetupVM(PVM pVM)
281{
282 int rc = VINF_SUCCESS;
283 uint32_t val;
284
285 AssertReturn(pVM, VERR_INVALID_PARAMETER);
286
287 for (unsigned i=0;i<pVM->cCPUs;i++)
288 {
289 PVMCPU pVCpu = &pVM->aCpus[i];
290
291 Assert(pVCpu->hwaccm.s.vmx.pVMCS);
292
293 /* Set revision dword at the beginning of the VMCS structure. */
294 *(uint32_t *)pVCpu->hwaccm.s.vmx.pVMCS = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hwaccm.s.vmx.msr.vmx_basic_info);
295
296 /* Clear VM Control Structure. */
297 Log(("pVMCSPhys = %RHp\n", pVCpu->hwaccm.s.vmx.pVMCSPhys));
298 rc = VMXClearVMCS(pVCpu->hwaccm.s.vmx.pVMCSPhys);
299 if (RT_FAILURE(rc))
300 goto vmx_end;
301
302 /* Activate the VM Control Structure. */
303 rc = VMXActivateVMCS(pVCpu->hwaccm.s.vmx.pVMCSPhys);
304 if (RT_FAILURE(rc))
305 goto vmx_end;
306
307 /* VMX_VMCS_CTRL_PIN_EXEC_CONTROLS
308 * Set required bits to one and zero according to the MSR capabilities.
309 */
310 val = pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.disallowed0;
311 /* External and non-maskable interrupts cause VM-exits. */
312 val = val | VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_EXT_INT_EXIT | VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_NMI_EXIT;
313 val &= pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.allowed1;
314
315 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, val);
316 AssertRC(rc);
317
318 /* VMX_VMCS_CTRL_PROC_EXEC_CONTROLS
319 * Set required bits to one and zero according to the MSR capabilities.
320 */
321 val = pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.disallowed0;
322 /* Program which event cause VM-exits and which features we want to use. */
323 val = val | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_HLT_EXIT
324 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_TSC_OFFSET
325 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT
326 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_UNCOND_IO_EXIT
327 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MWAIT_EXIT; /* don't execute mwait or else we'll idle inside the guest (host thinks the cpu load is high) */
328
329 /* Without nested paging we should intercept invlpg and cr3 mov instructions. */
330 if (!pVM->hwaccm.s.fNestedPaging)
331 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INVLPG_EXIT
332 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_LOAD_EXIT
333 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_STORE_EXIT;
334
335 /* Note: VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MWAIT_EXIT might cause a vmlaunch failure with an invalid control fields error. (combined with some other exit reasons) */
336 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW)
337 {
338 /* CR8 reads from the APIC shadow page; writes cause an exit is they lower the TPR below the threshold */
339 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW;
340 Assert(pVM->hwaccm.s.vmx.pAPIC);
341 }
342 else
343 /* Exit on CR8 reads & writes in case the TPR shadow feature isn't present. */
344 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR8_STORE_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR8_LOAD_EXIT;
345
346#ifdef VBOX_WITH_VTX_MSR_BITMAPS
347 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_MSR_BITMAPS)
348 {
349 Assert(pVM->hwaccm.s.vmx.pMSRBitmapPhys);
350 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_MSR_BITMAPS;
351 }
352#endif
353
354 /* We will use the secondary control if it's present. */
355 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
356
357 /* Mask away the bits that the CPU doesn't support */
358 /** @todo make sure they don't conflict with the above requirements. */
359 val &= pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1;
360 pVCpu->hwaccm.s.vmx.proc_ctls = val;
361
362 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, val);
363 AssertRC(rc);
364
365 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
366 {
367 /* VMX_VMCS_CTRL_PROC_EXEC_CONTROLS2
368 * Set required bits to one and zero according to the MSR capabilities.
369 */
370 val = pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.disallowed0;
371 val |= VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT;
372
373#ifdef HWACCM_VTX_WITH_EPT
374 if (pVM->hwaccm.s.fNestedPaging)
375 val |= VMX_VMCS_CTRL_PROC_EXEC2_EPT;
376#endif /* HWACCM_VTX_WITH_EPT */
377#ifdef HWACCM_VTX_WITH_VPID
378 else
379 if (pVM->hwaccm.s.vmx.fVPID)
380 val |= VMX_VMCS_CTRL_PROC_EXEC2_VPID;
381#endif /* HWACCM_VTX_WITH_VPID */
382
383 /* Mask away the bits that the CPU doesn't support */
384 /** @todo make sure they don't conflict with the above requirements. */
385 val &= pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.allowed1;
386
387 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS2, val);
388 AssertRC(rc);
389 }
390
391 /* VMX_VMCS_CTRL_CR3_TARGET_COUNT
392 * Set required bits to one and zero according to the MSR capabilities.
393 */
394 rc = VMXWriteVMCS(VMX_VMCS_CTRL_CR3_TARGET_COUNT, 0);
395 AssertRC(rc);
396
397 /* Forward all exception except #NM & #PF to the guest.
398 * We always need to check pagefaults since our shadow page table can be out of sync.
399 * And we always lazily sync the FPU & XMM state.
400 */
401
402 /** @todo Possible optimization:
403 * Keep the FPU and XMM state current in the EM thread. That way there's no need to
404 * lazily sync anything, but the downside is that we can't use the FPU stack or XMM
405 * registers ourselves of course.
406 *
407 * Note: only possible if the current state is actually ours (X86_CR0_TS flag)
408 */
409
410 /* Don't filter page faults; all of them should cause a switch. */
411 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PAGEFAULT_ERROR_MASK, 0);
412 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_PAGEFAULT_ERROR_MATCH, 0);
413 AssertRC(rc);
414
415 /* Init TSC offset to zero. */
416 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_TSC_OFFSET_FULL, 0);
417 AssertRC(rc);
418
419 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_IO_BITMAP_A_FULL, 0);
420 AssertRC(rc);
421
422 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_IO_BITMAP_B_FULL, 0);
423 AssertRC(rc);
424
425 /* Set the MSR bitmap address. */
426 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_MSR_BITMAPS)
427 {
428 /* Optional */
429 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_MSR_BITMAP_FULL, pVM->hwaccm.s.vmx.pMSRBitmapPhys);
430 AssertRC(rc);
431 }
432
433 /* Clear MSR controls. */
434 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_VMEXIT_MSR_STORE_FULL, 0);
435 rc |= VMXWriteVMCS64(VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_FULL, 0);
436 rc |= VMXWriteVMCS64(VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_FULL, 0);
437 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_EXIT_MSR_STORE_COUNT, 0);
438 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_EXIT_MSR_LOAD_COUNT, 0);
439 AssertRC(rc);
440
441 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW)
442 {
443 Assert(pVM->hwaccm.s.vmx.pMemObjAPIC);
444 /* Optional */
445 rc = VMXWriteVMCS(VMX_VMCS_CTRL_TPR_THRESHOLD, 0);
446 rc |= VMXWriteVMCS64(VMX_VMCS_CTRL_VAPIC_PAGEADDR_FULL, pVM->hwaccm.s.vmx.pAPICPhys);
447 AssertRC(rc);
448 }
449
450 /* Set link pointer to -1. Not currently used. */
451 rc = VMXWriteVMCS64(VMX_VMCS_GUEST_LINK_PTR_FULL, 0xFFFFFFFFFFFFFFFFULL);
452 AssertRC(rc);
453
454 /* Clear VM Control Structure. Marking it inactive, clearing implementation specific data and writing back VMCS data to memory. */
455 rc = VMXClearVMCS(pVCpu->hwaccm.s.vmx.pVMCSPhys);
456 AssertRC(rc);
457
458 /* Configure the VMCS read cache. */
459 PVMCSCACHE pCache = &pVCpu->hwaccm.s.vmx.VMCSCache;
460
461 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_RIP);
462 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_RSP);
463 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_GUEST_RFLAGS);
464 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE);
465 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_CTRL_CR0_READ_SHADOW);
466 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_CR0);
467 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_CTRL_CR4_READ_SHADOW);
468 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_CR4);
469 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_DR7);
470 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_GUEST_SYSENTER_CS);
471 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_SYSENTER_EIP);
472 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_SYSENTER_ESP);
473 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_GUEST_GDTR_LIMIT);
474 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_GDTR_BASE);
475 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_GUEST_IDTR_LIMIT);
476 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_IDTR_BASE);
477
478 VMX_SETUP_SELREG(ES, pCache);
479 VMX_SETUP_SELREG(SS, pCache);
480 VMX_SETUP_SELREG(CS, pCache);
481 VMX_SETUP_SELREG(DS, pCache);
482 VMX_SETUP_SELREG(FS, pCache);
483 VMX_SETUP_SELREG(GS, pCache);
484 VMX_SETUP_SELREG(LDTR, pCache);
485 VMX_SETUP_SELREG(TR, pCache);
486
487 /* Status code VMCS reads. */
488 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_REASON);
489 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_VM_INSTR_ERROR);
490 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_INSTR_LENGTH);
491 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_INTERRUPTION_ERRCODE);
492 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO);
493 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_INSTR_INFO);
494 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_RO_EXIT_QUALIFICATION);
495 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_IDT_INFO);
496 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_IDT_ERRCODE);
497
498 if (pVM->hwaccm.s.fNestedPaging)
499 {
500 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_CR3);
501 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_EXIT_PHYS_ADDR_FULL);
502 pCache->Read.cValidEntries = VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX;
503 }
504 else
505 pCache->Read.cValidEntries = VMX_VMCS_MAX_CACHE_IDX;
506 } /* for each VMCPU */
507
508 /* Choose the right TLB setup function. */
509 if (pVM->hwaccm.s.fNestedPaging)
510 {
511 pVM->hwaccm.s.vmx.pfnSetupTaggedTLB = vmxR0SetupTLBEPT;
512
513 /* Default values for flushing. */
514 pVM->hwaccm.s.vmx.enmFlushPage = VMX_FLUSH_ALL_CONTEXTS;
515 pVM->hwaccm.s.vmx.enmFlushContext = VMX_FLUSH_ALL_CONTEXTS;
516
517 /* If the capabilities specify we can do more, then make use of it. */
518 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVEPT_CAPS_INDIV)
519 pVM->hwaccm.s.vmx.enmFlushPage = VMX_FLUSH_PAGE;
520 else
521 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVEPT_CAPS_CONTEXT)
522 pVM->hwaccm.s.vmx.enmFlushPage = VMX_FLUSH_SINGLE_CONTEXT;
523
524 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVEPT_CAPS_CONTEXT)
525 pVM->hwaccm.s.vmx.enmFlushContext = VMX_FLUSH_SINGLE_CONTEXT;
526 }
527#ifdef HWACCM_VTX_WITH_VPID
528 else
529 if (pVM->hwaccm.s.vmx.fVPID)
530 {
531 pVM->hwaccm.s.vmx.pfnSetupTaggedTLB = vmxR0SetupTLBVPID;
532
533 /* Default values for flushing. */
534 pVM->hwaccm.s.vmx.enmFlushPage = VMX_FLUSH_ALL_CONTEXTS;
535 pVM->hwaccm.s.vmx.enmFlushContext = VMX_FLUSH_ALL_CONTEXTS;
536
537 /* If the capabilities specify we can do more, then make use of it. */
538 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_INDIV)
539 pVM->hwaccm.s.vmx.enmFlushPage = VMX_FLUSH_PAGE;
540 else
541 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_CONTEXT)
542 pVM->hwaccm.s.vmx.enmFlushPage = VMX_FLUSH_SINGLE_CONTEXT;
543
544 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_CONTEXT)
545 pVM->hwaccm.s.vmx.enmFlushContext = VMX_FLUSH_SINGLE_CONTEXT;
546 }
547#endif /* HWACCM_VTX_WITH_VPID */
548 else
549 pVM->hwaccm.s.vmx.pfnSetupTaggedTLB = vmxR0SetupTLBDummy;
550
551vmx_end:
552 VMXR0CheckError(pVM, &pVM->aCpus[0], rc);
553 return rc;
554}
555
556
557/**
558 * Injects an event (trap or external interrupt)
559 *
560 * @returns VBox status code.
561 * @param pVM The VM to operate on.
562 * @param pVCpu The VMCPU to operate on.
563 * @param pCtx CPU Context
564 * @param intInfo VMX interrupt info
565 * @param cbInstr Opcode length of faulting instruction
566 * @param errCode Error code (optional)
567 */
568static int VMXR0InjectEvent(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t intInfo, uint32_t cbInstr, uint32_t errCode)
569{
570 int rc;
571 uint32_t iGate = VMX_EXIT_INTERRUPTION_INFO_VECTOR(intInfo);
572
573#ifdef VBOX_STRICT
574 if (iGate == 0xE)
575 LogFlow(("VMXR0InjectEvent: Injecting interrupt %d at %RGv error code=%08x CR2=%08x intInfo=%08x\n", iGate, (RTGCPTR)pCtx->rip, errCode, pCtx->cr2, intInfo));
576 else
577 if (iGate < 0x20)
578 LogFlow(("VMXR0InjectEvent: Injecting interrupt %d at %RGv error code=%08x\n", iGate, (RTGCPTR)pCtx->rip, errCode));
579 else
580 {
581 LogFlow(("INJ-EI: %x at %RGv\n", iGate, (RTGCPTR)pCtx->rip));
582 Assert(!VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS));
583 Assert(pCtx->eflags.u32 & X86_EFL_IF);
584 }
585#endif
586
587#ifdef HWACCM_VMX_EMULATE_REALMODE
588 if (CPUMIsGuestInRealModeEx(pCtx))
589 {
590 RTGCPHYS GCPhysHandler;
591 uint16_t offset, ip;
592 RTSEL sel;
593
594 /* Injecting events doesn't work right with real mode emulation.
595 * (#GP if we try to inject external hardware interrupts)
596 * Inject the interrupt or trap directly instead.
597 */
598 Log(("Manual interrupt/trap '%x' inject (real mode)\n", iGate));
599
600 /* Check if the interrupt handler is present. */
601 if (iGate * 4 + 3 > pCtx->idtr.cbIdt)
602 {
603 Log(("IDT cbIdt violation\n"));
604 if (iGate != X86_XCPT_DF)
605 {
606 RTGCUINTPTR intInfo;
607
608 intInfo = (iGate == X86_XCPT_GP) ? (uint32_t)X86_XCPT_DF : iGate;
609 intInfo |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
610 intInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
611 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HWEXCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
612
613 return VMXR0InjectEvent(pVM, pVCpu, pCtx, intInfo, 0, 0 /* no error code according to the Intel docs */);
614 }
615 Log(("Triple fault -> reset the VM!\n"));
616 return VINF_EM_RESET;
617 }
618 if ( VMX_EXIT_INTERRUPTION_INFO_TYPE(intInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW
619 || iGate == 3 /* Both #BP and #OF point to the instruction after. */
620 || iGate == 4)
621 {
622 ip = pCtx->ip + cbInstr;
623 }
624 else
625 ip = pCtx->ip;
626
627 /* Read the selector:offset pair of the interrupt handler. */
628 GCPhysHandler = (RTGCPHYS)pCtx->idtr.pIdt + iGate * 4;
629 PGMPhysRead(pVM, GCPhysHandler, &offset, sizeof(offset));
630 PGMPhysRead(pVM, GCPhysHandler + 2, &sel, sizeof(sel));
631
632 LogFlow(("IDT handler %04X:%04X\n", sel, offset));
633
634 /* Construct the stack frame. */
635 /** @todo should check stack limit. */
636 pCtx->sp -= 2;
637 LogFlow(("ss:sp %04X:%04X eflags=%x\n", pCtx->ss, pCtx->sp, pCtx->eflags.u));
638 PGMPhysWrite(pVM, pCtx->ssHid.u64Base + pCtx->sp, &pCtx->eflags, sizeof(uint16_t));
639 pCtx->sp -= 2;
640 LogFlow(("ss:sp %04X:%04X cs=%x\n", pCtx->ss, pCtx->sp, pCtx->cs));
641 PGMPhysWrite(pVM, pCtx->ssHid.u64Base + pCtx->sp, &pCtx->cs, sizeof(uint16_t));
642 pCtx->sp -= 2;
643 LogFlow(("ss:sp %04X:%04X ip=%x\n", pCtx->ss, pCtx->sp, ip));
644 PGMPhysWrite(pVM, pCtx->ssHid.u64Base + pCtx->sp, &ip, sizeof(ip));
645
646 /* Update the CPU state for executing the handler. */
647 pCtx->rip = offset;
648 pCtx->cs = sel;
649 pCtx->csHid.u64Base = sel << 4;
650 pCtx->eflags.u &= ~(X86_EFL_IF|X86_EFL_TF|X86_EFL_RF|X86_EFL_AC);
651
652 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_SEGMENT_REGS;
653 return VINF_SUCCESS;
654 }
655#endif /* HWACCM_VMX_EMULATE_REALMODE */
656
657 /* Set event injection state. */
658 rc = VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_IRQ_INFO, intInfo | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT));
659
660 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
661 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_EXCEPTION_ERRCODE, errCode);
662
663 AssertRC(rc);
664 return rc;
665}
666
667
668/**
669 * Checks for pending guest interrupts and injects them
670 *
671 * @returns VBox status code.
672 * @param pVM The VM to operate on.
673 * @param pVCpu The VMCPU to operate on.
674 * @param pCtx CPU Context
675 */
676static int VMXR0CheckPendingInterrupt(PVM pVM, PVMCPU pVCpu, CPUMCTX *pCtx)
677{
678 int rc;
679
680 /* Dispatch any pending interrupts. (injected before, but a VM exit occurred prematurely) */
681 if (pVCpu->hwaccm.s.Event.fPending)
682 {
683 Log(("Reinjecting event %RX64 %08x at %RGv cr2=%RX64\n", pVCpu->hwaccm.s.Event.intInfo, pVCpu->hwaccm.s.Event.errCode, (RTGCPTR)pCtx->rip, pCtx->cr2));
684 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatIntReinject);
685 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, pVCpu->hwaccm.s.Event.intInfo, 0, pVCpu->hwaccm.s.Event.errCode);
686 AssertRC(rc);
687
688 pVCpu->hwaccm.s.Event.fPending = false;
689 return VINF_SUCCESS;
690 }
691
692 if (pVM->hwaccm.s.fInjectNMI)
693 {
694 RTGCUINTPTR intInfo;
695
696 intInfo = X86_XCPT_NMI;
697 intInfo |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
698 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
699
700 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, intInfo, 0, 0);
701 AssertRC(rc);
702
703 pVM->hwaccm.s.fInjectNMI = false;
704 return VINF_SUCCESS;
705 }
706
707 /* When external interrupts are pending, we should exit the VM when IF is set. */
708 if ( !TRPMHasTrap(pVM)
709 && VM_FF_ISPENDING(pVM, (VM_FF_INTERRUPT_APIC|VM_FF_INTERRUPT_PIC)))
710 {
711 if (!(pCtx->eflags.u32 & X86_EFL_IF))
712 {
713 if (!(pVCpu->hwaccm.s.vmx.proc_ctls & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_IRQ_WINDOW_EXIT))
714 {
715 LogFlow(("Enable irq window exit!\n"));
716 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_IRQ_WINDOW_EXIT;
717 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
718 AssertRC(rc);
719 }
720 /* else nothing to do but wait */
721 }
722 else
723 if (!VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS))
724 {
725 uint8_t u8Interrupt;
726
727 rc = PDMGetInterrupt(pVM, &u8Interrupt);
728 Log(("Dispatch interrupt: u8Interrupt=%x (%d) rc=%Rrc cs:rip=%04X:%RGv\n", u8Interrupt, u8Interrupt, rc, pCtx->cs, (RTGCPTR)pCtx->rip));
729 if (RT_SUCCESS(rc))
730 {
731 rc = TRPMAssertTrap(pVM, u8Interrupt, TRPM_HARDWARE_INT);
732 AssertRC(rc);
733 }
734 else
735 {
736 /* Can only happen in rare cases where a pending interrupt is cleared behind our back */
737 Assert(!VM_FF_ISPENDING(pVM, (VM_FF_INTERRUPT_APIC|VM_FF_INTERRUPT_PIC)));
738 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatSwitchGuestIrq);
739 /* Just continue */
740 }
741 }
742 else
743 Log(("Pending interrupt blocked at %RGv by VM_FF_INHIBIT_INTERRUPTS!!\n", (RTGCPTR)pCtx->rip));
744 }
745
746#ifdef VBOX_STRICT
747 if (TRPMHasTrap(pVM))
748 {
749 uint8_t u8Vector;
750 rc = TRPMQueryTrapAll(pVM, &u8Vector, 0, 0, 0);
751 AssertRC(rc);
752 }
753#endif
754
755 if ( pCtx->eflags.u32 & X86_EFL_IF
756 && (!VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS))
757 && TRPMHasTrap(pVM)
758 )
759 {
760 uint8_t u8Vector;
761 int rc;
762 TRPMEVENT enmType;
763 RTGCUINTPTR intInfo;
764 RTGCUINT errCode;
765
766 /* If a new event is pending, then dispatch it now. */
767 rc = TRPMQueryTrapAll(pVM, &u8Vector, &enmType, &errCode, 0);
768 AssertRC(rc);
769 Assert(pCtx->eflags.Bits.u1IF == 1 || enmType == TRPM_TRAP);
770 Assert(enmType != TRPM_SOFTWARE_INT);
771
772 /* Clear the pending trap. */
773 rc = TRPMResetTrap(pVM);
774 AssertRC(rc);
775
776 intInfo = u8Vector;
777 intInfo |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
778
779 if (enmType == TRPM_TRAP)
780 {
781 switch (u8Vector) {
782 case 8:
783 case 10:
784 case 11:
785 case 12:
786 case 13:
787 case 14:
788 case 17:
789 /* Valid error codes. */
790 intInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
791 break;
792 default:
793 break;
794 }
795 if (u8Vector == X86_XCPT_BP || u8Vector == X86_XCPT_OF)
796 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SWEXCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
797 else
798 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HWEXCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
799 }
800 else
801 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
802
803 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatIntInject);
804 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, intInfo, 0, errCode);
805 AssertRC(rc);
806 } /* if (interrupts can be dispatched) */
807
808 return VINF_SUCCESS;
809}
810
811/**
812 * Save the host state
813 *
814 * @returns VBox status code.
815 * @param pVM The VM to operate on.
816 * @param pVCpu The VMCPU to operate on.
817 */
818VMMR0DECL(int) VMXR0SaveHostState(PVM pVM, PVMCPU pVCpu)
819{
820 int rc = VINF_SUCCESS;
821
822 /*
823 * Host CPU Context
824 */
825 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_HOST_CONTEXT)
826 {
827 RTIDTR idtr;
828 RTGDTR gdtr;
829 RTSEL SelTR;
830 PX86DESCHC pDesc;
831 uintptr_t trBase;
832 RTSEL cs;
833 RTSEL ss;
834 uint64_t cr3;
835
836 /* Control registers */
837 rc = VMXWriteVMCS(VMX_VMCS_HOST_CR0, ASMGetCR0());
838#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
839 if (VMX_IS_64BIT_HOST_MODE())
840 {
841 cr3 = hwaccmR0Get64bitCR3();
842 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_CR3, cr3);
843 }
844 else
845#endif
846 {
847 cr3 = ASMGetCR3();
848 rc |= VMXWriteVMCS(VMX_VMCS_HOST_CR3, cr3);
849 }
850 rc |= VMXWriteVMCS(VMX_VMCS_HOST_CR4, ASMGetCR4());
851 AssertRC(rc);
852 Log2(("VMX_VMCS_HOST_CR0 %08x\n", ASMGetCR0()));
853 Log2(("VMX_VMCS_HOST_CR3 %08RX64\n", cr3));
854 Log2(("VMX_VMCS_HOST_CR4 %08x\n", ASMGetCR4()));
855
856 /* Selector registers. */
857#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
858 if (VMX_IS_64BIT_HOST_MODE())
859 {
860 cs = (RTSEL)(uintptr_t)&SUPR0Abs64bitKernelCS;
861 ss = (RTSEL)(uintptr_t)&SUPR0Abs64bitKernelSS;
862 }
863 else
864 {
865 /* sysenter loads LDT cs & ss, VMX doesn't like this. Load the GDT ones (safe). */
866 cs = (RTSEL)(uintptr_t)&SUPR0AbsKernelCS;
867 ss = (RTSEL)(uintptr_t)&SUPR0AbsKernelSS;
868 }
869#else
870 cs = ASMGetCS();
871 ss = ASMGetSS();
872#endif
873 Assert(!(cs & X86_SEL_LDT)); Assert((cs & X86_SEL_RPL) == 0);
874 Assert(!(ss & X86_SEL_LDT)); Assert((ss & X86_SEL_RPL) == 0);
875 rc = VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_CS, cs);
876 /* Note: VMX is (again) very picky about the RPL of the selectors here; we'll restore them manually. */
877 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_DS, 0);
878 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_ES, 0);
879#if HC_ARCH_BITS == 32
880 if (!VMX_IS_64BIT_HOST_MODE())
881 {
882 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_FS, 0);
883 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_GS, 0);
884 }
885#endif
886 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_SS, ss);
887 SelTR = ASMGetTR();
888 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_TR, SelTR);
889 AssertRC(rc);
890 Log2(("VMX_VMCS_HOST_FIELD_CS %08x (%08x)\n", cs, ASMGetSS()));
891 Log2(("VMX_VMCS_HOST_FIELD_DS 00000000 (%08x)\n", ASMGetDS()));
892 Log2(("VMX_VMCS_HOST_FIELD_ES 00000000 (%08x)\n", ASMGetES()));
893 Log2(("VMX_VMCS_HOST_FIELD_FS 00000000 (%08x)\n", ASMGetFS()));
894 Log2(("VMX_VMCS_HOST_FIELD_GS 00000000 (%08x)\n", ASMGetGS()));
895 Log2(("VMX_VMCS_HOST_FIELD_SS %08x (%08x)\n", ss, ASMGetSS()));
896 Log2(("VMX_VMCS_HOST_FIELD_TR %08x\n", ASMGetTR()));
897
898 /* GDTR & IDTR */
899#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
900 if (VMX_IS_64BIT_HOST_MODE())
901 {
902 X86XDTR64 gdtr64, idtr64;
903 hwaccmR0Get64bitGDTRandIDTR(&gdtr64, &idtr64);
904 rc = VMXWriteVMCS64(VMX_VMCS_HOST_GDTR_BASE, gdtr64.uAddr);
905 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_IDTR_BASE, gdtr64.uAddr);
906 AssertRC(rc);
907 Log2(("VMX_VMCS_HOST_GDTR_BASE %RX64\n", gdtr64.uAddr));
908 Log2(("VMX_VMCS_HOST_IDTR_BASE %RX64\n", idtr64.uAddr));
909 gdtr.cbGdt = gdtr64.cb;
910 gdtr.pGdt = (uintptr_t)gdtr64.uAddr;
911 }
912 else
913#endif
914 {
915 ASMGetGDTR(&gdtr);
916 rc = VMXWriteVMCS(VMX_VMCS_HOST_GDTR_BASE, gdtr.pGdt);
917 ASMGetIDTR(&idtr);
918 rc |= VMXWriteVMCS(VMX_VMCS_HOST_IDTR_BASE, idtr.pIdt);
919 AssertRC(rc);
920 Log2(("VMX_VMCS_HOST_GDTR_BASE %RHv\n", gdtr.pGdt));
921 Log2(("VMX_VMCS_HOST_IDTR_BASE %RHv\n", idtr.pIdt));
922 }
923
924
925 /* Save the base address of the TR selector. */
926 if (SelTR > gdtr.cbGdt)
927 {
928 AssertMsgFailed(("Invalid TR selector %x. GDTR.cbGdt=%x\n", SelTR, gdtr.cbGdt));
929 return VERR_VMX_INVALID_HOST_STATE;
930 }
931
932#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
933 if (VMX_IS_64BIT_HOST_MODE())
934 {
935 pDesc = &((PX86DESCHC)gdtr.pGdt)[SelTR >> X86_SEL_SHIFT_HC]; /// ????
936 uint64_t trBase64 = X86DESC64_BASE(*(PX86DESC64)pDesc);
937 rc = VMXWriteVMCS64(VMX_VMCS_HOST_TR_BASE, trBase64);
938 Log2(("VMX_VMCS_HOST_TR_BASE %RX64\n", trBase64));
939 AssertRC(rc);
940 }
941 else
942#endif
943 {
944 pDesc = &((PX86DESCHC)gdtr.pGdt)[SelTR >> X86_SEL_SHIFT_HC];
945#if HC_ARCH_BITS == 64
946 trBase = X86DESC64_BASE(*pDesc);
947#else
948 trBase = X86DESC_BASE(*pDesc);
949#endif
950 rc = VMXWriteVMCS(VMX_VMCS_HOST_TR_BASE, trBase);
951 AssertRC(rc);
952 Log2(("VMX_VMCS_HOST_TR_BASE %RHv\n", trBase));
953 }
954
955 /* FS and GS base. */
956#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
957 if (VMX_IS_64BIT_HOST_MODE())
958 {
959 Log2(("MSR_K8_FS_BASE = %RX64\n", ASMRdMsr(MSR_K8_FS_BASE)));
960 Log2(("MSR_K8_GS_BASE = %RX64\n", ASMRdMsr(MSR_K8_GS_BASE)));
961 rc = VMXWriteVMCS64(VMX_VMCS_HOST_FS_BASE, ASMRdMsr(MSR_K8_FS_BASE));
962 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_GS_BASE, ASMRdMsr(MSR_K8_GS_BASE));
963 }
964#endif
965 AssertRC(rc);
966
967 /* Sysenter MSRs. */
968 /** @todo expensive!! */
969 rc = VMXWriteVMCS(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS));
970 Log2(("VMX_VMCS_HOST_SYSENTER_CS %08x\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)));
971#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
972 if (VMX_IS_64BIT_HOST_MODE())
973 {
974 Log2(("VMX_VMCS_HOST_SYSENTER_EIP %RX64\n", ASMRdMsr(MSR_IA32_SYSENTER_EIP)));
975 Log2(("VMX_VMCS_HOST_SYSENTER_ESP %RX64\n", ASMRdMsr(MSR_IA32_SYSENTER_ESP)));
976 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
977 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
978 }
979 else
980 {
981 rc |= VMXWriteVMCS(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
982 rc |= VMXWriteVMCS(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
983 Log2(("VMX_VMCS_HOST_SYSENTER_EIP %RX32\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP)));
984 Log2(("VMX_VMCS_HOST_SYSENTER_ESP %RX32\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP)));
985 }
986#elif HC_ARCH_BITS == 32
987 rc |= VMXWriteVMCS(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
988 rc |= VMXWriteVMCS(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
989 Log2(("VMX_VMCS_HOST_SYSENTER_EIP %RX32\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP)));
990 Log2(("VMX_VMCS_HOST_SYSENTER_ESP %RX32\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP)));
991#else
992 Log2(("VMX_VMCS_HOST_SYSENTER_EIP %RX64\n", ASMRdMsr(MSR_IA32_SYSENTER_EIP)));
993 Log2(("VMX_VMCS_HOST_SYSENTER_ESP %RX64\n", ASMRdMsr(MSR_IA32_SYSENTER_ESP)));
994 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
995 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
996#endif
997 AssertRC(rc);
998
999#if 0 /* @todo deal with 32/64 */
1000 /* Restore the host EFER - on CPUs that support it. */
1001 if (pVM->hwaccm.s.vmx.msr.vmx_exit.n.allowed1 & VMX_VMCS_CTRL_EXIT_CONTROLS_LOAD_HOST_EFER_MSR)
1002 {
1003 uint64_t msrEFER = ASMRdMsr(MSR_IA32_EFER);
1004 rc = VMXWriteVMCS64(VMX_VMCS_HOST_FIELD_EFER_FULL, msrEFER);
1005 AssertRC(rc);
1006 }
1007#endif
1008 pVCpu->hwaccm.s.fContextUseFlags &= ~HWACCM_CHANGED_HOST_CONTEXT;
1009 }
1010 return rc;
1011}
1012
1013/**
1014 * Prefetch the 4 PDPT pointers (PAE and nested paging only)
1015 *
1016 * @param pVM The VM to operate on.
1017 * @param pVCpu The VMCPU to operate on.
1018 * @param pCtx Guest context
1019 */
1020static void vmxR0PrefetchPAEPdptrs(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1021{
1022 if (CPUMIsGuestInPAEModeEx(pCtx))
1023 {
1024 X86PDPE Pdpe;
1025
1026 for (unsigned i=0;i<4;i++)
1027 {
1028 Pdpe = PGMGstGetPaePDPtr(pVM, i);
1029 int rc = VMXWriteVMCS64(VMX_VMCS_GUEST_PDPTR0_FULL + i*2, Pdpe.u);
1030 AssertRC(rc);
1031 }
1032 }
1033}
1034
1035/**
1036 * Update the exception bitmap according to the current CPU state
1037 *
1038 * @param pVM The VM to operate on.
1039 * @param pVCpu The VMCPU to operate on.
1040 * @param pCtx Guest context
1041 */
1042static void vmxR0UpdateExceptionBitmap(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1043{
1044 uint32_t u32TrapMask;
1045 Assert(pCtx);
1046
1047 u32TrapMask = HWACCM_VMX_TRAP_MASK;
1048#ifndef DEBUG
1049 if (pVM->hwaccm.s.fNestedPaging)
1050 u32TrapMask &= ~RT_BIT(X86_XCPT_PF); /* no longer need to intercept #PF. */
1051#endif
1052
1053 /* Also catch floating point exceptions as we need to report them to the guest in a different way. */
1054 if ( CPUMIsGuestFPUStateActive(pVCpu) == true
1055 && !(pCtx->cr0 & X86_CR0_NE)
1056 && !pVCpu->hwaccm.s.fFPUOldStyleOverride)
1057 {
1058 u32TrapMask |= RT_BIT(X86_XCPT_MF);
1059 pVCpu->hwaccm.s.fFPUOldStyleOverride = true;
1060 }
1061
1062#ifdef DEBUG
1063 /* Intercept X86_XCPT_DB if stepping is enabled */
1064 if (DBGFIsStepping(pVM))
1065 u32TrapMask |= RT_BIT(X86_XCPT_DB);
1066#endif
1067
1068#ifdef VBOX_STRICT
1069 Assert(u32TrapMask & RT_BIT(X86_XCPT_GP));
1070#endif
1071
1072# ifdef HWACCM_VMX_EMULATE_REALMODE
1073 /* Intercept all exceptions in real mode as none of them can be injected directly (#GP otherwise). */
1074 if (CPUMIsGuestInRealModeEx(pCtx) && pVM->hwaccm.s.vmx.pRealModeTSS)
1075 u32TrapMask |= HWACCM_VMX_TRAP_MASK_REALMODE;
1076# endif /* HWACCM_VMX_EMULATE_REALMODE */
1077
1078 int rc = VMXWriteVMCS(VMX_VMCS_CTRL_EXCEPTION_BITMAP, u32TrapMask);
1079 AssertRC(rc);
1080}
1081
1082/**
1083 * Loads the guest state
1084 *
1085 * NOTE: Don't do anything here that can cause a jump back to ring 3!!!!!
1086 *
1087 * @returns VBox status code.
1088 * @param pVM The VM to operate on.
1089 * @param pVCpu The VMCPU to operate on.
1090 * @param pCtx Guest context
1091 */
1092VMMR0DECL(int) VMXR0LoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1093{
1094 int rc = VINF_SUCCESS;
1095 RTGCUINTPTR val;
1096 X86EFLAGS eflags;
1097
1098 /* VMX_VMCS_CTRL_ENTRY_CONTROLS
1099 * Set required bits to one and zero according to the MSR capabilities.
1100 */
1101 val = pVM->hwaccm.s.vmx.msr.vmx_entry.n.disallowed0;
1102 /* Load guest debug controls (dr7 & IA32_DEBUGCTL_MSR) (forced to 1 on the 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */
1103 val |= VMX_VMCS_CTRL_ENTRY_CONTROLS_LOAD_DEBUG;
1104#if 0 /* @todo deal with 32/64 */
1105 /* Required for the EFER write below, not supported on all CPUs. */
1106 val |= VMX_VMCS_CTRL_ENTRY_CONTROLS_LOAD_GUEST_EFER_MSR;
1107#endif
1108 /* 64 bits guest mode? */
1109 if (pCtx->msrEFER & MSR_K6_EFER_LMA)
1110 val |= VMX_VMCS_CTRL_ENTRY_CONTROLS_IA64_MODE;
1111 /* else Must be zero when AMD64 is not available. */
1112
1113 /* Mask away the bits that the CPU doesn't support */
1114 val &= pVM->hwaccm.s.vmx.msr.vmx_entry.n.allowed1;
1115 rc = VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_CONTROLS, val);
1116 AssertRC(rc);
1117
1118 /* VMX_VMCS_CTRL_EXIT_CONTROLS
1119 * Set required bits to one and zero according to the MSR capabilities.
1120 */
1121 val = pVM->hwaccm.s.vmx.msr.vmx_exit.n.disallowed0;
1122
1123 /* Save debug controls (dr7 & IA32_DEBUGCTL_MSR) (forced to 1 on the 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */
1124#if 0 /* @todo deal with 32/64 */
1125 val |= VMX_VMCS_CTRL_EXIT_CONTROLS_SAVE_DEBUG | VMX_VMCS_CTRL_EXIT_CONTROLS_LOAD_HOST_EFER_MSR;
1126#else
1127 val |= VMX_VMCS_CTRL_EXIT_CONTROLS_SAVE_DEBUG;
1128#endif
1129
1130#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
1131 if (VMX_IS_64BIT_HOST_MODE())
1132 val |= VMX_VMCS_CTRL_EXIT_CONTROLS_HOST_AMD64;
1133 /* else: Must be zero when AMD64 is not available. */
1134#elif HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
1135 if (pCtx->msrEFER & MSR_K6_EFER_LMA)
1136 val |= VMX_VMCS_CTRL_EXIT_CONTROLS_HOST_AMD64; /* our switcher goes to long mode */
1137 else
1138 Assert(!(val & VMX_VMCS_CTRL_EXIT_CONTROLS_HOST_AMD64));
1139#endif
1140 val &= pVM->hwaccm.s.vmx.msr.vmx_exit.n.allowed1;
1141 /* Don't acknowledge external interrupts on VM-exit. */
1142 rc = VMXWriteVMCS(VMX_VMCS_CTRL_EXIT_CONTROLS, val);
1143 AssertRC(rc);
1144
1145 /* Guest CPU context: ES, CS, SS, DS, FS, GS. */
1146 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_SEGMENT_REGS)
1147 {
1148#ifdef HWACCM_VMX_EMULATE_REALMODE
1149 if (pVM->hwaccm.s.vmx.pRealModeTSS)
1150 {
1151 PGMMODE enmGuestMode = PGMGetGuestMode(pVM);
1152 if (pVCpu->hwaccm.s.vmx.enmLastSeenGuestMode != enmGuestMode)
1153 {
1154 /* Correct weird requirements for switching to protected mode. */
1155 if ( pVCpu->hwaccm.s.vmx.enmLastSeenGuestMode == PGMMODE_REAL
1156 && enmGuestMode >= PGMMODE_PROTECTED)
1157 {
1158 /* DPL of all hidden selector registers must match the current CPL (0). */
1159 pCtx->csHid.Attr.n.u2Dpl = 0;
1160 pCtx->csHid.Attr.n.u4Type = X86_SEL_TYPE_CODE | X86_SEL_TYPE_RW_ACC;
1161
1162 pCtx->dsHid.Attr.n.u2Dpl = 0;
1163 pCtx->esHid.Attr.n.u2Dpl = 0;
1164 pCtx->fsHid.Attr.n.u2Dpl = 0;
1165 pCtx->gsHid.Attr.n.u2Dpl = 0;
1166 pCtx->ssHid.Attr.n.u2Dpl = 0;
1167 }
1168 else
1169 /* Switching from protected mode to real mode. */
1170 if ( pVCpu->hwaccm.s.vmx.enmLastSeenGuestMode >= PGMMODE_PROTECTED
1171 && enmGuestMode == PGMMODE_REAL)
1172 {
1173 /* The limit must also be adjusted. */
1174 pCtx->csHid.u32Limit &= 0xffff;
1175 pCtx->dsHid.u32Limit &= 0xffff;
1176 pCtx->esHid.u32Limit &= 0xffff;
1177 pCtx->fsHid.u32Limit &= 0xffff;
1178 pCtx->gsHid.u32Limit &= 0xffff;
1179 pCtx->ssHid.u32Limit &= 0xffff;
1180
1181 Assert(pCtx->csHid.u64Base <= 0xfffff);
1182 Assert(pCtx->dsHid.u64Base <= 0xfffff);
1183 Assert(pCtx->esHid.u64Base <= 0xfffff);
1184 Assert(pCtx->fsHid.u64Base <= 0xfffff);
1185 Assert(pCtx->gsHid.u64Base <= 0xfffff);
1186 }
1187 pVCpu->hwaccm.s.vmx.enmLastSeenGuestMode = enmGuestMode;
1188 }
1189 else
1190 /* VT-x will fail with a guest invalid state otherwise... (CPU state after a reset) */
1191 if ( CPUMIsGuestInRealModeEx(pCtx)
1192 && pCtx->csHid.u64Base == 0xffff0000)
1193 {
1194 pCtx->csHid.u64Base = 0xf0000;
1195 pCtx->cs = 0xf000;
1196 }
1197 }
1198#endif /* HWACCM_VMX_EMULATE_REALMODE */
1199
1200 VMX_WRITE_SELREG(ES, es);
1201 AssertRC(rc);
1202
1203 VMX_WRITE_SELREG(CS, cs);
1204 AssertRC(rc);
1205
1206 VMX_WRITE_SELREG(SS, ss);
1207 AssertRC(rc);
1208
1209 VMX_WRITE_SELREG(DS, ds);
1210 AssertRC(rc);
1211
1212 /* The base values in the hidden fs & gs registers are not in sync with the msrs; they are cut to 32 bits. */
1213 VMX_WRITE_SELREG(FS, fs);
1214 AssertRC(rc);
1215
1216 VMX_WRITE_SELREG(GS, gs);
1217 AssertRC(rc);
1218 }
1219
1220 /* Guest CPU context: LDTR. */
1221 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_LDTR)
1222 {
1223 if (pCtx->ldtr == 0)
1224 {
1225 rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_LDTR, 0);
1226 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_LDTR_LIMIT, 0);
1227 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_LDTR_BASE, 0);
1228 /* Note: vmlaunch will fail with 0 or just 0x02. No idea why. */
1229 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, 0x82 /* present, LDT */);
1230 }
1231 else
1232 {
1233 rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_LDTR, pCtx->ldtr);
1234 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtrHid.u32Limit);
1235 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_LDTR_BASE, pCtx->ldtrHid.u64Base);
1236 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, pCtx->ldtrHid.Attr.u);
1237 }
1238 AssertRC(rc);
1239 }
1240 /* Guest CPU context: TR. */
1241 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_TR)
1242 {
1243#ifdef HWACCM_VMX_EMULATE_REALMODE
1244 /* Real mode emulation using v86 mode with CR4.VME (interrupt redirection using the int bitmap in the TSS) */
1245 if (CPUMIsGuestInRealModeEx(pCtx))
1246 {
1247 RTGCPHYS GCPhys;
1248
1249 /* We convert it here every time as pci regions could be reconfigured. */
1250 rc = PDMVMMDevHeapR3ToGCPhys(pVM, pVM->hwaccm.s.vmx.pRealModeTSS, &GCPhys);
1251 AssertRC(rc);
1252
1253 rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_TR, 0);
1254 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_TR_LIMIT, HWACCM_VTX_TSS_SIZE);
1255 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_TR_BASE, GCPhys /* phys = virt in this mode */);
1256
1257 X86DESCATTR attr;
1258
1259 attr.u = 0;
1260 attr.n.u1Present = 1;
1261 attr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
1262 val = attr.u;
1263 }
1264 else
1265#endif /* HWACCM_VMX_EMULATE_REALMODE */
1266 {
1267 rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_TR, pCtx->tr);
1268 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_TR_LIMIT, pCtx->trHid.u32Limit);
1269 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_TR_BASE, pCtx->trHid.u64Base);
1270
1271 val = pCtx->trHid.Attr.u;
1272
1273 /* The TSS selector must be busy. */
1274 if ((val & 0xF) == X86_SEL_TYPE_SYS_286_TSS_AVAIL)
1275 val = (val & ~0xF) | X86_SEL_TYPE_SYS_286_TSS_BUSY;
1276 else
1277 /* Default even if no TR selector has been set (otherwise vmlaunch will fail!) */
1278 val = (val & ~0xF) | X86_SEL_TYPE_SYS_386_TSS_BUSY;
1279
1280 }
1281 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, val);
1282 AssertRC(rc);
1283 }
1284 /* Guest CPU context: GDTR. */
1285 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_GDTR)
1286 {
1287 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt);
1288 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_GDTR_BASE, pCtx->gdtr.pGdt);
1289 AssertRC(rc);
1290 }
1291 /* Guest CPU context: IDTR. */
1292 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_IDTR)
1293 {
1294 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt);
1295 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_IDTR_BASE, pCtx->idtr.pIdt);
1296 AssertRC(rc);
1297 }
1298
1299 /*
1300 * Sysenter MSRs (unconditional)
1301 */
1302 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
1303 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
1304 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
1305 AssertRC(rc);
1306
1307 /* Control registers */
1308 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR0)
1309 {
1310 val = pCtx->cr0;
1311 rc = VMXWriteVMCS(VMX_VMCS_CTRL_CR0_READ_SHADOW, val);
1312 Log2(("Guest CR0-shadow %08x\n", val));
1313 if (CPUMIsGuestFPUStateActive(pVCpu) == false)
1314 {
1315 /* Always use #NM exceptions to load the FPU/XMM state on demand. */
1316 val |= X86_CR0_TS | X86_CR0_ET | X86_CR0_NE | X86_CR0_MP;
1317 }
1318 else
1319 {
1320 /** @todo check if we support the old style mess correctly. */
1321 if (!(val & X86_CR0_NE))
1322 Log(("Forcing X86_CR0_NE!!!\n"));
1323
1324 val |= X86_CR0_NE; /* always turn on the native mechanism to report FPU errors (old style uses interrupts) */
1325 }
1326 /* Note: protected mode & paging are always enabled; we use them for emulating real and protected mode without paging too. */
1327 val |= X86_CR0_PE | X86_CR0_PG;
1328 if (pVM->hwaccm.s.fNestedPaging)
1329 {
1330 if (CPUMIsGuestInPagedProtectedModeEx(pCtx))
1331 {
1332 /* Disable cr3 read/write monitoring as we don't need it for EPT. */
1333 pVCpu->hwaccm.s.vmx.proc_ctls &= ~( VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_LOAD_EXIT
1334 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_STORE_EXIT);
1335 }
1336 else
1337 {
1338 /* Reenable cr3 read/write monitoring as our identity mapped page table is active. */
1339 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_LOAD_EXIT
1340 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_STORE_EXIT;
1341 }
1342 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
1343 AssertRC(rc);
1344 }
1345 else
1346 {
1347 /* Note: We must also set this as we rely on protecting various pages for which supervisor writes must be caught. */
1348 val |= X86_CR0_WP;
1349 }
1350
1351 /* Always enable caching. */
1352 val &= ~(X86_CR0_CD|X86_CR0_NW);
1353
1354 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_CR0, val);
1355 Log2(("Guest CR0 %08x\n", val));
1356 /* CR0 flags owned by the host; if the guests attempts to change them, then
1357 * the VM will exit.
1358 */
1359 val = X86_CR0_PE /* Must monitor this bit (assumptions are made for real mode emulation) */
1360 | X86_CR0_WP /* Must monitor this bit (it must always be enabled). */
1361 | X86_CR0_PG /* Must monitor this bit (assumptions are made for real mode & protected mode without paging emulation) */
1362 | X86_CR0_TS
1363 | X86_CR0_ET /* Bit not restored during VM-exit! */
1364 | X86_CR0_CD /* Bit not restored during VM-exit! */
1365 | X86_CR0_NW /* Bit not restored during VM-exit! */
1366 | X86_CR0_NE
1367 | X86_CR0_MP;
1368 pVCpu->hwaccm.s.vmx.cr0_mask = val;
1369
1370 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_CR0_MASK, val);
1371 Log2(("Guest CR0-mask %08x\n", val));
1372 AssertRC(rc);
1373 }
1374 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR4)
1375 {
1376 /* CR4 */
1377 rc = VMXWriteVMCS(VMX_VMCS_CTRL_CR4_READ_SHADOW, pCtx->cr4);
1378 Log2(("Guest CR4-shadow %08x\n", pCtx->cr4));
1379 /* Set the required bits in cr4 too (currently X86_CR4_VMXE). */
1380 val = pCtx->cr4 | (uint32_t)pVM->hwaccm.s.vmx.msr.vmx_cr4_fixed0;
1381
1382 if (!pVM->hwaccm.s.fNestedPaging)
1383 {
1384 switch(pVCpu->hwaccm.s.enmShadowMode)
1385 {
1386 case PGMMODE_REAL: /* Real mode -> emulated using v86 mode */
1387 case PGMMODE_PROTECTED: /* Protected mode, no paging -> emulated using identity mapping. */
1388 case PGMMODE_32_BIT: /* 32-bit paging. */
1389 val &= ~X86_CR4_PAE;
1390 break;
1391
1392 case PGMMODE_PAE: /* PAE paging. */
1393 case PGMMODE_PAE_NX: /* PAE paging with NX enabled. */
1394 /** @todo use normal 32 bits paging */
1395 val |= X86_CR4_PAE;
1396 break;
1397
1398 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
1399 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
1400#ifdef VBOX_ENABLE_64_BITS_GUESTS
1401 break;
1402#else
1403 AssertFailed();
1404 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1405#endif
1406 default: /* shut up gcc */
1407 AssertFailed();
1408 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1409 }
1410 }
1411 else
1412 if (!CPUMIsGuestInPagedProtectedModeEx(pCtx))
1413 {
1414 /* We use 4 MB pages in our identity mapping page table for real and protected mode without paging. */
1415 val |= X86_CR4_PSE;
1416 /* Our identity mapping is a 32 bits page directory. */
1417 val &= ~X86_CR4_PAE;
1418 }
1419
1420#ifdef HWACCM_VMX_EMULATE_REALMODE
1421 /* Real mode emulation using v86 mode with CR4.VME (interrupt redirection using the int bitmap in the TSS) */
1422 if (CPUMIsGuestInRealModeEx(pCtx))
1423 val |= X86_CR4_VME;
1424#endif /* HWACCM_VMX_EMULATE_REALMODE */
1425
1426 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_CR4, val);
1427 Log2(("Guest CR4 %08x\n", val));
1428 /* CR4 flags owned by the host; if the guests attempts to change them, then
1429 * the VM will exit.
1430 */
1431 val = 0
1432#ifdef HWACCM_VMX_EMULATE_REALMODE
1433 | (pVM->hwaccm.s.vmx.pRealModeTSS ? X86_CR4_VME : 0)
1434#endif
1435 | X86_CR4_PAE
1436 | X86_CR4_PGE
1437 | X86_CR4_PSE
1438 | X86_CR4_VMXE;
1439 pVCpu->hwaccm.s.vmx.cr4_mask = val;
1440
1441 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_CR4_MASK, val);
1442 Log2(("Guest CR4-mask %08x\n", val));
1443 AssertRC(rc);
1444 }
1445
1446 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR3)
1447 {
1448 if (pVM->hwaccm.s.fNestedPaging)
1449 {
1450 AssertMsg( PGMGetEPTCR3(pVM) == PGMGetHyperCR3(pVM)
1451 || VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL),
1452 ("%RHp vs %RHp\n", PGMGetEPTCR3(pVM), PGMGetHyperCR3(pVM)));
1453 pVCpu->hwaccm.s.vmx.GCPhysEPTP = PGMGetEPTCR3(pVM);
1454
1455 Assert(!(pVCpu->hwaccm.s.vmx.GCPhysEPTP & 0xfff));
1456 /** @todo Check the IA32_VMX_EPT_VPID_CAP MSR for other supported memory types. */
1457 pVCpu->hwaccm.s.vmx.GCPhysEPTP |= VMX_EPT_MEMTYPE_WB
1458 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
1459
1460 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_EPTP_FULL, pVCpu->hwaccm.s.vmx.GCPhysEPTP);
1461 AssertRC(rc);
1462
1463 if (!CPUMIsGuestInPagedProtectedModeEx(pCtx))
1464 {
1465 RTGCPHYS GCPhys;
1466
1467 /* We convert it here every time as pci regions could be reconfigured. */
1468 rc = PDMVMMDevHeapR3ToGCPhys(pVM, pVM->hwaccm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
1469 AssertRC(rc);
1470
1471 /* We use our identity mapping page table here as we need to map guest virtual to guest physical addresses; EPT will
1472 * take care of the translation to host physical addresses.
1473 */
1474 val = GCPhys;
1475 }
1476 else
1477 {
1478 /* Save the real guest CR3 in VMX_VMCS_GUEST_CR3 */
1479 val = pCtx->cr3;
1480 /* Prefetch the four PDPT entries in PAE mode. */
1481 vmxR0PrefetchPAEPdptrs(pVM, pVCpu, pCtx);
1482 }
1483 }
1484 else
1485 {
1486 val = PGMGetHyperCR3(pVM);
1487 Assert(val || VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL));
1488 }
1489
1490 /* Save our shadow CR3 register. */
1491 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_CR3, val);
1492 AssertRC(rc);
1493 }
1494
1495 /* Debug registers. */
1496 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_DEBUG)
1497 {
1498 pCtx->dr[6] |= X86_DR6_INIT_VAL; /* set all reserved bits to 1. */
1499 pCtx->dr[6] &= ~RT_BIT(12); /* must be zero. */
1500
1501 pCtx->dr[7] &= 0xffffffff; /* upper 32 bits reserved */
1502 pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
1503 pCtx->dr[7] |= 0x400; /* must be one */
1504
1505 /* Resync DR7 */
1506 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_DR7, pCtx->dr[7]);
1507 AssertRC(rc);
1508
1509 /* Sync the debug state now if any breakpoint is armed. */
1510 if ( (pCtx->dr[7] & (X86_DR7_ENABLED_MASK|X86_DR7_GD))
1511 && !CPUMIsGuestDebugStateActive(pVM)
1512 && !DBGFIsStepping(pVM))
1513 {
1514 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxArmed);
1515
1516 /* Disable drx move intercepts. */
1517 pVCpu->hwaccm.s.vmx.proc_ctls &= ~VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT;
1518 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
1519 AssertRC(rc);
1520
1521 /* Save the host and load the guest debug state. */
1522 rc = CPUMR0LoadGuestDebugState(pVM, pVCpu, pCtx, true /* include DR6 */);
1523 AssertRC(rc);
1524 }
1525
1526 /* IA32_DEBUGCTL MSR. */
1527 rc = VMXWriteVMCS64(VMX_VMCS_GUEST_DEBUGCTL_FULL, 0);
1528 AssertRC(rc);
1529
1530 /** @todo do we really ever need this? */
1531 rc |= VMXWriteVMCS(VMX_VMCS_GUEST_DEBUG_EXCEPTIONS, 0);
1532 AssertRC(rc);
1533 }
1534
1535 /* EIP, ESP and EFLAGS */
1536 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_RIP, pCtx->rip);
1537 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_RSP, pCtx->rsp);
1538 AssertRC(rc);
1539
1540 /* Bits 22-31, 15, 5 & 3 must be zero. Bit 1 must be 1. */
1541 eflags = pCtx->eflags;
1542 eflags.u32 &= VMX_EFLAGS_RESERVED_0;
1543 eflags.u32 |= VMX_EFLAGS_RESERVED_1;
1544
1545#ifdef HWACCM_VMX_EMULATE_REALMODE
1546 /* Real mode emulation using v86 mode with CR4.VME (interrupt redirection using the int bitmap in the TSS) */
1547 if (CPUMIsGuestInRealModeEx(pCtx))
1548 {
1549 pVCpu->hwaccm.s.vmx.RealMode.eflags = eflags;
1550
1551 eflags.Bits.u1VM = 1;
1552 eflags.Bits.u2IOPL = 3;
1553 }
1554#endif /* HWACCM_VMX_EMULATE_REALMODE */
1555 rc = VMXWriteVMCS(VMX_VMCS_GUEST_RFLAGS, eflags.u32);
1556 AssertRC(rc);
1557
1558 /* TSC offset. */
1559 uint64_t u64TSCOffset;
1560
1561 if (TMCpuTickCanUseRealTSC(pVM, &u64TSCOffset))
1562 {
1563 /* Note: VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDTSC_EXIT takes precedence over TSC_OFFSET */
1564 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_TSC_OFFSET_FULL, u64TSCOffset);
1565 AssertRC(rc);
1566
1567 pVCpu->hwaccm.s.vmx.proc_ctls &= ~VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDTSC_EXIT;
1568 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
1569 AssertRC(rc);
1570 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTSCOffset);
1571 }
1572 else
1573 {
1574 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDTSC_EXIT;
1575 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
1576 AssertRC(rc);
1577 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTSCIntercept);
1578 }
1579
1580 /* 64 bits guest mode? */
1581 if (pCtx->msrEFER & MSR_K6_EFER_LMA)
1582 {
1583#if !defined(VBOX_ENABLE_64_BITS_GUESTS)
1584 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1585#elif HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
1586 pVCpu->hwaccm.s.vmx.pfnStartVM = VMXR0SwitcherStartVM64;
1587#else
1588# ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
1589 if (!pVM->hwaccm.s.fAllow64BitGuests)
1590 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1591# endif
1592 pVCpu->hwaccm.s.vmx.pfnStartVM = VMXR0StartVM64;
1593#endif
1594 /* Unconditionally update these as wrmsr might have changed them. */
1595 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_FS_BASE, pCtx->fsHid.u64Base);
1596 AssertRC(rc);
1597 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_GS_BASE, pCtx->gsHid.u64Base);
1598 AssertRC(rc);
1599 }
1600 else
1601 {
1602 pVCpu->hwaccm.s.vmx.pfnStartVM = VMXR0StartVM32;
1603 }
1604
1605#if 0 /* @todo deal with 32/64 */
1606 /* Unconditionally update the guest EFER - on CPUs that supports it. */
1607 if (pVM->hwaccm.s.vmx.msr.vmx_entry.n.allowed1 & VMX_VMCS_CTRL_ENTRY_CONTROLS_LOAD_GUEST_EFER_MSR)
1608 {
1609 rc = VMXWriteVMCS64(VMX_VMCS_GUEST_EFER_FULL, pCtx->msrEFER);
1610 AssertRC(rc);
1611 }
1612#endif
1613
1614 vmxR0UpdateExceptionBitmap(pVM, pVCpu, pCtx);
1615
1616 /* Done. */
1617 pVCpu->hwaccm.s.fContextUseFlags &= ~HWACCM_CHANGED_ALL_GUEST;
1618
1619 return rc;
1620}
1621
1622/**
1623 * Syncs back the guest state
1624 *
1625 * @returns VBox status code.
1626 * @param pVM The VM to operate on.
1627 * @param pVCpu The VMCPU to operate on.
1628 * @param pCtx Guest context
1629 */
1630DECLINLINE(int) VMXR0SaveGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1631{
1632 RTGCUINTREG val, valShadow;
1633 RTGCUINTPTR uInterruptState;
1634 int rc;
1635
1636 /* Let's first sync back eip, esp, and eflags. */
1637 rc = VMXReadCachedVMCS(VMX_VMCS64_GUEST_RIP, &val);
1638 AssertRC(rc);
1639 pCtx->rip = val;
1640 rc = VMXReadCachedVMCS(VMX_VMCS64_GUEST_RSP, &val);
1641 AssertRC(rc);
1642 pCtx->rsp = val;
1643 rc = VMXReadCachedVMCS(VMX_VMCS_GUEST_RFLAGS, &val);
1644 AssertRC(rc);
1645 pCtx->eflags.u32 = val;
1646
1647 /* Take care of instruction fusing (sti, mov ss) */
1648 rc |= VMXReadCachedVMCS(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &val);
1649 uInterruptState = val;
1650 if (uInterruptState != 0)
1651 {
1652 Assert(uInterruptState <= 2); /* only sti & mov ss */
1653 Log(("uInterruptState %x eip=%RGv\n", uInterruptState, pCtx->rip));
1654 EMSetInhibitInterruptsPC(pVM, pCtx->rip);
1655 }
1656 else
1657 VM_FF_CLEAR(pVM, VM_FF_INHIBIT_INTERRUPTS);
1658
1659 /* Control registers. */
1660 VMXReadCachedVMCS(VMX_VMCS_CTRL_CR0_READ_SHADOW, &valShadow);
1661 VMXReadCachedVMCS(VMX_VMCS64_GUEST_CR0, &val);
1662 val = (valShadow & pVCpu->hwaccm.s.vmx.cr0_mask) | (val & ~pVCpu->hwaccm.s.vmx.cr0_mask);
1663 CPUMSetGuestCR0(pVM, val);
1664
1665 VMXReadCachedVMCS(VMX_VMCS_CTRL_CR4_READ_SHADOW, &valShadow);
1666 VMXReadCachedVMCS(VMX_VMCS64_GUEST_CR4, &val);
1667 val = (valShadow & pVCpu->hwaccm.s.vmx.cr4_mask) | (val & ~pVCpu->hwaccm.s.vmx.cr4_mask);
1668 CPUMSetGuestCR4(pVM, val);
1669
1670 /* Note: no reason to sync back the CRx registers. They can't be changed by the guest. */
1671 /* Note: only in the nested paging case can CR3 & CR4 be changed by the guest. */
1672 if ( pVM->hwaccm.s.fNestedPaging
1673 && CPUMIsGuestInPagedProtectedModeEx(pCtx))
1674 {
1675 PVMCSCACHE pCache = &pVCpu->hwaccm.s.vmx.VMCSCache;
1676
1677 /* Can be updated behind our back in the nested paging case. */
1678 CPUMSetGuestCR2(pVM, pCache->cr2);
1679
1680 VMXReadCachedVMCS(VMX_VMCS64_GUEST_CR3, &val);
1681
1682 if (val != pCtx->cr3)
1683 {
1684 CPUMSetGuestCR3(pVM, val);
1685 PGMUpdateCR3(pVM, val);
1686 }
1687 /* Prefetch the four PDPT entries in PAE mode. */
1688 vmxR0PrefetchPAEPdptrs(pVM, pVCpu, pCtx);
1689 }
1690
1691 /* Sync back DR7 here. */
1692 VMXReadCachedVMCS(VMX_VMCS64_GUEST_DR7, &val);
1693 pCtx->dr[7] = val;
1694
1695 /* Guest CPU context: ES, CS, SS, DS, FS, GS. */
1696 VMX_READ_SELREG(ES, es);
1697 VMX_READ_SELREG(SS, ss);
1698 VMX_READ_SELREG(CS, cs);
1699 VMX_READ_SELREG(DS, ds);
1700 VMX_READ_SELREG(FS, fs);
1701 VMX_READ_SELREG(GS, gs);
1702
1703 /*
1704 * System MSRs
1705 */
1706 VMXReadCachedVMCS(VMX_VMCS32_GUEST_SYSENTER_CS, &val);
1707 pCtx->SysEnter.cs = val;
1708 VMXReadCachedVMCS(VMX_VMCS64_GUEST_SYSENTER_EIP, &val);
1709 pCtx->SysEnter.eip = val;
1710 VMXReadCachedVMCS(VMX_VMCS64_GUEST_SYSENTER_ESP, &val);
1711 pCtx->SysEnter.esp = val;
1712
1713 /* Misc. registers; must sync everything otherwise we can get out of sync when jumping to ring 3. */
1714 VMX_READ_SELREG(LDTR, ldtr);
1715
1716 VMXReadCachedVMCS(VMX_VMCS32_GUEST_GDTR_LIMIT, &val);
1717 pCtx->gdtr.cbGdt = val;
1718 VMXReadCachedVMCS(VMX_VMCS64_GUEST_GDTR_BASE, &val);
1719 pCtx->gdtr.pGdt = val;
1720
1721 VMXReadCachedVMCS(VMX_VMCS32_GUEST_IDTR_LIMIT, &val);
1722 pCtx->idtr.cbIdt = val;
1723 VMXReadCachedVMCS(VMX_VMCS64_GUEST_IDTR_BASE, &val);
1724 pCtx->idtr.pIdt = val;
1725
1726#ifdef HWACCM_VMX_EMULATE_REALMODE
1727 /* Real mode emulation using v86 mode with CR4.VME (interrupt redirection using the int bitmap in the TSS) */
1728 if (CPUMIsGuestInRealModeEx(pCtx))
1729 {
1730 /* Hide our emulation flags */
1731 pCtx->eflags.Bits.u1VM = 0;
1732 pCtx->eflags.Bits.u2IOPL = pVCpu->hwaccm.s.vmx.RealMode.eflags.Bits.u2IOPL;
1733
1734 /* Force a TR resync every time in case we switch modes. */
1735 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_TR;
1736 }
1737 else
1738#endif /* HWACCM_VMX_EMULATE_REALMODE */
1739 {
1740 /* In real mode we have a fake TSS, so only sync it back when it's supposed to be valid. */
1741 VMX_READ_SELREG(TR, tr);
1742 }
1743 return VINF_SUCCESS;
1744}
1745
1746/**
1747 * Dummy placeholder
1748 *
1749 * @param pVM The VM to operate on.
1750 * @param pVCpu The VMCPU to operate on.
1751 */
1752static void vmxR0SetupTLBDummy(PVM pVM, PVMCPU pVCpu)
1753{
1754 NOREF(pVM);
1755 NOREF(pVCpu);
1756 return;
1757}
1758
1759/**
1760 * Setup the tagged TLB for EPT
1761 *
1762 * @returns VBox status code.
1763 * @param pVM The VM to operate on.
1764 * @param pVCpu The VMCPU to operate on.
1765 */
1766static void vmxR0SetupTLBEPT(PVM pVM, PVMCPU pVCpu)
1767{
1768 PHWACCM_CPUINFO pCpu;
1769
1770 Assert(pVM->hwaccm.s.fNestedPaging);
1771 Assert(!pVM->hwaccm.s.vmx.fVPID);
1772
1773 /* Deal with tagged TLBs if VPID or EPT is supported. */
1774 pCpu = HWACCMR0GetCurrentCpu();
1775 /* Force a TLB flush for the first world switch if the current cpu differs from the one we ran on last. */
1776 /* Note that this can happen both for start and resume due to long jumps back to ring 3. */
1777 if ( pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu
1778 /* if the tlb flush count has changed, another VM has flushed the TLB of this cpu, so we can't use our current ASID anymore. */
1779 || pVCpu->hwaccm.s.cTLBFlushes != pCpu->cTLBFlushes)
1780 {
1781 /* Force a TLB flush on VM entry. */
1782 pVCpu->hwaccm.s.fForceTLBFlush = true;
1783 }
1784 else
1785 Assert(!pCpu->fFlushTLB);
1786
1787 pVCpu->hwaccm.s.idLastCpu = pCpu->idCpu;
1788 pCpu->fFlushTLB = false;
1789
1790 if (pVCpu->hwaccm.s.fForceTLBFlush)
1791 vmxR0FlushEPT(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushContext, 0);
1792
1793#ifdef VBOX_WITH_STATISTICS
1794 if (pVCpu->hwaccm.s.fForceTLBFlush)
1795 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushTLBWorldSwitch);
1796 else
1797 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatNoFlushTLBWorldSwitch);
1798#endif
1799}
1800
1801#ifdef HWACCM_VTX_WITH_VPID
1802/**
1803 * Setup the tagged TLB for VPID
1804 *
1805 * @returns VBox status code.
1806 * @param pVM The VM to operate on.
1807 * @param pVCpu The VMCPU to operate on.
1808 */
1809static void vmxR0SetupTLBVPID(PVM pVM, PVMCPU pVCpu)
1810{
1811 PHWACCM_CPUINFO pCpu;
1812
1813 Assert(pVM->hwaccm.s.vmx.fVPID);
1814 Assert(!pVM->hwaccm.s.fNestedPaging);
1815
1816 /* Deal with tagged TLBs if VPID or EPT is supported. */
1817 pCpu = HWACCMR0GetCurrentCpu();
1818 /* Force a TLB flush for the first world switch if the current cpu differs from the one we ran on last. */
1819 /* Note that this can happen both for start and resume due to long jumps back to ring 3. */
1820 if ( pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu
1821 /* if the tlb flush count has changed, another VM has flushed the TLB of this cpu, so we can't use our current ASID anymore. */
1822 || pVCpu->hwaccm.s.cTLBFlushes != pCpu->cTLBFlushes)
1823 {
1824 /* Force a TLB flush on VM entry. */
1825 pVCpu->hwaccm.s.fForceTLBFlush = true;
1826 }
1827 else
1828 Assert(!pCpu->fFlushTLB);
1829
1830 pVCpu->hwaccm.s.idLastCpu = pCpu->idCpu;
1831
1832 /* Make sure we flush the TLB when required. Switch ASID to achieve the same thing, but without actually flushing the whole TLB (which is expensive). */
1833 if (pVCpu->hwaccm.s.fForceTLBFlush)
1834 {
1835 if ( ++pCpu->uCurrentASID >= pVM->hwaccm.s.uMaxASID
1836 || pCpu->fFlushTLB)
1837 {
1838 pCpu->fFlushTLB = false;
1839 pCpu->uCurrentASID = 1; /* start at 1; host uses 0 */
1840 pCpu->cTLBFlushes++;
1841 }
1842 else
1843 {
1844 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushASID);
1845 pVCpu->hwaccm.s.fForceTLBFlush = false;
1846 }
1847
1848 pVCpu->hwaccm.s.cTLBFlushes = pCpu->cTLBFlushes;
1849 pVCpu->hwaccm.s.uCurrentASID = pCpu->uCurrentASID;
1850 }
1851 else
1852 {
1853 Assert(!pCpu->fFlushTLB);
1854
1855 if (!pCpu->uCurrentASID || !pVCpu->hwaccm.s.uCurrentASID)
1856 pVCpu->hwaccm.s.uCurrentASID = pCpu->uCurrentASID = 1;
1857 }
1858 AssertMsg(pVCpu->hwaccm.s.cTLBFlushes == pCpu->cTLBFlushes, ("Flush count mismatch for cpu %d (%x vs %x)\n", pCpu->idCpu, pVCpu->hwaccm.s.cTLBFlushes, pCpu->cTLBFlushes));
1859 AssertMsg(pCpu->uCurrentASID >= 1 && pCpu->uCurrentASID < pVM->hwaccm.s.uMaxASID, ("cpu%d uCurrentASID = %x\n", pCpu->idCpu, pCpu->uCurrentASID));
1860 AssertMsg(pVCpu->hwaccm.s.uCurrentASID >= 1 && pVCpu->hwaccm.s.uCurrentASID < pVM->hwaccm.s.uMaxASID, ("cpu%d VM uCurrentASID = %x\n", pCpu->idCpu, pVCpu->hwaccm.s.uCurrentASID));
1861
1862 int rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_VPID, pVCpu->hwaccm.s.uCurrentASID);
1863 AssertRC(rc);
1864
1865 if (pVCpu->hwaccm.s.fForceTLBFlush)
1866 vmxR0FlushVPID(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushContext, 0);
1867
1868#ifdef VBOX_WITH_STATISTICS
1869 if (pVCpu->hwaccm.s.fForceTLBFlush)
1870 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushTLBWorldSwitch);
1871 else
1872 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatNoFlushTLBWorldSwitch);
1873#endif
1874}
1875#endif /* HWACCM_VTX_WITH_VPID */
1876
1877/**
1878 * Runs guest code in a VT-x VM.
1879 *
1880 * @returns VBox status code.
1881 * @param pVM The VM to operate on.
1882 * @param pVCpu The VMCPU to operate on.
1883 * @param pCtx Guest context
1884 */
1885VMMR0DECL(int) VMXR0RunGuestCode(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1886{
1887 int rc = VINF_SUCCESS;
1888 RTGCUINTREG val;
1889 RTGCUINTREG exitReason, instrError, cbInstr;
1890 RTGCUINTPTR exitQualification;
1891 RTGCUINTPTR intInfo = 0; /* shut up buggy gcc 4 */
1892 RTGCUINTPTR errCode, instrInfo;
1893 bool fSyncTPR = false;
1894 PHWACCM_CPUINFO pCpu = 0;
1895 unsigned cResume = 0;
1896#ifdef VBOX_STRICT
1897 RTCPUID idCpuCheck;
1898#endif
1899#ifdef VBOX_WITH_STATISTICS
1900 bool fStatEntryStarted = true;
1901 bool fStatExit2Started = false;
1902#endif
1903
1904 Log2(("\nE"));
1905
1906 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatEntry, x);
1907
1908#ifdef VBOX_STRICT
1909 {
1910 RTCCUINTREG val;
1911
1912 rc = VMXReadVMCS(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, &val);
1913 AssertRC(rc);
1914 Log2(("VMX_VMCS_CTRL_PIN_EXEC_CONTROLS = %08x\n", val));
1915
1916 /* allowed zero */
1917 if ((val & pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.disallowed0) != pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.disallowed0)
1918 Log(("Invalid VMX_VMCS_CTRL_PIN_EXEC_CONTROLS: zero\n"));
1919
1920 /* allowed one */
1921 if ((val & ~pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.allowed1) != 0)
1922 Log(("Invalid VMX_VMCS_CTRL_PIN_EXEC_CONTROLS: one\n"));
1923
1924 rc = VMXReadVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, &val);
1925 AssertRC(rc);
1926 Log2(("VMX_VMCS_CTRL_PROC_EXEC_CONTROLS = %08x\n", val));
1927
1928 /* Must be set according to the MSR, but can be cleared in case of EPT. */
1929 if (pVM->hwaccm.s.fNestedPaging)
1930 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INVLPG_EXIT
1931 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_LOAD_EXIT
1932 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_STORE_EXIT;
1933
1934 /* allowed zero */
1935 if ((val & pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.disallowed0) != pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.disallowed0)
1936 Log(("Invalid VMX_VMCS_CTRL_PROC_EXEC_CONTROLS: zero\n"));
1937
1938 /* allowed one */
1939 if ((val & ~pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1) != 0)
1940 Log(("Invalid VMX_VMCS_CTRL_PROC_EXEC_CONTROLS: one\n"));
1941
1942 rc = VMXReadVMCS(VMX_VMCS_CTRL_ENTRY_CONTROLS, &val);
1943 AssertRC(rc);
1944 Log2(("VMX_VMCS_CTRL_ENTRY_CONTROLS = %08x\n", val));
1945
1946 /* allowed zero */
1947 if ((val & pVM->hwaccm.s.vmx.msr.vmx_entry.n.disallowed0) != pVM->hwaccm.s.vmx.msr.vmx_entry.n.disallowed0)
1948 Log(("Invalid VMX_VMCS_CTRL_ENTRY_CONTROLS: zero\n"));
1949
1950 /* allowed one */
1951 if ((val & ~pVM->hwaccm.s.vmx.msr.vmx_entry.n.allowed1) != 0)
1952 Log(("Invalid VMX_VMCS_CTRL_ENTRY_CONTROLS: one\n"));
1953
1954 rc = VMXReadVMCS(VMX_VMCS_CTRL_EXIT_CONTROLS, &val);
1955 AssertRC(rc);
1956 Log2(("VMX_VMCS_CTRL_EXIT_CONTROLS = %08x\n", val));
1957
1958 /* allowed zero */
1959 if ((val & pVM->hwaccm.s.vmx.msr.vmx_exit.n.disallowed0) != pVM->hwaccm.s.vmx.msr.vmx_exit.n.disallowed0)
1960 Log(("Invalid VMX_VMCS_CTRL_EXIT_CONTROLS: zero\n"));
1961
1962 /* allowed one */
1963 if ((val & ~pVM->hwaccm.s.vmx.msr.vmx_exit.n.allowed1) != 0)
1964 Log(("Invalid VMX_VMCS_CTRL_EXIT_CONTROLS: one\n"));
1965 }
1966#endif
1967
1968 /* We can jump to this point to resume execution after determining that a VM-exit is innocent.
1969 */
1970ResumeExecution:
1971 STAM_STATS({
1972 if (fStatExit2Started) { STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2, y); fStatExit2Started = false; }
1973 if (!fStatEntryStarted) { STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatEntry, x); fStatEntryStarted = true; }
1974 });
1975 AssertMsg(pVCpu->hwaccm.s.idEnteredCpu == RTMpCpuId(),
1976 ("Expected %d, I'm %d; cResume=%d exitReason=%RGv exitQualification=%RGv\n",
1977 (int)pVCpu->hwaccm.s.idEnteredCpu, (int)RTMpCpuId(), cResume, exitReason, exitQualification));
1978 Assert(!HWACCMR0SuspendPending());
1979
1980 /* Safety precaution; looping for too long here can have a very bad effect on the host */
1981 if (++cResume > HWACCM_MAX_RESUME_LOOPS)
1982 {
1983 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitMaxResume);
1984 rc = VINF_EM_RAW_INTERRUPT;
1985 goto end;
1986 }
1987
1988 /* Check for irq inhibition due to instruction fusing (sti, mov ss). */
1989 if (VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS))
1990 {
1991 Log(("VM_FF_INHIBIT_INTERRUPTS at %RGv successor %RGv\n", (RTGCPTR)pCtx->rip, EMGetInhibitInterruptsPC(pVM)));
1992 if (pCtx->rip != EMGetInhibitInterruptsPC(pVM))
1993 {
1994 /* Note: we intentionally don't clear VM_FF_INHIBIT_INTERRUPTS here.
1995 * Before we are able to execute this instruction in raw mode (iret to guest code) an external interrupt might
1996 * force a world switch again. Possibly allowing a guest interrupt to be dispatched in the process. This could
1997 * break the guest. Sounds very unlikely, but such timing sensitive problems are not as rare as you might think.
1998 */
1999 VM_FF_CLEAR(pVM, VM_FF_INHIBIT_INTERRUPTS);
2000 /* Irq inhibition is no longer active; clear the corresponding VMX state. */
2001 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, 0);
2002 AssertRC(rc);
2003 }
2004 }
2005 else
2006 {
2007 /* Irq inhibition is no longer active; clear the corresponding VMX state. */
2008 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, 0);
2009 AssertRC(rc);
2010 }
2011
2012 /* Check for pending actions that force us to go back to ring 3. */
2013 if (VM_FF_ISPENDING(pVM, VM_FF_TO_R3 | VM_FF_TIMER))
2014 {
2015 VM_FF_CLEAR(pVM, VM_FF_TO_R3);
2016 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatSwitchToR3);
2017 rc = VINF_EM_RAW_TO_R3;
2018 goto end;
2019 }
2020 /* Pending request packets might contain actions that need immediate attention, such as pending hardware interrupts. */
2021 if (VM_FF_ISPENDING(pVM, VM_FF_REQUEST))
2022 {
2023 rc = VINF_EM_PENDING_REQUEST;
2024 goto end;
2025 }
2026
2027 /* When external interrupts are pending, we should exit the VM when IF is set. */
2028 /* Note! *After* VM_FF_INHIBIT_INTERRUPTS check!!! */
2029 rc = VMXR0CheckPendingInterrupt(pVM, pVCpu, pCtx);
2030 if (RT_FAILURE(rc))
2031 goto end;
2032
2033 /** @todo check timers?? */
2034
2035 /* TPR caching using CR8 is only available in 64 bits mode */
2036 /* Note the 32 bits exception for AMD (X86_CPUID_AMD_FEATURE_ECX_CR8L), but that appears missing in Intel CPUs */
2037 /* Note: we can't do this in LoadGuestState as PDMApicGetTPR can jump back to ring 3 (lock)!!!!! */
2038 /**
2039 * @todo reduce overhead
2040 */
2041 if ( (pCtx->msrEFER & MSR_K6_EFER_LMA)
2042 && pVM->hwaccm.s.vmx.pAPIC)
2043 {
2044 /* TPR caching in CR8 */
2045 uint8_t u8TPR;
2046 bool fPending;
2047
2048 int rc = PDMApicGetTPR(pVM, &u8TPR, &fPending);
2049 AssertRC(rc);
2050 /* The TPR can be found at offset 0x80 in the APIC mmio page. */
2051 pVM->hwaccm.s.vmx.pAPIC[0x80] = u8TPR << 4; /* bits 7-4 contain the task priority */
2052
2053 /* Two options here:
2054 * - external interrupt pending, but masked by the TPR value.
2055 * -> a CR8 update that lower the current TPR value should cause an exit
2056 * - no pending interrupts
2057 * -> We don't need to be explicitely notified. There are enough world switches for detecting pending interrupts.
2058 */
2059 rc = VMXWriteVMCS(VMX_VMCS_CTRL_TPR_THRESHOLD, (fPending) ? u8TPR : 0);
2060 AssertRC(rc);
2061
2062 /* Always sync back the TPR; we should optimize this though */ /** @todo optimize TPR sync. */
2063 fSyncTPR = true;
2064 }
2065
2066#if defined(HWACCM_VTX_WITH_EPT) && defined(LOG_ENABLED)
2067 if ( pVM->hwaccm.s.fNestedPaging
2068# ifdef HWACCM_VTX_WITH_VPID
2069 || pVM->hwaccm.s.vmx.fVPID
2070# endif /* HWACCM_VTX_WITH_VPID */
2071 )
2072 {
2073 pCpu = HWACCMR0GetCurrentCpu();
2074 if ( pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu
2075 || pVCpu->hwaccm.s.cTLBFlushes != pCpu->cTLBFlushes)
2076 {
2077 if (pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu)
2078 Log(("Force TLB flush due to rescheduling to a different cpu (%d vs %d)\n", pVCpu->hwaccm.s.idLastCpu, pCpu->idCpu));
2079 else
2080 Log(("Force TLB flush due to changed TLB flush count (%x vs %x)\n", pVCpu->hwaccm.s.cTLBFlushes, pCpu->cTLBFlushes));
2081 }
2082 if (pCpu->fFlushTLB)
2083 Log(("Force TLB flush: first time cpu %d is used -> flush\n", pCpu->idCpu));
2084 else
2085 if (pVCpu->hwaccm.s.fForceTLBFlush)
2086 LogFlow(("Manual TLB flush\n"));
2087 }
2088#endif
2089#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2090 PGMDynMapFlushAutoSet(pVCpu);
2091#endif
2092
2093 /*
2094 * NOTE: DO NOT DO ANYTHING AFTER THIS POINT THAT MIGHT JUMP BACK TO RING 3!
2095 * (until the actual world switch)
2096 */
2097#ifdef VBOX_STRICT
2098 idCpuCheck = RTMpCpuId();
2099#endif
2100#ifdef LOG_LOGGING
2101 VMMR0LogFlushDisable(pVCpu);
2102#endif
2103 /* Save the host state first. */
2104 rc = VMXR0SaveHostState(pVM, pVCpu);
2105 if (rc != VINF_SUCCESS)
2106 goto end;
2107 /* Load the guest state */
2108 rc = VMXR0LoadGuestState(pVM, pVCpu, pCtx);
2109 if (rc != VINF_SUCCESS)
2110 goto end;
2111
2112 /* Deal with tagged TLB setup and invalidation. */
2113 pVM->hwaccm.s.vmx.pfnSetupTaggedTLB(pVM, pVCpu);
2114
2115 /* Non-register state Guest Context */
2116 /** @todo change me according to cpu state */
2117 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_ACTIVITY_STATE, VMX_CMS_GUEST_ACTIVITY_ACTIVE);
2118 AssertRC(rc);
2119
2120 STAM_STATS({ STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatEntry, x); fStatEntryStarted = false; });
2121
2122 /* Manual save and restore:
2123 * - General purpose registers except RIP, RSP
2124 *
2125 * Trashed:
2126 * - CR2 (we don't care)
2127 * - LDTR (reset to 0)
2128 * - DRx (presumably not changed at all)
2129 * - DR7 (reset to 0x400)
2130 * - EFLAGS (reset to RT_BIT(1); not relevant)
2131 *
2132 */
2133
2134
2135 /* All done! Let's start VM execution. */
2136 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatInGC, z);
2137#ifdef VBOX_STRICT
2138 Assert(idCpuCheck == RTMpCpuId());
2139#endif
2140 TMNotifyStartOfExecution(pVM);
2141 rc = pVCpu->hwaccm.s.vmx.pfnStartVM(pVCpu->hwaccm.s.fResumeVM, pCtx, &pVCpu->hwaccm.s.vmx.VMCSCache, pVM, pVCpu);
2142 TMNotifyEndOfExecution(pVM);
2143
2144 AssertMsg(!pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries, ("pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries=%d\n", pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries));
2145
2146 /* In case we execute a goto ResumeExecution later on. */
2147 pVCpu->hwaccm.s.fResumeVM = true;
2148 pVCpu->hwaccm.s.fForceTLBFlush = false;
2149
2150 /*
2151 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2152 * IMPORTANT: WE CAN'T DO ANY LOGGING OR OPERATIONS THAT CAN DO A LONGJMP BACK TO RING 3 *BEFORE* WE'VE SYNCED BACK (MOST OF) THE GUEST STATE
2153 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
2154 */
2155 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatInGC, z);
2156 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatExit1, v);
2157
2158 if (rc != VINF_SUCCESS)
2159 {
2160 VMXR0ReportWorldSwitchError(pVM, pVCpu, rc, pCtx);
2161 goto end;
2162 }
2163 /* Success. Query the guest state and figure out what has happened. */
2164
2165 /* Investigate why there was a VM-exit. */
2166 rc = VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_REASON, &exitReason);
2167 STAM_COUNTER_INC(&pVCpu->hwaccm.s.paStatExitReasonR0[exitReason & MASK_EXITREASON_STAT]);
2168
2169 exitReason &= 0xffff; /* bit 0-15 contain the exit code. */
2170 rc |= VMXReadCachedVMCS(VMX_VMCS32_RO_VM_INSTR_ERROR, &instrError);
2171 rc |= VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &cbInstr);
2172 rc |= VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &intInfo);
2173 /* might not be valid; depends on VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID. */
2174 rc |= VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERRCODE, &errCode);
2175 rc |= VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_INSTR_INFO, &instrInfo);
2176 rc |= VMXReadCachedVMCS(VMX_VMCS_RO_EXIT_QUALIFICATION, &exitQualification);
2177 AssertRC(rc);
2178
2179 /* Sync back the guest state */
2180 rc = VMXR0SaveGuestState(pVM, pVCpu, pCtx);
2181 AssertRC(rc);
2182
2183 /* Note! NOW IT'S SAFE FOR LOGGING! */
2184#ifdef LOG_LOGGING
2185 VMMR0LogFlushEnable(pVCpu);
2186#endif
2187 Log2(("Raw exit reason %08x\n", exitReason));
2188
2189 /* Check if an injected event was interrupted prematurely. */
2190 rc = VMXReadCachedVMCS(VMX_VMCS32_RO_IDT_INFO, &val);
2191 AssertRC(rc);
2192 pVCpu->hwaccm.s.Event.intInfo = VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(val);
2193 if ( VMX_EXIT_INTERRUPTION_INFO_VALID(pVCpu->hwaccm.s.Event.intInfo)
2194 /* Ignore 'int xx' as they'll be restarted anyway. */
2195 && VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hwaccm.s.Event.intInfo) != VMX_EXIT_INTERRUPTION_INFO_TYPE_SW
2196 /* Ignore software exceptions (such as int3) as they're reoccur when we restart the instruction anyway. */
2197 && VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hwaccm.s.Event.intInfo) != VMX_EXIT_INTERRUPTION_INFO_TYPE_SWEXCPT)
2198 {
2199 pVCpu->hwaccm.s.Event.fPending = true;
2200 /* Error code present? */
2201 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(pVCpu->hwaccm.s.Event.intInfo))
2202 {
2203 rc = VMXReadCachedVMCS(VMX_VMCS32_RO_IDT_ERRCODE, &val);
2204 AssertRC(rc);
2205 pVCpu->hwaccm.s.Event.errCode = val;
2206 Log(("Pending inject %RX64 at %RGv exit=%08x intInfo=%08x exitQualification=%RGv pending error=%RX64\n", pVCpu->hwaccm.s.Event.intInfo, (RTGCPTR)pCtx->rip, exitReason, intInfo, exitQualification, val));
2207 }
2208 else
2209 {
2210 Log(("Pending inject %RX64 at %RGv exit=%08x intInfo=%08x exitQualification=%RGv\n", pVCpu->hwaccm.s.Event.intInfo, (RTGCPTR)pCtx->rip, exitReason, intInfo, exitQualification));
2211 pVCpu->hwaccm.s.Event.errCode = 0;
2212 }
2213 }
2214#ifdef VBOX_STRICT
2215 else
2216 if ( VMX_EXIT_INTERRUPTION_INFO_VALID(pVCpu->hwaccm.s.Event.intInfo)
2217 /* Ignore software exceptions (such as int3) as they're reoccur when we restart the instruction anyway. */
2218 && VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hwaccm.s.Event.intInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_SWEXCPT)
2219 {
2220 Log(("Ignore pending inject %RX64 at %RGv exit=%08x intInfo=%08x exitQualification=%RGv\n", pVCpu->hwaccm.s.Event.intInfo, (RTGCPTR)pCtx->rip, exitReason, intInfo, exitQualification));
2221 }
2222
2223 if (exitReason == VMX_EXIT_ERR_INVALID_GUEST_STATE)
2224 HWACCMDumpRegs(pVM, pCtx);
2225#endif
2226
2227 Log2(("E%d", exitReason));
2228 Log2(("Exit reason %d, exitQualification %RGv\n", (uint32_t)exitReason, exitQualification));
2229 Log2(("instrInfo=%d instrError=%d instr length=%d\n", (uint32_t)instrInfo, (uint32_t)instrError, (uint32_t)cbInstr));
2230 Log2(("Interruption error code %d\n", (uint32_t)errCode));
2231 Log2(("IntInfo = %08x\n", (uint32_t)intInfo));
2232 Log2(("New EIP=%RGv\n", (RTGCPTR)pCtx->rip));
2233
2234 if (fSyncTPR)
2235 {
2236 rc = PDMApicSetTPR(pVM, pVM->hwaccm.s.vmx.pAPIC[0x80] >> 4);
2237 AssertRC(rc);
2238 }
2239
2240 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, v);
2241 STAM_STATS({ STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatExit2, y); fStatExit2Started = true; });
2242
2243 /* Some cases don't need a complete resync of the guest CPU state; handle them here. */
2244 switch (exitReason)
2245 {
2246 case VMX_EXIT_EXCEPTION: /* 0 Exception or non-maskable interrupt (NMI). */
2247 case VMX_EXIT_EXTERNAL_IRQ: /* 1 External interrupt. */
2248 {
2249 uint32_t vector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(intInfo);
2250
2251 if (!VMX_EXIT_INTERRUPTION_INFO_VALID(intInfo))
2252 {
2253 Assert(exitReason == VMX_EXIT_EXTERNAL_IRQ);
2254 /* External interrupt; leave to allow it to be dispatched again. */
2255 rc = VINF_EM_RAW_INTERRUPT;
2256 break;
2257 }
2258 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2259 switch (VMX_EXIT_INTERRUPTION_INFO_TYPE(intInfo))
2260 {
2261 case VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI: /* Non-maskable interrupt. */
2262 /* External interrupt; leave to allow it to be dispatched again. */
2263 rc = VINF_EM_RAW_INTERRUPT;
2264 break;
2265
2266 case VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT: /* External hardware interrupt. */
2267 AssertFailed(); /* can't come here; fails the first check. */
2268 break;
2269
2270 case VMX_EXIT_INTERRUPTION_INFO_TYPE_DBEXCPT: /* Unknown why we get this type for #DB */
2271 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SWEXCPT: /* Software exception. (#BP or #OF) */
2272 Assert(vector == 1 || vector == 3 || vector == 4);
2273 /* no break */
2274 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HWEXCPT: /* Hardware exception. */
2275 Log2(("Hardware/software interrupt %d\n", vector));
2276 switch (vector)
2277 {
2278 case X86_XCPT_NM:
2279 {
2280 Log(("#NM fault at %RGv error code %x\n", (RTGCPTR)pCtx->rip, errCode));
2281
2282 /** @todo don't intercept #NM exceptions anymore when we've activated the guest FPU state. */
2283 /* If we sync the FPU/XMM state on-demand, then we can continue execution as if nothing has happened. */
2284 rc = CPUMR0LoadGuestFPU(pVM, pVCpu, pCtx);
2285 if (rc == VINF_SUCCESS)
2286 {
2287 Assert(CPUMIsGuestFPUStateActive(pVCpu));
2288
2289 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitShadowNM);
2290
2291 /* Continue execution. */
2292 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
2293
2294 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2295 goto ResumeExecution;
2296 }
2297
2298 Log(("Forward #NM fault to the guest\n"));
2299 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestNM);
2300 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, 0);
2301 AssertRC(rc);
2302 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2303 goto ResumeExecution;
2304 }
2305
2306 case X86_XCPT_PF: /* Page fault */
2307 {
2308#ifdef DEBUG
2309 if (pVM->hwaccm.s.fNestedPaging)
2310 { /* A genuine pagefault.
2311 * Forward the trap to the guest by injecting the exception and resuming execution.
2312 */
2313 Log(("Guest page fault at %RGv cr2=%RGv error code %x rsp=%RGv\n", (RTGCPTR)pCtx->rip, exitQualification, errCode, (RTGCPTR)pCtx->rsp));
2314
2315 Assert(CPUMIsGuestInPagedProtectedModeEx(pCtx));
2316
2317 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestPF);
2318
2319 /* Now we must update CR2. */
2320 pCtx->cr2 = exitQualification;
2321 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
2322 AssertRC(rc);
2323
2324 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2325 goto ResumeExecution;
2326 }
2327#endif
2328 Assert(!pVM->hwaccm.s.fNestedPaging);
2329
2330 Log2(("Page fault at %RGv error code %x\n", exitQualification, errCode));
2331 /* Exit qualification contains the linear address of the page fault. */
2332 TRPMAssertTrap(pVM, X86_XCPT_PF, TRPM_TRAP);
2333 TRPMSetErrorCode(pVM, errCode);
2334 TRPMSetFaultAddress(pVM, exitQualification);
2335
2336 /* Forward it to our trap handler first, in case our shadow pages are out of sync. */
2337 rc = PGMTrap0eHandler(pVM, errCode, CPUMCTX2CORE(pCtx), (RTGCPTR)exitQualification);
2338 Log2(("PGMTrap0eHandler %RGv returned %Rrc\n", (RTGCPTR)pCtx->rip, rc));
2339 if (rc == VINF_SUCCESS)
2340 { /* We've successfully synced our shadow pages, so let's just continue execution. */
2341 Log2(("Shadow page fault at %RGv cr2=%RGv error code %x\n", (RTGCPTR)pCtx->rip, exitQualification ,errCode));
2342 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitShadowPF);
2343
2344 TRPMResetTrap(pVM);
2345
2346 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2347 goto ResumeExecution;
2348 }
2349 else
2350 if (rc == VINF_EM_RAW_GUEST_TRAP)
2351 { /* A genuine pagefault.
2352 * Forward the trap to the guest by injecting the exception and resuming execution.
2353 */
2354 Log2(("Forward page fault to the guest\n"));
2355
2356 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestPF);
2357 /* The error code might have been changed. */
2358 errCode = TRPMGetErrorCode(pVM);
2359
2360 TRPMResetTrap(pVM);
2361
2362 /* Now we must update CR2. */
2363 pCtx->cr2 = exitQualification;
2364 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
2365 AssertRC(rc);
2366
2367 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2368 goto ResumeExecution;
2369 }
2370#ifdef VBOX_STRICT
2371 if (rc != VINF_EM_RAW_EMULATE_INSTR)
2372 Log2(("PGMTrap0eHandler failed with %d\n", rc));
2373#endif
2374 /* Need to go back to the recompiler to emulate the instruction. */
2375 TRPMResetTrap(pVM);
2376 break;
2377 }
2378
2379 case X86_XCPT_MF: /* Floating point exception. */
2380 {
2381 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestMF);
2382 if (!(pCtx->cr0 & X86_CR0_NE))
2383 {
2384 /* old style FPU error reporting needs some extra work. */
2385 /** @todo don't fall back to the recompiler, but do it manually. */
2386 rc = VINF_EM_RAW_EMULATE_INSTR;
2387 break;
2388 }
2389 Log(("Trap %x at %04X:%RGv\n", vector, pCtx->cs, (RTGCPTR)pCtx->rip));
2390 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
2391 AssertRC(rc);
2392
2393 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2394 goto ResumeExecution;
2395 }
2396
2397 case X86_XCPT_DB: /* Debug exception. */
2398 {
2399 uint64_t uDR6;
2400
2401 /* DR6, DR7.GD and IA32_DEBUGCTL.LBR are not updated yet.
2402 *
2403 * Exit qualification bits:
2404 * 3:0 B0-B3 which breakpoint condition was met
2405 * 12:4 Reserved (0)
2406 * 13 BD - debug register access detected
2407 * 14 BS - single step execution or branch taken
2408 * 63:15 Reserved (0)
2409 */
2410 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestDB);
2411
2412 /* Note that we don't support guest and host-initiated debugging at the same time. */
2413 Assert(DBGFIsStepping(pVM) || CPUMIsGuestInRealModeEx(pCtx));
2414
2415 uDR6 = X86_DR6_INIT_VAL;
2416 uDR6 |= (exitQualification & (X86_DR6_B0|X86_DR6_B1|X86_DR6_B2|X86_DR6_B3|X86_DR6_BD|X86_DR6_BS));
2417 rc = DBGFR0Trap01Handler(pVM, CPUMCTX2CORE(pCtx), uDR6);
2418 if (rc == VINF_EM_RAW_GUEST_TRAP)
2419 {
2420 /** @todo this isn't working, but we'll never get here normally. */
2421
2422 /* Update DR6 here. */
2423 pCtx->dr[6] = uDR6;
2424
2425 /* X86_DR7_GD will be cleared if drx accesses should be trapped inside the guest. */
2426 pCtx->dr[7] &= ~X86_DR7_GD;
2427
2428 /* Paranoia. */
2429 pCtx->dr[7] &= 0xffffffff; /* upper 32 bits reserved */
2430 pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
2431 pCtx->dr[7] |= 0x400; /* must be one */
2432
2433 /* Resync DR7 */
2434 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_DR7, pCtx->dr[7]);
2435 AssertRC(rc);
2436
2437 Log(("Trap %x (debug) at %RGv exit qualification %RX64\n", vector, (RTGCPTR)pCtx->rip, exitQualification));
2438 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
2439 AssertRC(rc);
2440
2441 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2442 goto ResumeExecution;
2443 }
2444 /* Return to ring 3 to deal with the debug exit code. */
2445 break;
2446 }
2447
2448 case X86_XCPT_GP: /* General protection failure exception.*/
2449 {
2450 uint32_t cbSize;
2451
2452 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestGP);
2453#ifdef VBOX_STRICT
2454 if (!CPUMIsGuestInRealModeEx(pCtx))
2455 {
2456 Log(("Trap %x at %04X:%RGv errorCode=%x\n", vector, pCtx->cs, (RTGCPTR)pCtx->rip, errCode));
2457 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
2458 AssertRC(rc);
2459 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2460 goto ResumeExecution;
2461 }
2462#endif
2463 Assert(CPUMIsGuestInRealModeEx(pCtx));
2464
2465 LogFlow(("Real mode X86_XCPT_GP instruction emulation at %RGv\n", (RTGCPTR)pCtx->rip));
2466 rc = EMInterpretInstruction(pVM, CPUMCTX2CORE(pCtx), 0, &cbSize);
2467 if (rc == VINF_SUCCESS)
2468 {
2469 /* EIP has been updated already. */
2470
2471 /* lidt, lgdt can end up here. In the future crx changes as well. Just reload the whole context to be done with it. */
2472 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_ALL;
2473
2474 /* Only resume if successful. */
2475 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2476 goto ResumeExecution;
2477 }
2478 AssertMsg(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_EM_HALT, ("Unexpected rc=%Rrc\n", rc));
2479 break;
2480 }
2481
2482#ifdef VBOX_STRICT
2483 case X86_XCPT_DE: /* Divide error. */
2484 case X86_XCPT_UD: /* Unknown opcode exception. */
2485 case X86_XCPT_SS: /* Stack segment exception. */
2486 case X86_XCPT_NP: /* Segment not present exception. */
2487 {
2488 switch(vector)
2489 {
2490 case X86_XCPT_DE:
2491 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestDE);
2492 break;
2493 case X86_XCPT_UD:
2494 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestUD);
2495 break;
2496 case X86_XCPT_SS:
2497 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestSS);
2498 break;
2499 case X86_XCPT_NP:
2500 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestNP);
2501 break;
2502 }
2503
2504 Log(("Trap %x at %04X:%RGv\n", vector, pCtx->cs, (RTGCPTR)pCtx->rip));
2505 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
2506 AssertRC(rc);
2507
2508 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2509 goto ResumeExecution;
2510 }
2511#endif
2512 default:
2513#ifdef HWACCM_VMX_EMULATE_REALMODE
2514 if (CPUMIsGuestInRealModeEx(pCtx))
2515 {
2516 Log(("Real Mode Trap %x at %04x:%04X error code %x\n", vector, pCtx->cs, pCtx->eip, errCode));
2517 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), cbInstr, errCode);
2518 AssertRC(rc);
2519
2520 /* Go back to ring 3 in case of a triple fault. */
2521 if ( vector == X86_XCPT_DF
2522 && rc == VINF_EM_RESET)
2523 break;
2524
2525 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2526 goto ResumeExecution;
2527 }
2528#endif
2529 AssertMsgFailed(("Unexpected vm-exit caused by exception %x\n", vector));
2530 rc = VERR_VMX_UNEXPECTED_EXCEPTION;
2531 break;
2532 } /* switch (vector) */
2533
2534 break;
2535
2536 default:
2537 rc = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_CODE;
2538 AssertMsgFailed(("Unexpected interuption code %x\n", intInfo));
2539 break;
2540 }
2541
2542 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
2543 break;
2544 }
2545
2546 case VMX_EXIT_EPT_VIOLATION: /* 48 EPT violation. An attempt to access memory with a guest-physical address was disallowed by the configuration of the EPT paging structures. */
2547 {
2548 RTGCPHYS GCPhys;
2549
2550 Assert(pVM->hwaccm.s.fNestedPaging);
2551
2552 rc = VMXReadVMCS64(VMX_VMCS_EXIT_PHYS_ADDR_FULL, &GCPhys);
2553 AssertRC(rc);
2554 Assert(((exitQualification >> 7) & 3) != 2);
2555
2556 /* Determine the kind of violation. */
2557 errCode = 0;
2558 if (exitQualification & VMX_EXIT_QUALIFICATION_EPT_INSTR_FETCH)
2559 errCode |= X86_TRAP_PF_ID;
2560
2561 if (exitQualification & VMX_EXIT_QUALIFICATION_EPT_DATA_WRITE)
2562 errCode |= X86_TRAP_PF_RW;
2563
2564 /* If the page is present, then it's a page level protection fault. */
2565 if (exitQualification & VMX_EXIT_QUALIFICATION_EPT_ENTRY_PRESENT)
2566 errCode |= X86_TRAP_PF_P;
2567
2568 Log(("EPT Page fault %x at %RGp error code %x\n", (uint32_t)exitQualification, GCPhys, errCode));
2569
2570 /* GCPhys contains the guest physical address of the page fault. */
2571 TRPMAssertTrap(pVM, X86_XCPT_PF, TRPM_TRAP);
2572 TRPMSetErrorCode(pVM, errCode);
2573 TRPMSetFaultAddress(pVM, GCPhys);
2574
2575 /* Handle the pagefault trap for the nested shadow table. */
2576 rc = PGMR0Trap0eHandlerNestedPaging(pVM, PGMMODE_EPT, errCode, CPUMCTX2CORE(pCtx), GCPhys);
2577 Log2(("PGMR0Trap0eHandlerNestedPaging %RGv returned %Rrc\n", (RTGCPTR)pCtx->rip, rc));
2578 if (rc == VINF_SUCCESS)
2579 { /* We've successfully synced our shadow pages, so let's just continue execution. */
2580 Log2(("Shadow page fault at %RGv cr2=%RGp error code %x\n", (RTGCPTR)pCtx->rip, exitQualification , errCode));
2581 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitReasonNPF);
2582
2583 TRPMResetTrap(pVM);
2584
2585 goto ResumeExecution;
2586 }
2587
2588#ifdef VBOX_STRICT
2589 if (rc != VINF_EM_RAW_EMULATE_INSTR)
2590 LogFlow(("PGMTrap0eHandlerNestedPaging failed with %d\n", rc));
2591#endif
2592 /* Need to go back to the recompiler to emulate the instruction. */
2593 TRPMResetTrap(pVM);
2594 break;
2595 }
2596
2597 case VMX_EXIT_EPT_MISCONFIG:
2598 {
2599 RTGCPHYS GCPhys;
2600
2601 Assert(pVM->hwaccm.s.fNestedPaging);
2602
2603 rc = VMXReadVMCS64(VMX_VMCS_EXIT_PHYS_ADDR_FULL, &GCPhys);
2604 AssertRC(rc);
2605
2606 Log(("VMX_EXIT_EPT_MISCONFIG for %VGp\n", GCPhys));
2607 break;
2608 }
2609
2610 case VMX_EXIT_IRQ_WINDOW: /* 7 Interrupt window. */
2611 /* Clear VM-exit on IF=1 change. */
2612 LogFlow(("VMX_EXIT_IRQ_WINDOW %RGv pending=%d IF=%d\n", (RTGCPTR)pCtx->rip, VM_FF_ISPENDING(pVM, (VM_FF_INTERRUPT_APIC|VM_FF_INTERRUPT_PIC)), pCtx->eflags.Bits.u1IF));
2613 pVCpu->hwaccm.s.vmx.proc_ctls &= ~VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_IRQ_WINDOW_EXIT;
2614 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
2615 AssertRC(rc);
2616 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIrqWindow);
2617 goto ResumeExecution; /* we check for pending guest interrupts there */
2618
2619 case VMX_EXIT_WBINVD: /* 54 Guest software attempted to execute WBINVD. (conditional) */
2620 case VMX_EXIT_INVD: /* 13 Guest software attempted to execute INVD. (unconditional) */
2621 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitInvd);
2622 /* Skip instruction and continue directly. */
2623 pCtx->rip += cbInstr;
2624 /* Continue execution.*/
2625 goto ResumeExecution;
2626
2627 case VMX_EXIT_CPUID: /* 10 Guest software attempted to execute CPUID. */
2628 {
2629 Log2(("VMX: Cpuid %x\n", pCtx->eax));
2630 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCpuid);
2631 rc = EMInterpretCpuId(pVM, CPUMCTX2CORE(pCtx));
2632 if (rc == VINF_SUCCESS)
2633 {
2634 /* Update EIP and continue execution. */
2635 Assert(cbInstr == 2);
2636 pCtx->rip += cbInstr;
2637 goto ResumeExecution;
2638 }
2639 AssertMsgFailed(("EMU: cpuid failed with %Rrc\n", rc));
2640 rc = VINF_EM_RAW_EMULATE_INSTR;
2641 break;
2642 }
2643
2644 case VMX_EXIT_RDTSC: /* 16 Guest software attempted to execute RDTSC. */
2645 {
2646 Log2(("VMX: Rdtsc\n"));
2647 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitRdtsc);
2648 rc = EMInterpretRdtsc(pVM, CPUMCTX2CORE(pCtx));
2649 if (rc == VINF_SUCCESS)
2650 {
2651 /* Update EIP and continue execution. */
2652 Assert(cbInstr == 2);
2653 pCtx->rip += cbInstr;
2654 goto ResumeExecution;
2655 }
2656 AssertMsgFailed(("EMU: rdtsc failed with %Rrc\n", rc));
2657 rc = VINF_EM_RAW_EMULATE_INSTR;
2658 break;
2659 }
2660
2661 case VMX_EXIT_INVPG: /* 14 Guest software attempted to execute INVPG. */
2662 {
2663 Log2(("VMX: invlpg\n"));
2664 Assert(!pVM->hwaccm.s.fNestedPaging);
2665
2666 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitInvpg);
2667 rc = EMInterpretInvlpg(pVM, CPUMCTX2CORE(pCtx), exitQualification);
2668 if (rc == VINF_SUCCESS)
2669 {
2670 /* Update EIP and continue execution. */
2671 pCtx->rip += cbInstr;
2672 goto ResumeExecution;
2673 }
2674 AssertMsg(rc == VERR_EM_INTERPRETER, ("EMU: invlpg %RGv failed with %Rrc\n", exitQualification, rc));
2675 break;
2676 }
2677
2678 case VMX_EXIT_RDMSR: /* 31 RDMSR. Guest software attempted to execute RDMSR. */
2679 case VMX_EXIT_WRMSR: /* 32 WRMSR. Guest software attempted to execute WRMSR. */
2680 {
2681 uint32_t cbSize;
2682
2683 /* Note: the intel manual claims there's a REX version of RDMSR that's slightly different, so we play safe by completely disassembling the instruction. */
2684 Log2(("VMX: %s\n", (exitReason == VMX_EXIT_RDMSR) ? "rdmsr" : "wrmsr"));
2685 rc = EMInterpretInstruction(pVM, CPUMCTX2CORE(pCtx), 0, &cbSize);
2686 if (rc == VINF_SUCCESS)
2687 {
2688 /* EIP has been updated already. */
2689
2690 /* Only resume if successful. */
2691 goto ResumeExecution;
2692 }
2693 AssertMsg(rc == VERR_EM_INTERPRETER, ("EMU: %s failed with %Rrc\n", (exitReason == VMX_EXIT_RDMSR) ? "rdmsr" : "wrmsr", rc));
2694 break;
2695 }
2696
2697 case VMX_EXIT_CRX_MOVE: /* 28 Control-register accesses. */
2698 {
2699 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatExit2Sub2, y2);
2700
2701 switch (VMX_EXIT_QUALIFICATION_CRX_ACCESS(exitQualification))
2702 {
2703 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_WRITE:
2704 Log2(("VMX: %RGv mov cr%d, x\n", (RTGCPTR)pCtx->rip, VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification)));
2705 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCRxWrite[VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification)]);
2706 rc = EMInterpretCRxWrite(pVM, CPUMCTX2CORE(pCtx),
2707 VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification),
2708 VMX_EXIT_QUALIFICATION_CRX_GENREG(exitQualification));
2709
2710 switch (VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification))
2711 {
2712 case 0:
2713 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0 | HWACCM_CHANGED_GUEST_CR3;
2714 break;
2715 case 2:
2716 break;
2717 case 3:
2718 Assert(!pVM->hwaccm.s.fNestedPaging || !CPUMIsGuestInPagedProtectedModeEx(pCtx));
2719 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR3;
2720 break;
2721 case 4:
2722 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR4;
2723 break;
2724 case 8:
2725 /* CR8 contains the APIC TPR */
2726 Assert(!(pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW));
2727 break;
2728
2729 default:
2730 AssertFailed();
2731 break;
2732 }
2733 /* Check if a sync operation is pending. */
2734 if ( rc == VINF_SUCCESS /* don't bother if we are going to ring 3 anyway */
2735 && VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL))
2736 {
2737 rc = PGMSyncCR3(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR3(pVM), CPUMGetGuestCR4(pVM), VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3));
2738 AssertRC(rc);
2739 }
2740 break;
2741
2742 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ:
2743 Log2(("VMX: mov x, crx\n"));
2744 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCRxRead[VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification)]);
2745
2746 Assert(!pVM->hwaccm.s.fNestedPaging || !CPUMIsGuestInPagedProtectedModeEx(pCtx) || VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification) != USE_REG_CR3);
2747
2748 /* CR8 reads only cause an exit when the TPR shadow feature isn't present. */
2749 Assert(VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification) != 8 || !(pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW));
2750
2751 rc = EMInterpretCRxRead(pVM, CPUMCTX2CORE(pCtx),
2752 VMX_EXIT_QUALIFICATION_CRX_GENREG(exitQualification),
2753 VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification));
2754 break;
2755
2756 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_CLTS:
2757 Log2(("VMX: clts\n"));
2758 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCLTS);
2759 rc = EMInterpretCLTS(pVM);
2760 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
2761 break;
2762
2763 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_LMSW:
2764 Log2(("VMX: lmsw %x\n", VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(exitQualification)));
2765 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitLMSW);
2766 rc = EMInterpretLMSW(pVM, CPUMCTX2CORE(pCtx), VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(exitQualification));
2767 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
2768 break;
2769 }
2770
2771 /* Update EIP if no error occurred. */
2772 if (RT_SUCCESS(rc))
2773 pCtx->rip += cbInstr;
2774
2775 if (rc == VINF_SUCCESS)
2776 {
2777 /* Only resume if successful. */
2778 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub2, y2);
2779 goto ResumeExecution;
2780 }
2781 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
2782 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub2, y2);
2783 break;
2784 }
2785
2786 case VMX_EXIT_DRX_MOVE: /* 29 Debug-register accesses. */
2787 {
2788 if (!DBGFIsStepping(pVM))
2789 {
2790 /* Disable drx move intercepts. */
2791 pVCpu->hwaccm.s.vmx.proc_ctls &= ~VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT;
2792 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
2793 AssertRC(rc);
2794
2795 /* Save the host and load the guest debug state. */
2796 rc = CPUMR0LoadGuestDebugState(pVM, pVCpu, pCtx, true /* include DR6 */);
2797 AssertRC(rc);
2798
2799#ifdef VBOX_WITH_STATISTICS
2800 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxContextSwitch);
2801 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
2802 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxWrite);
2803 else
2804 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxRead);
2805#endif
2806
2807 goto ResumeExecution;
2808 }
2809
2810 /** @todo clear VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT after the first time and restore drx registers afterwards */
2811 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
2812 {
2813 Log2(("VMX: mov drx%d, genreg%d\n", VMX_EXIT_QUALIFICATION_DRX_REGISTER(exitQualification), VMX_EXIT_QUALIFICATION_DRX_GENREG(exitQualification)));
2814 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxWrite);
2815 rc = EMInterpretDRxWrite(pVM, CPUMCTX2CORE(pCtx),
2816 VMX_EXIT_QUALIFICATION_DRX_REGISTER(exitQualification),
2817 VMX_EXIT_QUALIFICATION_DRX_GENREG(exitQualification));
2818 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_DEBUG;
2819 Log2(("DR7=%08x\n", pCtx->dr[7]));
2820 }
2821 else
2822 {
2823 Log2(("VMX: mov x, drx\n"));
2824 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxRead);
2825 rc = EMInterpretDRxRead(pVM, CPUMCTX2CORE(pCtx),
2826 VMX_EXIT_QUALIFICATION_DRX_GENREG(exitQualification),
2827 VMX_EXIT_QUALIFICATION_DRX_REGISTER(exitQualification));
2828 }
2829 /* Update EIP if no error occurred. */
2830 if (RT_SUCCESS(rc))
2831 pCtx->rip += cbInstr;
2832
2833 if (rc == VINF_SUCCESS)
2834 {
2835 /* Only resume if successful. */
2836 goto ResumeExecution;
2837 }
2838 Assert(rc == VERR_EM_INTERPRETER);
2839 break;
2840 }
2841
2842 /* Note: We'll get a #GP if the IO instruction isn't allowed (IOPL or TSS bitmap); no need to double check. */
2843 case VMX_EXIT_PORT_IO: /* 30 I/O instruction. */
2844 {
2845 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
2846 uint32_t uIOWidth = VMX_EXIT_QUALIFICATION_IO_WIDTH(exitQualification);
2847 uint32_t uPort;
2848 bool fIOWrite = (VMX_EXIT_QUALIFICATION_IO_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT);
2849
2850 /** @todo necessary to make the distinction? */
2851 if (VMX_EXIT_QUALIFICATION_IO_ENCODING(exitQualification) == VMX_EXIT_QUALIFICATION_IO_ENCODING_DX)
2852 {
2853 uPort = pCtx->edx & 0xffff;
2854 }
2855 else
2856 uPort = VMX_EXIT_QUALIFICATION_IO_PORT(exitQualification); /* Immediate encoding. */
2857
2858 /* paranoia */
2859 if (RT_UNLIKELY(uIOWidth == 2 || uIOWidth >= 4))
2860 {
2861 rc = fIOWrite ? VINF_IOM_HC_IOPORT_WRITE : VINF_IOM_HC_IOPORT_READ;
2862 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
2863 break;
2864 }
2865
2866 uint32_t cbSize = g_aIOSize[uIOWidth];
2867
2868 if (VMX_EXIT_QUALIFICATION_IO_STRING(exitQualification))
2869 {
2870 /* ins/outs */
2871 DISCPUSTATE Cpu;
2872
2873 /* Disassemble manually to deal with segment prefixes. */
2874 /** @todo VMX_VMCS_EXIT_GUEST_LINEAR_ADDR contains the flat pointer operand of the instruction. */
2875 /** @todo VMX_VMCS32_RO_EXIT_INSTR_INFO also contains segment prefix info. */
2876 rc = EMInterpretDisasOne(pVM, CPUMCTX2CORE(pCtx), &Cpu, NULL);
2877 if (rc == VINF_SUCCESS)
2878 {
2879 if (fIOWrite)
2880 {
2881 Log2(("IOMInterpretOUTSEx %RGv %x size=%d\n", (RTGCPTR)pCtx->rip, uPort, cbSize));
2882 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIOStringWrite);
2883 rc = IOMInterpretOUTSEx(pVM, CPUMCTX2CORE(pCtx), uPort, Cpu.prefix, cbSize);
2884 }
2885 else
2886 {
2887 Log2(("IOMInterpretINSEx %RGv %x size=%d\n", (RTGCPTR)pCtx->rip, uPort, cbSize));
2888 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIOStringRead);
2889 rc = IOMInterpretINSEx(pVM, CPUMCTX2CORE(pCtx), uPort, Cpu.prefix, cbSize);
2890 }
2891 }
2892 else
2893 rc = VINF_EM_RAW_EMULATE_INSTR;
2894 }
2895 else
2896 {
2897 /* normal in/out */
2898 uint32_t uAndVal = g_aIOOpAnd[uIOWidth];
2899
2900 Assert(!VMX_EXIT_QUALIFICATION_IO_REP(exitQualification));
2901
2902 if (fIOWrite)
2903 {
2904 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIOWrite);
2905 rc = IOMIOPortWrite(pVM, uPort, pCtx->eax & uAndVal, cbSize);
2906 }
2907 else
2908 {
2909 uint32_t u32Val = 0;
2910
2911 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIORead);
2912 rc = IOMIOPortRead(pVM, uPort, &u32Val, cbSize);
2913 if (IOM_SUCCESS(rc))
2914 {
2915 /* Write back to the EAX register. */
2916 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Val & uAndVal);
2917 }
2918 }
2919 }
2920 /*
2921 * Handled the I/O return codes.
2922 * (The unhandled cases end up with rc == VINF_EM_RAW_EMULATE_INSTR.)
2923 */
2924 if (IOM_SUCCESS(rc))
2925 {
2926 /* Update EIP and continue execution. */
2927 pCtx->rip += cbInstr;
2928 if (RT_LIKELY(rc == VINF_SUCCESS))
2929 {
2930 /* If any IO breakpoints are armed, then we should check if a debug trap needs to be generated. */
2931 if (pCtx->dr[7] & X86_DR7_ENABLED_MASK)
2932 {
2933 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxIOCheck);
2934 for (unsigned i=0;i<4;i++)
2935 {
2936 unsigned uBPLen = g_aIOSize[X86_DR7_GET_LEN(pCtx->dr[7], i)];
2937
2938 if ( (uPort >= pCtx->dr[i] && uPort < pCtx->dr[i] + uBPLen)
2939 && (pCtx->dr[7] & (X86_DR7_L(i) | X86_DR7_G(i)))
2940 && (pCtx->dr[7] & X86_DR7_RW(i, X86_DR7_RW_IO)) == X86_DR7_RW(i, X86_DR7_RW_IO))
2941 {
2942 uint64_t uDR6;
2943
2944 Assert(CPUMIsGuestDebugStateActive(pVM));
2945
2946 uDR6 = ASMGetDR6();
2947
2948 /* Clear all breakpoint status flags and set the one we just hit. */
2949 uDR6 &= ~(X86_DR6_B0|X86_DR6_B1|X86_DR6_B2|X86_DR6_B3);
2950 uDR6 |= (uint64_t)RT_BIT(i);
2951
2952 /* Note: AMD64 Architecture Programmer's Manual 13.1:
2953 * Bits 15:13 of the DR6 register is never cleared by the processor and must be cleared by software after
2954 * the contents have been read.
2955 */
2956 ASMSetDR6(uDR6);
2957
2958 /* X86_DR7_GD will be cleared if drx accesses should be trapped inside the guest. */
2959 pCtx->dr[7] &= ~X86_DR7_GD;
2960
2961 /* Paranoia. */
2962 pCtx->dr[7] &= 0xffffffff; /* upper 32 bits reserved */
2963 pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
2964 pCtx->dr[7] |= 0x400; /* must be one */
2965
2966 /* Resync DR7 */
2967 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_DR7, pCtx->dr[7]);
2968 AssertRC(rc);
2969
2970 /* Construct inject info. */
2971 intInfo = X86_XCPT_DB;
2972 intInfo |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
2973 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HWEXCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
2974
2975 Log(("Inject IO debug trap at %RGv\n", (RTGCPTR)pCtx->rip));
2976 rc = VMXR0InjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo), 0, 0);
2977 AssertRC(rc);
2978
2979 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
2980 goto ResumeExecution;
2981 }
2982 }
2983 }
2984
2985 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
2986 goto ResumeExecution;
2987 }
2988 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
2989 break;
2990 }
2991
2992#ifdef VBOX_STRICT
2993 if (rc == VINF_IOM_HC_IOPORT_READ)
2994 Assert(!fIOWrite);
2995 else if (rc == VINF_IOM_HC_IOPORT_WRITE)
2996 Assert(fIOWrite);
2997 else
2998 AssertMsg(RT_FAILURE(rc) || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", rc));
2999#endif
3000 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
3001 break;
3002 }
3003
3004 case VMX_EXIT_TPR: /* 43 TPR below threshold. Guest software executed MOV to CR8. */
3005 LogFlow(("VMX_EXIT_TPR\n"));
3006 /* RIP is already set to the next instruction and the TPR has been synced back. Just resume. */
3007 goto ResumeExecution;
3008
3009 case VMX_EXIT_PREEMPTION_TIMER: /* 52 VMX-preemption timer expired. The preemption timer counted down to zero. */
3010#ifdef RT_OS_WINDOWS
3011 goto ResumeExecution;
3012#else
3013 break; /* enable interrupts again */
3014#endif
3015
3016 default:
3017 /* The rest is handled after syncing the entire CPU state. */
3018 break;
3019 }
3020
3021 /* Note: the guest state isn't entirely synced back at this stage. */
3022
3023 /* Investigate why there was a VM-exit. (part 2) */
3024 switch (exitReason)
3025 {
3026 case VMX_EXIT_EXCEPTION: /* 0 Exception or non-maskable interrupt (NMI). */
3027 case VMX_EXIT_EXTERNAL_IRQ: /* 1 External interrupt. */
3028 case VMX_EXIT_EPT_VIOLATION:
3029 case VMX_EXIT_PREEMPTION_TIMER: /* 52 VMX-preemption timer expired. The preemption timer counted down to zero. */
3030 /* Already handled above. */
3031 break;
3032
3033 case VMX_EXIT_TRIPLE_FAULT: /* 2 Triple fault. */
3034 rc = VINF_EM_RESET; /* Triple fault equals a reset. */
3035 break;
3036
3037 case VMX_EXIT_INIT_SIGNAL: /* 3 INIT signal. */
3038 case VMX_EXIT_SIPI: /* 4 Start-up IPI (SIPI). */
3039 rc = VINF_EM_RAW_INTERRUPT;
3040 AssertFailed(); /* Can't happen. Yet. */
3041 break;
3042
3043 case VMX_EXIT_IO_SMI_IRQ: /* 5 I/O system-management interrupt (SMI). */
3044 case VMX_EXIT_SMI_IRQ: /* 6 Other SMI. */
3045 rc = VINF_EM_RAW_INTERRUPT;
3046 AssertFailed(); /* Can't happen afaik. */
3047 break;
3048
3049 case VMX_EXIT_TASK_SWITCH: /* 9 Task switch. */
3050 rc = VERR_EM_INTERPRETER;
3051 break;
3052
3053 case VMX_EXIT_HLT: /* 12 Guest software attempted to execute HLT. */
3054 /** Check if external interrupts are pending; if so, don't switch back. */
3055 pCtx->rip++; /* skip hlt */
3056 if ( pCtx->eflags.Bits.u1IF
3057 && VM_FF_ISPENDING(pVM, (VM_FF_INTERRUPT_APIC|VM_FF_INTERRUPT_PIC)))
3058 goto ResumeExecution;
3059
3060 rc = VINF_EM_HALT;
3061 break;
3062
3063 case VMX_EXIT_RSM: /* 17 Guest software attempted to execute RSM in SMM. */
3064 AssertFailed(); /* can't happen. */
3065 rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
3066 break;
3067
3068 case VMX_EXIT_VMCALL: /* 18 Guest software executed VMCALL. */
3069 case VMX_EXIT_VMCLEAR: /* 19 Guest software executed VMCLEAR. */
3070 case VMX_EXIT_VMLAUNCH: /* 20 Guest software executed VMLAUNCH. */
3071 case VMX_EXIT_VMPTRLD: /* 21 Guest software executed VMPTRLD. */
3072 case VMX_EXIT_VMPTRST: /* 22 Guest software executed VMPTRST. */
3073 case VMX_EXIT_VMREAD: /* 23 Guest software executed VMREAD. */
3074 case VMX_EXIT_VMRESUME: /* 24 Guest software executed VMRESUME. */
3075 case VMX_EXIT_VMWRITE: /* 25 Guest software executed VMWRITE. */
3076 case VMX_EXIT_VMXOFF: /* 26 Guest software executed VMXOFF. */
3077 case VMX_EXIT_VMXON: /* 27 Guest software executed VMXON. */
3078 /** @todo inject #UD immediately */
3079 rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
3080 break;
3081
3082 case VMX_EXIT_CPUID: /* 10 Guest software attempted to execute CPUID. */
3083 case VMX_EXIT_RDTSC: /* 16 Guest software attempted to execute RDTSC. */
3084 case VMX_EXIT_INVPG: /* 14 Guest software attempted to execute INVPG. */
3085 case VMX_EXIT_CRX_MOVE: /* 28 Control-register accesses. */
3086 case VMX_EXIT_DRX_MOVE: /* 29 Debug-register accesses. */
3087 case VMX_EXIT_PORT_IO: /* 30 I/O instruction. */
3088 /* already handled above */
3089 AssertMsg( rc == VINF_PGM_CHANGE_MODE
3090 || rc == VINF_EM_RAW_INTERRUPT
3091 || rc == VERR_EM_INTERPRETER
3092 || rc == VINF_EM_RAW_EMULATE_INSTR
3093 || rc == VINF_PGM_SYNC_CR3
3094 || rc == VINF_IOM_HC_IOPORT_READ
3095 || rc == VINF_IOM_HC_IOPORT_WRITE
3096 || rc == VINF_EM_RAW_GUEST_TRAP
3097 || rc == VINF_TRPM_XCPT_DISPATCHED
3098 || rc == VINF_EM_RESCHEDULE_REM,
3099 ("rc = %d\n", rc));
3100 break;
3101
3102 case VMX_EXIT_TPR: /* 43 TPR below threshold. Guest software executed MOV to CR8. */
3103 case VMX_EXIT_RDMSR: /* 31 RDMSR. Guest software attempted to execute RDMSR. */
3104 case VMX_EXIT_WRMSR: /* 32 WRMSR. Guest software attempted to execute WRMSR. */
3105 /* Note: If we decide to emulate them here, then we must sync the MSRs that could have been changed (sysenter, fs/gs base)!!! */
3106 rc = VERR_EM_INTERPRETER;
3107 break;
3108
3109 case VMX_EXIT_RDPMC: /* 15 Guest software attempted to execute RDPMC. */
3110 case VMX_EXIT_MWAIT: /* 36 Guest software executed MWAIT. */
3111 case VMX_EXIT_MONITOR: /* 39 Guest software attempted to execute MONITOR. */
3112 case VMX_EXIT_PAUSE: /* 40 Guest software attempted to execute PAUSE. */
3113 rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
3114 break;
3115
3116 case VMX_EXIT_IRQ_WINDOW: /* 7 Interrupt window. */
3117 Assert(rc == VINF_EM_RAW_INTERRUPT);
3118 break;
3119
3120 case VMX_EXIT_ERR_INVALID_GUEST_STATE: /* 33 VM-entry failure due to invalid guest state. */
3121 {
3122#ifdef VBOX_STRICT
3123 RTCCUINTREG val = 0;
3124
3125 Log(("VMX_EXIT_ERR_INVALID_GUEST_STATE\n"));
3126
3127 VMXReadVMCS(VMX_VMCS64_GUEST_RIP, &val);
3128 Log(("Old eip %RGv new %RGv\n", (RTGCPTR)pCtx->rip, (RTGCPTR)val));
3129
3130 VMXReadVMCS(VMX_VMCS64_GUEST_CR0, &val);
3131 Log(("VMX_VMCS_GUEST_CR0 %RX64\n", (uint64_t)val));
3132
3133 VMXReadVMCS(VMX_VMCS64_GUEST_CR3, &val);
3134 Log(("VMX_VMCS_GUEST_CR3 %RX64\n", (uint64_t)val));
3135
3136 VMXReadVMCS(VMX_VMCS64_GUEST_CR4, &val);
3137 Log(("VMX_VMCS_GUEST_CR4 %RX64\n", (uint64_t)val));
3138
3139 VMXReadVMCS(VMX_VMCS_GUEST_RFLAGS, &val);
3140 Log(("VMX_VMCS_GUEST_RFLAGS %08x\n", val));
3141
3142 VMX_LOG_SELREG(CS, "CS");
3143 VMX_LOG_SELREG(DS, "DS");
3144 VMX_LOG_SELREG(ES, "ES");
3145 VMX_LOG_SELREG(FS, "FS");
3146 VMX_LOG_SELREG(GS, "GS");
3147 VMX_LOG_SELREG(SS, "SS");
3148 VMX_LOG_SELREG(TR, "TR");
3149 VMX_LOG_SELREG(LDTR, "LDTR");
3150
3151 VMXReadVMCS(VMX_VMCS64_GUEST_GDTR_BASE, &val);
3152 Log(("VMX_VMCS_GUEST_GDTR_BASE %RX64\n", (uint64_t)val));
3153 VMXReadVMCS(VMX_VMCS64_GUEST_IDTR_BASE, &val);
3154 Log(("VMX_VMCS_GUEST_IDTR_BASE %RX64\n", (uint64_t)val));
3155#endif /* VBOX_STRICT */
3156 rc = VERR_VMX_INVALID_GUEST_STATE;
3157 break;
3158 }
3159
3160 case VMX_EXIT_ERR_MSR_LOAD: /* 34 VM-entry failure due to MSR loading. */
3161 case VMX_EXIT_ERR_MACHINE_CHECK: /* 41 VM-entry failure due to machine-check. */
3162 default:
3163 rc = VERR_VMX_UNEXPECTED_EXIT_CODE;
3164 AssertMsgFailed(("Unexpected exit code %d\n", exitReason)); /* Can't happen. */
3165 break;
3166
3167 }
3168end:
3169
3170 /* Signal changes for the recompiler. */
3171 CPUMSetChangedFlags(pVM, CPUM_CHANGED_SYSENTER_MSR | CPUM_CHANGED_LDTR | CPUM_CHANGED_GDTR | CPUM_CHANGED_IDTR | CPUM_CHANGED_TR | CPUM_CHANGED_HIDDEN_SEL_REGS);
3172
3173 /* If we executed vmlaunch/vmresume and an external irq was pending, then we don't have to do a full sync the next time. */
3174 if ( exitReason == VMX_EXIT_EXTERNAL_IRQ
3175 && !VMX_EXIT_INTERRUPTION_INFO_VALID(intInfo))
3176 {
3177 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatPendingHostIrq);
3178 /* On the next entry we'll only sync the host context. */
3179 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_HOST_CONTEXT;
3180 }
3181 else
3182 {
3183 /* On the next entry we'll sync everything. */
3184 /** @todo we can do better than this */
3185 /* Not in the VINF_PGM_CHANGE_MODE though! */
3186 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_ALL;
3187 }
3188
3189 /* translate into a less severe return code */
3190 if (rc == VERR_EM_INTERPRETER)
3191 rc = VINF_EM_RAW_EMULATE_INSTR;
3192 else
3193 /* Try to extract more information about what might have gone wrong here. */
3194 if (rc == VERR_VMX_INVALID_VMCS_PTR)
3195 {
3196 VMXGetActivateVMCS(&pVCpu->hwaccm.s.vmx.lasterror.u64VMCSPhys);
3197 pVCpu->hwaccm.s.vmx.lasterror.ulVMCSRevision = *(uint32_t *)pVCpu->hwaccm.s.vmx.pVMCS;
3198 pVCpu->hwaccm.s.vmx.lasterror.idEnteredCpu = pVCpu->hwaccm.s.idEnteredCpu;
3199 pVCpu->hwaccm.s.vmx.lasterror.idCurrentCpu = RTMpCpuId();
3200 }
3201
3202 STAM_STATS({
3203 if (fStatExit2Started) STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2, y);
3204 else if (fStatEntryStarted) STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatEntry, x);
3205 });
3206 Log2(("X"));
3207 return rc;
3208}
3209
3210
3211/**
3212 * Enters the VT-x session
3213 *
3214 * @returns VBox status code.
3215 * @param pVM The VM to operate on.
3216 * @param pVCpu The VMCPU to operate on.
3217 * @param pCpu CPU info struct
3218 */
3219VMMR0DECL(int) VMXR0Enter(PVM pVM, PVMCPU pVCpu, PHWACCM_CPUINFO pCpu)
3220{
3221 Assert(pVM->hwaccm.s.vmx.fSupported);
3222
3223 unsigned cr4 = ASMGetCR4();
3224 if (!(cr4 & X86_CR4_VMXE))
3225 {
3226 AssertMsgFailed(("X86_CR4_VMXE should be set!\n"));
3227 return VERR_VMX_X86_CR4_VMXE_CLEARED;
3228 }
3229
3230 /* Activate the VM Control Structure. */
3231 int rc = VMXActivateVMCS(pVCpu->hwaccm.s.vmx.pVMCSPhys);
3232 if (RT_FAILURE(rc))
3233 return rc;
3234
3235 pVCpu->hwaccm.s.fResumeVM = false;
3236 return VINF_SUCCESS;
3237}
3238
3239
3240/**
3241 * Leaves the VT-x session
3242 *
3243 * @returns VBox status code.
3244 * @param pVM The VM to operate on.
3245 * @param pVCpu The VMCPU to operate on.
3246 * @param pCtx CPU context
3247 */
3248VMMR0DECL(int) VMXR0Leave(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
3249{
3250 Assert(pVM->hwaccm.s.vmx.fSupported);
3251
3252 /* Save the guest debug state if necessary. */
3253 if (CPUMIsGuestDebugStateActive(pVM))
3254 {
3255 CPUMR0SaveGuestDebugState(pVM, pVCpu, pCtx, true /* save DR6 */);
3256
3257 /* Enable drx move intercepts again. */
3258 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT;
3259 int rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
3260 AssertRC(rc);
3261
3262 /* Resync the debug registers the next time. */
3263 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_DEBUG;
3264 }
3265 else
3266 Assert(pVCpu->hwaccm.s.vmx.proc_ctls & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT);
3267
3268 /* Clear VM Control Structure. Marking it inactive, clearing implementation specific data and writing back VMCS data to memory. */
3269 int rc = VMXClearVMCS(pVCpu->hwaccm.s.vmx.pVMCSPhys);
3270 AssertRC(rc);
3271
3272 return VINF_SUCCESS;
3273}
3274
3275/**
3276 * Flush the TLB (EPT)
3277 *
3278 * @returns VBox status code.
3279 * @param pVM The VM to operate on.
3280 * @param pVCpu The VM CPU to operate on.
3281 * @param enmFlush Type of flush
3282 * @param GCPhys Physical address of the page to flush
3283 */
3284static void vmxR0FlushEPT(PVM pVM, PVMCPU pVCpu, VMX_FLUSH enmFlush, RTGCPHYS GCPhys)
3285{
3286 uint64_t descriptor[2];
3287
3288 LogFlow(("vmxR0FlushEPT %d %RGv\n", enmFlush, GCPhys));
3289 Assert(pVM->hwaccm.s.fNestedPaging);
3290 descriptor[0] = pVCpu->hwaccm.s.vmx.GCPhysEPTP;
3291 descriptor[1] = GCPhys;
3292 int rc = VMXR0InvEPT(enmFlush, &descriptor[0]);
3293 AssertRC(rc);
3294}
3295
3296#ifdef HWACCM_VTX_WITH_VPID
3297/**
3298 * Flush the TLB (EPT)
3299 *
3300 * @returns VBox status code.
3301 * @param pVM The VM to operate on.
3302 * @param pVCpu The VM CPU to operate on.
3303 * @param enmFlush Type of flush
3304 * @param GCPtr Virtual address of the page to flush
3305 */
3306static void vmxR0FlushVPID(PVM pVM, PVMCPU pVCpu, VMX_FLUSH enmFlush, RTGCPTR GCPtr)
3307{
3308#if HC_ARCH_BITS == 32
3309 /* If we get a flush in 64 bits guest mode, then force a full TLB flush. Invvpid probably takes only 32 bits addresses. (@todo) */
3310 if ( CPUMIsGuestInLongMode(pVM)
3311 && !VMX_IS_64BIT_HOST_MODE())
3312 {
3313 pVCpu->hwaccm.s.fForceTLBFlush = true;
3314 }
3315 else
3316#endif
3317 {
3318 uint64_t descriptor[2];
3319
3320 Assert(pVM->hwaccm.s.vmx.fVPID);
3321 descriptor[0] = pVCpu->hwaccm.s.uCurrentASID;
3322 descriptor[1] = GCPtr;
3323 int rc = VMXR0InvVPID(enmFlush, &descriptor[0]);
3324 AssertRC(rc);
3325 }
3326}
3327#endif /* HWACCM_VTX_WITH_VPID */
3328
3329/**
3330 * Invalidates a guest page
3331 *
3332 * @returns VBox status code.
3333 * @param pVM The VM to operate on.
3334 * @param pVCpu The VM CPU to operate on.
3335 * @param GCVirt Page to invalidate
3336 */
3337VMMR0DECL(int) VMXR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt)
3338{
3339 bool fFlushPending = pVCpu->hwaccm.s.fForceTLBFlush;
3340
3341 LogFlow(("VMXR0InvalidatePage %RGv\n", GCVirt));
3342
3343 /* Only relevant if we want to use VPID.
3344 * In the nested paging case we still see such calls, but
3345 * can safely ignore them. (e.g. after cr3 updates)
3346 */
3347#ifdef HWACCM_VTX_WITH_VPID
3348 /* Skip it if a TLB flush is already pending. */
3349 if ( !fFlushPending
3350 && pVM->hwaccm.s.vmx.fVPID)
3351 vmxR0FlushVPID(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushPage, GCVirt);
3352#endif /* HWACCM_VTX_WITH_VPID */
3353
3354 return VINF_SUCCESS;
3355}
3356
3357/**
3358 * Invalidates a guest page by physical address
3359 *
3360 * NOTE: Assumes the current instruction references this physical page though a virtual address!!
3361 *
3362 * @returns VBox status code.
3363 * @param pVM The VM to operate on.
3364 * @param pVCpu The VM CPU to operate on.
3365 * @param GCPhys Page to invalidate
3366 */
3367VMMR0DECL(int) VMXR0InvalidatePhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
3368{
3369 bool fFlushPending = pVCpu->hwaccm.s.fForceTLBFlush;
3370
3371 Assert(pVM->hwaccm.s.fNestedPaging);
3372
3373 LogFlow(("VMXR0InvalidatePhysPage %RGp\n", GCPhys));
3374
3375 /* Skip it if a TLB flush is already pending. */
3376 if (!fFlushPending)
3377 vmxR0FlushEPT(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushPage, GCPhys);
3378
3379 return VINF_SUCCESS;
3380}
3381
3382/**
3383 * Report world switch error and dump some useful debug info
3384 *
3385 * @param pVM The VM to operate on.
3386 * @param pVCpu The VMCPU to operate on.
3387 * @param rc Return code
3388 * @param pCtx Current CPU context (not updated)
3389 */
3390static void VMXR0ReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, int rc, PCPUMCTX pCtx)
3391{
3392 switch (rc)
3393 {
3394 case VERR_VMX_INVALID_VMXON_PTR:
3395 AssertFailed();
3396 break;
3397
3398 case VERR_VMX_UNABLE_TO_START_VM:
3399 case VERR_VMX_UNABLE_TO_RESUME_VM:
3400 {
3401 int rc;
3402 RTCCUINTREG exitReason, instrError, val;
3403
3404 rc = VMXReadVMCS(VMX_VMCS32_RO_EXIT_REASON, &exitReason);
3405 rc |= VMXReadVMCS(VMX_VMCS32_RO_VM_INSTR_ERROR, &instrError);
3406 AssertRC(rc);
3407 if (rc == VINF_SUCCESS)
3408 {
3409 Log(("Unable to start/resume VM for reason: %x. Instruction error %x\n", (uint32_t)exitReason, (uint32_t)instrError));
3410 Log(("Current stack %08x\n", &rc));
3411
3412 pVCpu->hwaccm.s.vmx.lasterror.ulInstrError = instrError;
3413 pVCpu->hwaccm.s.vmx.lasterror.ulExitReason = exitReason;
3414
3415#ifdef VBOX_STRICT
3416 RTGDTR gdtr;
3417 PX86DESCHC pDesc;
3418
3419 ASMGetGDTR(&gdtr);
3420
3421 VMXReadVMCS(VMX_VMCS64_GUEST_RIP, &val);
3422 Log(("Old eip %RGv new %RGv\n", (RTGCPTR)pCtx->rip, (RTGCPTR)val));
3423 VMXReadVMCS(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, &val);
3424 Log(("VMX_VMCS_CTRL_PIN_EXEC_CONTROLS %08x\n", val));
3425 VMXReadVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, &val);
3426 Log(("VMX_VMCS_CTRL_PROC_EXEC_CONTROLS %08x\n", val));
3427 VMXReadVMCS(VMX_VMCS_CTRL_ENTRY_CONTROLS, &val);
3428 Log(("VMX_VMCS_CTRL_ENTRY_CONTROLS %08x\n", val));
3429 VMXReadVMCS(VMX_VMCS_CTRL_EXIT_CONTROLS, &val);
3430 Log(("VMX_VMCS_CTRL_EXIT_CONTROLS %08x\n", val));
3431
3432 VMXReadVMCS(VMX_VMCS_HOST_CR0, &val);
3433 Log(("VMX_VMCS_HOST_CR0 %08x\n", val));
3434
3435 VMXReadVMCS(VMX_VMCS_HOST_CR3, &val);
3436 Log(("VMX_VMCS_HOST_CR3 %08x\n", val));
3437
3438 VMXReadVMCS(VMX_VMCS_HOST_CR4, &val);
3439 Log(("VMX_VMCS_HOST_CR4 %08x\n", val));
3440
3441 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_CS, &val);
3442 Log(("VMX_VMCS_HOST_FIELD_CS %08x\n", val));
3443
3444 VMXReadVMCS(VMX_VMCS_GUEST_RFLAGS, &val);
3445 Log(("VMX_VMCS_GUEST_RFLAGS %08x\n", val));
3446
3447 if (val < gdtr.cbGdt)
3448 {
3449 pDesc = &((PX86DESCHC)gdtr.pGdt)[val >> X86_SEL_SHIFT_HC];
3450 HWACCMR0DumpDescriptor(pDesc, val, "CS: ");
3451 }
3452
3453 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_DS, &val);
3454 Log(("VMX_VMCS_HOST_FIELD_DS %08x\n", val));
3455 if (val < gdtr.cbGdt)
3456 {
3457 pDesc = &((PX86DESCHC)gdtr.pGdt)[val >> X86_SEL_SHIFT_HC];
3458 HWACCMR0DumpDescriptor(pDesc, val, "DS: ");
3459 }
3460
3461 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_ES, &val);
3462 Log(("VMX_VMCS_HOST_FIELD_ES %08x\n", val));
3463 if (val < gdtr.cbGdt)
3464 {
3465 pDesc = &((PX86DESCHC)gdtr.pGdt)[val >> X86_SEL_SHIFT_HC];
3466 HWACCMR0DumpDescriptor(pDesc, val, "ES: ");
3467 }
3468
3469 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_FS, &val);
3470 Log(("VMX_VMCS16_HOST_FIELD_FS %08x\n", val));
3471 if (val < gdtr.cbGdt)
3472 {
3473 pDesc = &((PX86DESCHC)gdtr.pGdt)[val >> X86_SEL_SHIFT_HC];
3474 HWACCMR0DumpDescriptor(pDesc, val, "FS: ");
3475 }
3476
3477 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_GS, &val);
3478 Log(("VMX_VMCS16_HOST_FIELD_GS %08x\n", val));
3479 if (val < gdtr.cbGdt)
3480 {
3481 pDesc = &((PX86DESCHC)gdtr.pGdt)[val >> X86_SEL_SHIFT_HC];
3482 HWACCMR0DumpDescriptor(pDesc, val, "GS: ");
3483 }
3484
3485 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_SS, &val);
3486 Log(("VMX_VMCS16_HOST_FIELD_SS %08x\n", val));
3487 if (val < gdtr.cbGdt)
3488 {
3489 pDesc = &((PX86DESCHC)gdtr.pGdt)[val >> X86_SEL_SHIFT_HC];
3490 HWACCMR0DumpDescriptor(pDesc, val, "SS: ");
3491 }
3492
3493 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_TR, &val);
3494 Log(("VMX_VMCS16_HOST_FIELD_TR %08x\n", val));
3495 if (val < gdtr.cbGdt)
3496 {
3497 pDesc = &((PX86DESCHC)gdtr.pGdt)[val >> X86_SEL_SHIFT_HC];
3498 HWACCMR0DumpDescriptor(pDesc, val, "TR: ");
3499 }
3500
3501 VMXReadVMCS(VMX_VMCS_HOST_TR_BASE, &val);
3502 Log(("VMX_VMCS_HOST_TR_BASE %RHv\n", val));
3503
3504 VMXReadVMCS(VMX_VMCS_HOST_GDTR_BASE, &val);
3505 Log(("VMX_VMCS_HOST_GDTR_BASE %RHv\n", val));
3506 VMXReadVMCS(VMX_VMCS_HOST_IDTR_BASE, &val);
3507 Log(("VMX_VMCS_HOST_IDTR_BASE %RHv\n", val));
3508
3509 VMXReadVMCS(VMX_VMCS32_HOST_SYSENTER_CS, &val);
3510 Log(("VMX_VMCS_HOST_SYSENTER_CS %08x\n", val));
3511
3512 VMXReadVMCS(VMX_VMCS_HOST_SYSENTER_EIP, &val);
3513 Log(("VMX_VMCS_HOST_SYSENTER_EIP %RHv\n", val));
3514
3515 VMXReadVMCS(VMX_VMCS_HOST_SYSENTER_ESP, &val);
3516 Log(("VMX_VMCS_HOST_SYSENTER_ESP %RHv\n", val));
3517
3518 VMXReadVMCS(VMX_VMCS_HOST_RSP, &val);
3519 Log(("VMX_VMCS_HOST_RSP %RHv\n", val));
3520 VMXReadVMCS(VMX_VMCS_HOST_RIP, &val);
3521 Log(("VMX_VMCS_HOST_RIP %RHv\n", val));
3522
3523# if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
3524 if (VMX_IS_64BIT_HOST_MODE())
3525 {
3526 Log(("MSR_K6_EFER = %RX64\n", ASMRdMsr(MSR_K6_EFER)));
3527 Log(("MSR_K6_STAR = %RX64\n", ASMRdMsr(MSR_K6_STAR)));
3528 Log(("MSR_K8_LSTAR = %RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
3529 Log(("MSR_K8_CSTAR = %RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
3530 Log(("MSR_K8_SF_MASK = %RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
3531 }
3532# endif
3533#endif /* VBOX_STRICT */
3534 }
3535 break;
3536 }
3537
3538 default:
3539 /* impossible */
3540 AssertMsgFailed(("%Rrc (%#x)\n", rc, rc));
3541 break;
3542 }
3543}
3544
3545#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
3546/**
3547 * Prepares for and executes VMLAUNCH (64 bits guest mode)
3548 *
3549 * @returns VBox status code
3550 * @param fResume vmlauch/vmresume
3551 * @param pCtx Guest context
3552 * @param pCache VMCS cache
3553 * @param pVM The VM to operate on.
3554 * @param pVCpu The VMCPU to operate on.
3555 */
3556DECLASM(int) VMXR0SwitcherStartVM64(RTHCUINT fResume, PCPUMCTX pCtx, PVMCSCACHE pCache, PVM pVM, PVMCPU pVCpu)
3557{
3558 uint32_t aParam[6];
3559 PHWACCM_CPUINFO pCpu;
3560 RTHCPHYS pPageCpuPhys;
3561 int rc;
3562
3563 pCpu = HWACCMR0GetCurrentCpu();
3564 pPageCpuPhys = RTR0MemObjGetPagePhysAddr(pCpu->pMemObj, 0);
3565
3566#ifdef DEBUG
3567 pCache->TestIn.pPageCpuPhys = 0;
3568 pCache->TestIn.pVMCSPhys = 0;
3569 pCache->TestIn.pCache = 0;
3570 pCache->TestOut.pVMCSPhys = 0;
3571 pCache->TestOut.pCache = 0;
3572 pCache->TestOut.pCtx = 0;
3573 pCache->TestOut.eflags = 0;
3574#endif
3575
3576 aParam[0] = (uint32_t)(pPageCpuPhys); /* Param 1: VMXON physical address - Lo. */
3577 aParam[1] = (uint32_t)(pPageCpuPhys >> 32); /* Param 1: VMXON physical address - Hi. */
3578 aParam[2] = (uint32_t)(pVCpu->hwaccm.s.vmx.pVMCSPhys); /* Param 2: VMCS physical address - Lo. */
3579 aParam[3] = (uint32_t)(pVCpu->hwaccm.s.vmx.pVMCSPhys >> 32); /* Param 2: VMCS physical address - Hi. */
3580 aParam[4] = VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hwaccm.s.vmx.VMCSCache);
3581 aParam[5] = 0;
3582
3583 if (pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_PREEMPT_TIMER)
3584 {
3585 uint32_t val;
3586
3587 rc = VMXReadVMCS32(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, &val);
3588 AssertRC(rc);
3589 val = val | VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_PREEMPT_TIMER;
3590 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, val);
3591 AssertRC(rc);
3592
3593 VMXWriteVMCS(VMX_VMCS32_GUEST_PREEMPTION_TIMER_VALUE, 0x10000);
3594 }
3595
3596 rc = VMXR0Execute64BitsHandler(pVM, pVCpu, pCtx, pVM->hwaccm.s.pfnVMXGCStartVM64, 6, &aParam[0]);
3597
3598 if (pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.allowed1 & VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_PREEMPT_TIMER)
3599 {
3600 uint32_t val;
3601
3602 rc = VMXReadVMCS32(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, &val);
3603 AssertRC(rc);
3604 val = val & ~VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_PREEMPT_TIMER;
3605 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, val);
3606 AssertRC(rc);
3607 }
3608
3609#ifdef DEBUG
3610 AssertMsg(pCache->TestIn.pPageCpuPhys == pPageCpuPhys, ("%RHp vs %RHp\n", pCache->TestIn.pPageCpuPhys, pPageCpuPhys));
3611 AssertMsg(pCache->TestIn.pVMCSPhys == pVCpu->hwaccm.s.vmx.pVMCSPhys, ("%RHp vs %RHp\n", pCache->TestIn.pVMCSPhys, pVCpu->hwaccm.s.vmx.pVMCSPhys));
3612 AssertMsg(pCache->TestIn.pVMCSPhys == pCache->TestOut.pVMCSPhys, ("%RHp vs %RHp\n", pCache->TestIn.pVMCSPhys, pCache->TestOut.pVMCSPhys));
3613 AssertMsg(pCache->TestIn.pCache == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache, pCache->TestOut.pCache));
3614 AssertMsg(pCache->TestIn.pCache == VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hwaccm.s.vmx.VMCSCache), ("%RGv vs %RGv\n", pCache->TestIn.pCache, VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hwaccm.s.vmx.VMCSCache)));
3615 AssertMsg(pCache->TestIn.pCtx == pCache->TestOut.pCtx, ("%RGv vs %RGv\n", pCache->TestIn.pCtx, pCache->TestOut.pCtx));
3616 Assert(!(pCache->TestOut.eflags & X86_EFL_IF));
3617#endif
3618
3619 return rc;
3620}
3621
3622/**
3623 * Executes the specified handler in 64 mode
3624 *
3625 * @returns VBox status code.
3626 * @param pVM The VM to operate on.
3627 * @param pVCpu The VMCPU to operate on.
3628 * @param pCtx Guest context
3629 * @param pfnHandler RC handler
3630 * @param cbParam Number of parameters
3631 * @param paParam Array of 32 bits parameters
3632 */
3633VMMR0DECL(int) VMXR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTRCPTR pfnHandler, uint32_t cbParam, uint32_t *paParam)
3634{
3635 int rc, rc2;
3636 PHWACCM_CPUINFO pCpu;
3637 RTHCPHYS pPageCpuPhys;
3638
3639 /* @todo This code is not guest SMP safe (hyper context) */
3640 AssertReturn(pVM->cCPUs == 1, VERR_ACCESS_DENIED);
3641 AssertReturn(pVM->hwaccm.s.pfnHost32ToGuest64R0, VERR_INTERNAL_ERROR);
3642 Assert(pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries <= RT_ELEMENTS(pVCpu->hwaccm.s.vmx.VMCSCache.Write.aField));
3643 Assert(pVCpu->hwaccm.s.vmx.VMCSCache.Read.cValidEntries <= RT_ELEMENTS(pVCpu->hwaccm.s.vmx.VMCSCache.Read.aField));
3644
3645#ifdef VBOX_STRICT
3646 for (unsigned i=0;i<pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries;i++)
3647 Assert(vmxR0IsValidWriteField(pVCpu->hwaccm.s.vmx.VMCSCache.Write.aField[i]));
3648
3649 for (unsigned i=0;i<pVCpu->hwaccm.s.vmx.VMCSCache.Read.cValidEntries;i++)
3650 Assert(vmxR0IsValidReadField(pVCpu->hwaccm.s.vmx.VMCSCache.Read.aField[i]));
3651#endif
3652
3653 pCpu = HWACCMR0GetCurrentCpu();
3654 pPageCpuPhys = RTR0MemObjGetPagePhysAddr(pCpu->pMemObj, 0);
3655
3656 /* Clear VM Control Structure. Marking it inactive, clearing implementation specific data and writing back VMCS data to memory. */
3657 VMXClearVMCS(pVCpu->hwaccm.s.vmx.pVMCSPhys);
3658
3659 /* Leave VMX Root Mode. */
3660 VMXDisable();
3661
3662 CPUMSetHyperESP(pVM, VMMGetStackRC(pVM));
3663 CPUMSetHyperEIP(pVM, pfnHandler);
3664 for (int i=(int)cbParam-1;i>=0;i--)
3665 CPUMPushHyper(pVM, paParam[i]);
3666
3667 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatWorldSwitch3264, z);
3668 /* Call switcher. */
3669 rc = pVM->hwaccm.s.pfnHost32ToGuest64R0(pVM);
3670 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatWorldSwitch3264, z);
3671
3672 /* Make sure the VMX instructions don't cause #UD faults. */
3673 ASMSetCR4(ASMGetCR4() | X86_CR4_VMXE);
3674
3675 /* Enter VMX Root Mode */
3676 rc2 = VMXEnable(pPageCpuPhys);
3677 if (RT_FAILURE(rc2))
3678 {
3679 if (pVM)
3680 VMXR0CheckError(pVM, pVCpu, rc2);
3681 ASMSetCR4(ASMGetCR4() & ~X86_CR4_VMXE);
3682 return VERR_VMX_VMXON_FAILED;
3683 }
3684
3685 VMXActivateVMCS(pVCpu->hwaccm.s.vmx.pVMCSPhys);
3686#ifdef RT_OS_WINDOWS
3687 Assert(ASMGetFlags() & X86_EFL_IF);
3688#else
3689 Assert(!(ASMGetFlags() & X86_EFL_IF));
3690#endif
3691 return rc;
3692}
3693
3694#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL) */
3695
3696
3697#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
3698/**
3699 * Executes VMWRITE
3700 *
3701 * @returns VBox status code
3702 * @param pVCpu The VMCPU to operate on.
3703 * @param idxField VMCS index
3704 * @param u64Val 16, 32 or 64 bits value
3705 */
3706VMMR0DECL(int) VMXWriteVMCS64Ex(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
3707{
3708 int rc;
3709
3710 switch (idxField)
3711 {
3712 case VMX_VMCS_CTRL_TSC_OFFSET_FULL:
3713 case VMX_VMCS_CTRL_IO_BITMAP_A_FULL:
3714 case VMX_VMCS_CTRL_IO_BITMAP_B_FULL:
3715 case VMX_VMCS_CTRL_MSR_BITMAP_FULL:
3716 case VMX_VMCS_CTRL_VMEXIT_MSR_STORE_FULL:
3717 case VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_FULL:
3718 case VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_FULL:
3719 case VMX_VMCS_CTRL_VAPIC_PAGEADDR_FULL:
3720 case VMX_VMCS_GUEST_LINK_PTR_FULL:
3721 case VMX_VMCS_GUEST_PDPTR0_FULL:
3722 case VMX_VMCS_GUEST_PDPTR1_FULL:
3723 case VMX_VMCS_GUEST_PDPTR2_FULL:
3724 case VMX_VMCS_GUEST_PDPTR3_FULL:
3725 case VMX_VMCS_GUEST_DEBUGCTL_FULL:
3726 case VMX_VMCS_GUEST_EFER_FULL:
3727 case VMX_VMCS_CTRL_EPTP_FULL:
3728 /* These fields consist of two parts, which are both writable in 32 bits mode. */
3729 rc = VMXWriteVMCS32(idxField, u64Val);
3730 rc |= VMXWriteVMCS32(idxField + 1, (uint32_t)(u64Val >> 32ULL));
3731 AssertRC(rc);
3732 return rc;
3733
3734 case VMX_VMCS64_GUEST_LDTR_BASE:
3735 case VMX_VMCS64_GUEST_TR_BASE:
3736 case VMX_VMCS64_GUEST_GDTR_BASE:
3737 case VMX_VMCS64_GUEST_IDTR_BASE:
3738 case VMX_VMCS64_GUEST_SYSENTER_EIP:
3739 case VMX_VMCS64_GUEST_SYSENTER_ESP:
3740 case VMX_VMCS64_GUEST_CR0:
3741 case VMX_VMCS64_GUEST_CR4:
3742 case VMX_VMCS64_GUEST_CR3:
3743 case VMX_VMCS64_GUEST_DR7:
3744 case VMX_VMCS64_GUEST_RIP:
3745 case VMX_VMCS64_GUEST_RSP:
3746 case VMX_VMCS64_GUEST_CS_BASE:
3747 case VMX_VMCS64_GUEST_DS_BASE:
3748 case VMX_VMCS64_GUEST_ES_BASE:
3749 case VMX_VMCS64_GUEST_FS_BASE:
3750 case VMX_VMCS64_GUEST_GS_BASE:
3751 case VMX_VMCS64_GUEST_SS_BASE:
3752 /* Queue a 64 bits value as we can't set it in 32 bits host mode. */
3753 if (u64Val >> 32ULL)
3754 rc = VMXWriteCachedVMCSEx(pVCpu, idxField, u64Val);
3755 else
3756 rc = VMXWriteVMCS32(idxField, (uint32_t)u64Val);
3757
3758 return rc;
3759
3760 default:
3761 AssertMsgFailed(("Unexpected field %x\n", idxField));
3762 return VERR_INVALID_PARAMETER;
3763 }
3764}
3765
3766/**
3767 * Cache VMCS writes for performance reasons (Darwin) and for running 64 bits guests on 32 bits hosts.
3768 *
3769 * @param pVCpu The VMCPU to operate on.
3770 * @param idxField VMCS field
3771 * @param u64Val Value
3772 */
3773VMMR0DECL(int) VMXWriteCachedVMCSEx(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
3774{
3775 PVMCSCACHE pCache = &pVCpu->hwaccm.s.vmx.VMCSCache;
3776
3777 AssertMsgReturn(pCache->Write.cValidEntries < VMCSCACHE_MAX_ENTRY - 1, ("entries=%x\n", pCache->Write.cValidEntries), VERR_ACCESS_DENIED);
3778
3779 /* Make sure there are no duplicates. */
3780 for (unsigned i=0;i<pCache->Write.cValidEntries;i++)
3781 {
3782 if (pCache->Write.aField[i] == idxField)
3783 {
3784 pCache->Write.aFieldVal[i] = u64Val;
3785 return VINF_SUCCESS;
3786 }
3787 }
3788
3789 pCache->Write.aField[pCache->Write.cValidEntries] = idxField;
3790 pCache->Write.aFieldVal[pCache->Write.cValidEntries] = u64Val;
3791 pCache->Write.cValidEntries++;
3792 return VINF_SUCCESS;
3793}
3794
3795#endif /* HC_ARCH_BITS == 32 && !VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
3796
3797#ifdef VBOX_STRICT
3798static bool vmxR0IsValidReadField(uint32_t idxField)
3799{
3800 switch(idxField)
3801 {
3802 case VMX_VMCS64_GUEST_RIP:
3803 case VMX_VMCS64_GUEST_RSP:
3804 case VMX_VMCS_GUEST_RFLAGS:
3805 case VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE:
3806 case VMX_VMCS_CTRL_CR0_READ_SHADOW:
3807 case VMX_VMCS64_GUEST_CR0:
3808 case VMX_VMCS_CTRL_CR4_READ_SHADOW:
3809 case VMX_VMCS64_GUEST_CR4:
3810 case VMX_VMCS64_GUEST_DR7:
3811 case VMX_VMCS32_GUEST_SYSENTER_CS:
3812 case VMX_VMCS64_GUEST_SYSENTER_EIP:
3813 case VMX_VMCS64_GUEST_SYSENTER_ESP:
3814 case VMX_VMCS32_GUEST_GDTR_LIMIT:
3815 case VMX_VMCS64_GUEST_GDTR_BASE:
3816 case VMX_VMCS32_GUEST_IDTR_LIMIT:
3817 case VMX_VMCS64_GUEST_IDTR_BASE:
3818 case VMX_VMCS16_GUEST_FIELD_CS:
3819 case VMX_VMCS32_GUEST_CS_LIMIT:
3820 case VMX_VMCS64_GUEST_CS_BASE:
3821 case VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS:
3822 case VMX_VMCS16_GUEST_FIELD_DS:
3823 case VMX_VMCS32_GUEST_DS_LIMIT:
3824 case VMX_VMCS64_GUEST_DS_BASE:
3825 case VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS:
3826 case VMX_VMCS16_GUEST_FIELD_ES:
3827 case VMX_VMCS32_GUEST_ES_LIMIT:
3828 case VMX_VMCS64_GUEST_ES_BASE:
3829 case VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS:
3830 case VMX_VMCS16_GUEST_FIELD_FS:
3831 case VMX_VMCS32_GUEST_FS_LIMIT:
3832 case VMX_VMCS64_GUEST_FS_BASE:
3833 case VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS:
3834 case VMX_VMCS16_GUEST_FIELD_GS:
3835 case VMX_VMCS32_GUEST_GS_LIMIT:
3836 case VMX_VMCS64_GUEST_GS_BASE:
3837 case VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS:
3838 case VMX_VMCS16_GUEST_FIELD_SS:
3839 case VMX_VMCS32_GUEST_SS_LIMIT:
3840 case VMX_VMCS64_GUEST_SS_BASE:
3841 case VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS:
3842 case VMX_VMCS16_GUEST_FIELD_LDTR:
3843 case VMX_VMCS32_GUEST_LDTR_LIMIT:
3844 case VMX_VMCS64_GUEST_LDTR_BASE:
3845 case VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS:
3846 case VMX_VMCS16_GUEST_FIELD_TR:
3847 case VMX_VMCS32_GUEST_TR_LIMIT:
3848 case VMX_VMCS64_GUEST_TR_BASE:
3849 case VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS:
3850 case VMX_VMCS32_RO_EXIT_REASON:
3851 case VMX_VMCS32_RO_VM_INSTR_ERROR:
3852 case VMX_VMCS32_RO_EXIT_INSTR_LENGTH:
3853 case VMX_VMCS32_RO_EXIT_INTERRUPTION_ERRCODE:
3854 case VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO:
3855 case VMX_VMCS32_RO_EXIT_INSTR_INFO:
3856 case VMX_VMCS_RO_EXIT_QUALIFICATION:
3857 case VMX_VMCS32_RO_IDT_INFO:
3858 case VMX_VMCS32_RO_IDT_ERRCODE:
3859 case VMX_VMCS64_GUEST_CR3:
3860 case VMX_VMCS_EXIT_PHYS_ADDR_FULL:
3861 return true;
3862 }
3863 return false;
3864}
3865
3866static bool vmxR0IsValidWriteField(uint32_t idxField)
3867{
3868 switch(idxField)
3869 {
3870 case VMX_VMCS64_GUEST_LDTR_BASE:
3871 case VMX_VMCS64_GUEST_TR_BASE:
3872 case VMX_VMCS64_GUEST_GDTR_BASE:
3873 case VMX_VMCS64_GUEST_IDTR_BASE:
3874 case VMX_VMCS64_GUEST_SYSENTER_EIP:
3875 case VMX_VMCS64_GUEST_SYSENTER_ESP:
3876 case VMX_VMCS64_GUEST_CR0:
3877 case VMX_VMCS64_GUEST_CR4:
3878 case VMX_VMCS64_GUEST_CR3:
3879 case VMX_VMCS64_GUEST_DR7:
3880 case VMX_VMCS64_GUEST_RIP:
3881 case VMX_VMCS64_GUEST_RSP:
3882 case VMX_VMCS64_GUEST_CS_BASE:
3883 case VMX_VMCS64_GUEST_DS_BASE:
3884 case VMX_VMCS64_GUEST_ES_BASE:
3885 case VMX_VMCS64_GUEST_FS_BASE:
3886 case VMX_VMCS64_GUEST_GS_BASE:
3887 case VMX_VMCS64_GUEST_SS_BASE:
3888 return true;
3889 }
3890 return false;
3891}
3892
3893#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette