VirtualBox

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

Last change on this file since 41939 was 41939, checked in by vboxsync, 13 years ago

CPUMGetGuestCPL: Drop the context core pointer and use the Guest state in CPUMCPU via pVCpu.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 216.0 KB
Line 
1/* $Id: HWVMXR0.cpp 41939 2012-06-27 23:59:46Z vboxsync $ */
2/** @file
3 * HM VMX (VT-x) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_HWACCM
23#include <iprt/asm-amd64-x86.h>
24#include <VBox/vmm/hwaccm.h>
25#include <VBox/vmm/pgm.h>
26#include <VBox/vmm/dbgf.h>
27#include <VBox/vmm/dbgftrace.h>
28#include <VBox/vmm/selm.h>
29#include <VBox/vmm/iom.h>
30#ifdef VBOX_WITH_REM
31# include <VBox/vmm/rem.h>
32#endif
33#include <VBox/vmm/tm.h>
34#include "HWACCMInternal.h"
35#include <VBox/vmm/vm.h>
36#include <VBox/vmm/pdmapi.h>
37#include <VBox/err.h>
38#include <VBox/log.h>
39#include <iprt/assert.h>
40#include <iprt/param.h>
41#include <iprt/string.h>
42#include <iprt/time.h>
43#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
44# include <iprt/thread.h>
45#endif
46#include <iprt/x86.h>
47#include "HWVMXR0.h"
48
49#include "dtrace/VBoxVMM.h"
50
51
52/*******************************************************************************
53* Defined Constants And Macros *
54*******************************************************************************/
55#if defined(RT_ARCH_AMD64)
56# define VMX_IS_64BIT_HOST_MODE() (true)
57#elif defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
58# define VMX_IS_64BIT_HOST_MODE() (g_fVMXIs64bitHost != 0)
59#else
60# define VMX_IS_64BIT_HOST_MODE() (false)
61#endif
62
63
64/*******************************************************************************
65* Global Variables *
66*******************************************************************************/
67/* IO operation lookup arrays. */
68static uint32_t const g_aIOSize[4] = {1, 2, 0, 4};
69static uint32_t const g_aIOOpAnd[4] = {0xff, 0xffff, 0, 0xffffffff};
70
71#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
72/** See HWACCMR0A.asm. */
73extern "C" uint32_t g_fVMXIs64bitHost;
74#endif
75
76
77/*******************************************************************************
78* Local Functions *
79*******************************************************************************/
80static DECLCALLBACK(void) hmR0VmxSetupTLBEPT(PVM pVM, PVMCPU pVCpu);
81static DECLCALLBACK(void) hmR0VmxSetupTLBVPID(PVM pVM, PVMCPU pVCpu);
82static DECLCALLBACK(void) hmR0VmxSetupTLBBoth(PVM pVM, PVMCPU pVCpu);
83static DECLCALLBACK(void) hmR0VmxSetupTLBDummy(PVM pVM, PVMCPU pVCpu);
84static void hmR0VmxFlushEPT(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_EPT enmFlush);
85static void hmR0VmxFlushVPID(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_VPID enmFlush, RTGCPTR GCPtr);
86static void hmR0VmxUpdateExceptionBitmap(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx);
87static void hmR0VmxSetMSRPermission(PVMCPU pVCpu, unsigned ulMSR, bool fRead, bool fWrite);
88static void hmR0VmxReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rc, PCPUMCTX pCtx);
89
90
91/**
92 * Updates error from VMCS to HWACCMCPU's lasterror record.
93 *
94 * @param pVM Pointer to the VM.
95 * @param pVCpu Pointer to the VMCPU.
96 * @param rc The error code.
97 */
98static void hmR0VmxCheckError(PVM pVM, PVMCPU pVCpu, int rc)
99{
100 if (rc == VERR_VMX_GENERIC)
101 {
102 RTCCUINTREG instrError;
103
104 VMXReadVMCS(VMX_VMCS32_RO_VM_INSTR_ERROR, &instrError);
105 pVCpu->hwaccm.s.vmx.lasterror.ulInstrError = instrError;
106 }
107 pVM->hwaccm.s.lLastError = rc;
108}
109
110
111/**
112 * Sets up and activates VT-x on the current CPU.
113 *
114 * @returns VBox status code.
115 * @param pCpu Pointer to the CPU info struct.
116 * @param pVM Pointer to the VM. (can be NULL after a resume!!)
117 * @param pvCpuPage Pointer to the global CPU page.
118 * @param HCPhysCpuPage Physical address of the global CPU page.
119 */
120VMMR0DECL(int) VMXR0EnableCpu(PHMGLOBLCPUINFO pCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
121{
122 AssertReturn(HCPhysCpuPage != 0 && HCPhysCpuPage != NIL_RTHCPHYS, VERR_INVALID_PARAMETER);
123 AssertReturn(pvCpuPage, VERR_INVALID_PARAMETER);
124
125 if (pVM)
126 {
127 /* Set revision dword at the beginning of the VMXON structure. */
128 *(uint32_t *)pvCpuPage = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hwaccm.s.vmx.msr.vmx_basic_info);
129 }
130
131 /** @todo we should unmap the two pages from the virtual address space in order to prevent accidental corruption.
132 * (which can have very bad consequences!!!)
133 */
134
135 if (ASMGetCR4() & X86_CR4_VMXE)
136 return VERR_VMX_IN_VMX_ROOT_MODE;
137
138 ASMSetCR4(ASMGetCR4() | X86_CR4_VMXE); /* Make sure the VMX instructions don't cause #UD faults. */
139
140 /*
141 * Enter VM root mode.
142 */
143 int rc = VMXEnable(HCPhysCpuPage);
144 if (RT_FAILURE(rc))
145 {
146 ASMSetCR4(ASMGetCR4() & ~X86_CR4_VMXE);
147 return VERR_VMX_VMXON_FAILED;
148 }
149
150 /*
151 * Flush all VPIDs (in case we or any other hypervisor have been using VPIDs) so that
152 * we can avoid an explicit flush while using new VPIDs. We would still need to flush
153 * each time while reusing a VPID after hitting the MaxASID limit once.
154 */
155 if ( pVM
156 && pVM->hwaccm.s.vmx.fVPID
157 && (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_ALL_CONTEXTS))
158 {
159 hmR0VmxFlushVPID(pVM, NULL /* pvCpu */, VMX_FLUSH_VPID_ALL_CONTEXTS, 0 /* GCPtr */);
160 pCpu->fFlushASIDBeforeUse = false;
161 }
162 else
163 pCpu->fFlushASIDBeforeUse = true;
164
165 /*
166 * Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}.
167 */
168 pCpu->cTLBFlushes++;
169
170 return VINF_SUCCESS;
171}
172
173
174/**
175 * Deactivates VT-x on the current CPU.
176 *
177 * @returns VBox status code.
178 * @param pCpu Pointer to the CPU info struct.
179 * @param pvCpuPage Pointer to the global CPU page.
180 * @param HCPhysCpuPage Physical address of the global CPU page.
181 */
182VMMR0DECL(int) VMXR0DisableCpu(PHMGLOBLCPUINFO pCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
183{
184 AssertReturn(HCPhysCpuPage != 0 && HCPhysCpuPage != NIL_RTHCPHYS, VERR_INVALID_PARAMETER);
185 AssertReturn(pvCpuPage, VERR_INVALID_PARAMETER);
186 NOREF(pCpu);
187
188 /* If we're somehow not in VMX root mode, then we shouldn't dare leaving it. */
189 if (!(ASMGetCR4() & X86_CR4_VMXE))
190 return VERR_VMX_NOT_IN_VMX_ROOT_MODE;
191
192 /* Leave VMX Root Mode. */
193 VMXDisable();
194
195 /* And clear the X86_CR4_VMXE bit. */
196 ASMSetCR4(ASMGetCR4() & ~X86_CR4_VMXE);
197 return VINF_SUCCESS;
198}
199
200
201/**
202 * Does Ring-0 per VM VT-x initialization.
203 *
204 * @returns VBox status code.
205 * @param pVM Pointer to the VM.
206 */
207VMMR0DECL(int) VMXR0InitVM(PVM pVM)
208{
209 int rc;
210
211#ifdef LOG_ENABLED
212 SUPR0Printf("VMXR0InitVM %x\n", pVM);
213#endif
214
215 pVM->hwaccm.s.vmx.pMemObjAPIC = NIL_RTR0MEMOBJ;
216
217 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW)
218 {
219 /* Allocate one page for the APIC physical page (serves for filtering accesses). */
220 rc = RTR0MemObjAllocCont(&pVM->hwaccm.s.vmx.pMemObjAPIC, PAGE_SIZE, true /* executable R0 mapping */);
221 AssertRC(rc);
222 if (RT_FAILURE(rc))
223 return rc;
224
225 pVM->hwaccm.s.vmx.pAPIC = (uint8_t *)RTR0MemObjAddress(pVM->hwaccm.s.vmx.pMemObjAPIC);
226 pVM->hwaccm.s.vmx.pAPICPhys = RTR0MemObjGetPagePhysAddr(pVM->hwaccm.s.vmx.pMemObjAPIC, 0);
227 ASMMemZero32(pVM->hwaccm.s.vmx.pAPIC, PAGE_SIZE);
228 }
229 else
230 {
231 pVM->hwaccm.s.vmx.pMemObjAPIC = 0;
232 pVM->hwaccm.s.vmx.pAPIC = 0;
233 pVM->hwaccm.s.vmx.pAPICPhys = 0;
234 }
235
236#ifdef VBOX_WITH_CRASHDUMP_MAGIC
237 {
238 rc = RTR0MemObjAllocCont(&pVM->hwaccm.s.vmx.pMemObjScratch, PAGE_SIZE, true /* executable R0 mapping */);
239 AssertRC(rc);
240 if (RT_FAILURE(rc))
241 return rc;
242
243 pVM->hwaccm.s.vmx.pScratch = (uint8_t *)RTR0MemObjAddress(pVM->hwaccm.s.vmx.pMemObjScratch);
244 pVM->hwaccm.s.vmx.pScratchPhys = RTR0MemObjGetPagePhysAddr(pVM->hwaccm.s.vmx.pMemObjScratch, 0);
245
246 ASMMemZero32(pVM->hwaccm.s.vmx.pScratch, PAGE_SIZE);
247 strcpy((char *)pVM->hwaccm.s.vmx.pScratch, "SCRATCH Magic");
248 *(uint64_t *)(pVM->hwaccm.s.vmx.pScratch + 16) = UINT64_C(0xDEADBEEFDEADBEEF);
249 }
250#endif
251
252 /* Allocate VMCSs for all guest CPUs. */
253 for (VMCPUID i = 0; i < pVM->cCpus; i++)
254 {
255 PVMCPU pVCpu = &pVM->aCpus[i];
256
257 pVCpu->hwaccm.s.vmx.hMemObjVMCS = NIL_RTR0MEMOBJ;
258
259 /* Allocate one page for the VM control structure (VMCS). */
260 rc = RTR0MemObjAllocCont(&pVCpu->hwaccm.s.vmx.hMemObjVMCS, PAGE_SIZE, true /* executable R0 mapping */);
261 AssertRC(rc);
262 if (RT_FAILURE(rc))
263 return rc;
264
265 pVCpu->hwaccm.s.vmx.pvVMCS = RTR0MemObjAddress(pVCpu->hwaccm.s.vmx.hMemObjVMCS);
266 pVCpu->hwaccm.s.vmx.HCPhysVMCS = RTR0MemObjGetPagePhysAddr(pVCpu->hwaccm.s.vmx.hMemObjVMCS, 0);
267 ASMMemZeroPage(pVCpu->hwaccm.s.vmx.pvVMCS);
268
269 pVCpu->hwaccm.s.vmx.cr0_mask = 0;
270 pVCpu->hwaccm.s.vmx.cr4_mask = 0;
271
272 /* Allocate one page for the virtual APIC page for TPR caching. */
273 rc = RTR0MemObjAllocCont(&pVCpu->hwaccm.s.vmx.hMemObjVAPIC, PAGE_SIZE, true /* executable R0 mapping */);
274 AssertRC(rc);
275 if (RT_FAILURE(rc))
276 return rc;
277
278 pVCpu->hwaccm.s.vmx.pbVAPIC = (uint8_t *)RTR0MemObjAddress(pVCpu->hwaccm.s.vmx.hMemObjVAPIC);
279 pVCpu->hwaccm.s.vmx.HCPhysVAPIC = RTR0MemObjGetPagePhysAddr(pVCpu->hwaccm.s.vmx.hMemObjVAPIC, 0);
280 ASMMemZeroPage(pVCpu->hwaccm.s.vmx.pbVAPIC);
281
282 /* Allocate the MSR bitmap if this feature is supported. */
283 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_MSR_BITMAPS)
284 {
285 rc = RTR0MemObjAllocCont(&pVCpu->hwaccm.s.vmx.pMemObjMSRBitmap, PAGE_SIZE, true /* executable R0 mapping */);
286 AssertRC(rc);
287 if (RT_FAILURE(rc))
288 return rc;
289
290 pVCpu->hwaccm.s.vmx.pMSRBitmap = (uint8_t *)RTR0MemObjAddress(pVCpu->hwaccm.s.vmx.pMemObjMSRBitmap);
291 pVCpu->hwaccm.s.vmx.pMSRBitmapPhys = RTR0MemObjGetPagePhysAddr(pVCpu->hwaccm.s.vmx.pMemObjMSRBitmap, 0);
292 memset(pVCpu->hwaccm.s.vmx.pMSRBitmap, 0xff, PAGE_SIZE);
293 }
294
295#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
296 /* Allocate one page for the guest MSR load area (for preloading guest MSRs during the world switch). */
297 rc = RTR0MemObjAllocCont(&pVCpu->hwaccm.s.vmx.pMemObjGuestMSR, PAGE_SIZE, true /* executable R0 mapping */);
298 AssertRC(rc);
299 if (RT_FAILURE(rc))
300 return rc;
301
302 pVCpu->hwaccm.s.vmx.pGuestMSR = (uint8_t *)RTR0MemObjAddress(pVCpu->hwaccm.s.vmx.pMemObjGuestMSR);
303 pVCpu->hwaccm.s.vmx.pGuestMSRPhys = RTR0MemObjGetPagePhysAddr(pVCpu->hwaccm.s.vmx.pMemObjGuestMSR, 0);
304 memset(pVCpu->hwaccm.s.vmx.pGuestMSR, 0, PAGE_SIZE);
305
306 /* Allocate one page for the host MSR load area (for restoring host MSRs after the world switch back). */
307 rc = RTR0MemObjAllocCont(&pVCpu->hwaccm.s.vmx.pMemObjHostMSR, PAGE_SIZE, true /* executable R0 mapping */);
308 AssertRC(rc);
309 if (RT_FAILURE(rc))
310 return rc;
311
312 pVCpu->hwaccm.s.vmx.pHostMSR = (uint8_t *)RTR0MemObjAddress(pVCpu->hwaccm.s.vmx.pMemObjHostMSR);
313 pVCpu->hwaccm.s.vmx.pHostMSRPhys = RTR0MemObjGetPagePhysAddr(pVCpu->hwaccm.s.vmx.pMemObjHostMSR, 0);
314 memset(pVCpu->hwaccm.s.vmx.pHostMSR, 0, PAGE_SIZE);
315#endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
316
317 /* Current guest paging mode. */
318 pVCpu->hwaccm.s.vmx.enmLastSeenGuestMode = PGMMODE_REAL;
319
320#ifdef LOG_ENABLED
321 SUPR0Printf("VMXR0InitVM %x VMCS=%x (%x)\n", pVM, pVCpu->hwaccm.s.vmx.pvVMCS, (uint32_t)pVCpu->hwaccm.s.vmx.HCPhysVMCS);
322#endif
323 }
324
325 return VINF_SUCCESS;
326}
327
328
329/**
330 * Does Ring-0 per VM VT-x termination.
331 *
332 * @returns VBox status code.
333 * @param pVM Pointer to the VM.
334 */
335VMMR0DECL(int) VMXR0TermVM(PVM pVM)
336{
337 for (VMCPUID i = 0; i < pVM->cCpus; i++)
338 {
339 PVMCPU pVCpu = &pVM->aCpus[i];
340
341 if (pVCpu->hwaccm.s.vmx.hMemObjVMCS != NIL_RTR0MEMOBJ)
342 {
343 RTR0MemObjFree(pVCpu->hwaccm.s.vmx.hMemObjVMCS, false);
344 pVCpu->hwaccm.s.vmx.hMemObjVMCS = NIL_RTR0MEMOBJ;
345 pVCpu->hwaccm.s.vmx.pvVMCS = 0;
346 pVCpu->hwaccm.s.vmx.HCPhysVMCS = 0;
347 }
348 if (pVCpu->hwaccm.s.vmx.hMemObjVAPIC != NIL_RTR0MEMOBJ)
349 {
350 RTR0MemObjFree(pVCpu->hwaccm.s.vmx.hMemObjVAPIC, false);
351 pVCpu->hwaccm.s.vmx.hMemObjVAPIC = NIL_RTR0MEMOBJ;
352 pVCpu->hwaccm.s.vmx.pbVAPIC = 0;
353 pVCpu->hwaccm.s.vmx.HCPhysVAPIC = 0;
354 }
355 if (pVCpu->hwaccm.s.vmx.pMemObjMSRBitmap != NIL_RTR0MEMOBJ)
356 {
357 RTR0MemObjFree(pVCpu->hwaccm.s.vmx.pMemObjMSRBitmap, false);
358 pVCpu->hwaccm.s.vmx.pMemObjMSRBitmap = NIL_RTR0MEMOBJ;
359 pVCpu->hwaccm.s.vmx.pMSRBitmap = 0;
360 pVCpu->hwaccm.s.vmx.pMSRBitmapPhys = 0;
361 }
362#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
363 if (pVCpu->hwaccm.s.vmx.pMemObjHostMSR != NIL_RTR0MEMOBJ)
364 {
365 RTR0MemObjFree(pVCpu->hwaccm.s.vmx.pMemObjHostMSR, false);
366 pVCpu->hwaccm.s.vmx.pMemObjHostMSR = NIL_RTR0MEMOBJ;
367 pVCpu->hwaccm.s.vmx.pHostMSR = 0;
368 pVCpu->hwaccm.s.vmx.pHostMSRPhys = 0;
369 }
370 if (pVCpu->hwaccm.s.vmx.pMemObjGuestMSR != NIL_RTR0MEMOBJ)
371 {
372 RTR0MemObjFree(pVCpu->hwaccm.s.vmx.pMemObjGuestMSR, false);
373 pVCpu->hwaccm.s.vmx.pMemObjGuestMSR = NIL_RTR0MEMOBJ;
374 pVCpu->hwaccm.s.vmx.pGuestMSR = 0;
375 pVCpu->hwaccm.s.vmx.pGuestMSRPhys = 0;
376 }
377#endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
378 }
379 if (pVM->hwaccm.s.vmx.pMemObjAPIC != NIL_RTR0MEMOBJ)
380 {
381 RTR0MemObjFree(pVM->hwaccm.s.vmx.pMemObjAPIC, false);
382 pVM->hwaccm.s.vmx.pMemObjAPIC = NIL_RTR0MEMOBJ;
383 pVM->hwaccm.s.vmx.pAPIC = 0;
384 pVM->hwaccm.s.vmx.pAPICPhys = 0;
385 }
386#ifdef VBOX_WITH_CRASHDUMP_MAGIC
387 if (pVM->hwaccm.s.vmx.pMemObjScratch != NIL_RTR0MEMOBJ)
388 {
389 ASMMemZero32(pVM->hwaccm.s.vmx.pScratch, PAGE_SIZE);
390 RTR0MemObjFree(pVM->hwaccm.s.vmx.pMemObjScratch, false);
391 pVM->hwaccm.s.vmx.pMemObjScratch = NIL_RTR0MEMOBJ;
392 pVM->hwaccm.s.vmx.pScratch = 0;
393 pVM->hwaccm.s.vmx.pScratchPhys = 0;
394 }
395#endif
396 return VINF_SUCCESS;
397}
398
399
400/**
401 * Sets up VT-x for the specified VM.
402 *
403 * @returns VBox status code.
404 * @param pVM Pointer to the VM.
405 */
406VMMR0DECL(int) VMXR0SetupVM(PVM pVM)
407{
408 int rc = VINF_SUCCESS;
409 uint32_t val;
410
411 AssertReturn(pVM, VERR_INVALID_PARAMETER);
412
413 /* Initialize these always, see hwaccmR3InitFinalizeR0().*/
414 pVM->hwaccm.s.vmx.enmFlushEPT = VMX_FLUSH_EPT_NONE;
415 pVM->hwaccm.s.vmx.enmFlushVPID = VMX_FLUSH_VPID_NONE;
416
417 /* Determine optimal flush type for EPT. */
418 if (pVM->hwaccm.s.fNestedPaging)
419 {
420 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVEPT_CAPS_SINGLE_CONTEXT)
421 pVM->hwaccm.s.vmx.enmFlushEPT = VMX_FLUSH_EPT_SINGLE_CONTEXT;
422 else if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVEPT_CAPS_ALL_CONTEXTS)
423 pVM->hwaccm.s.vmx.enmFlushEPT = VMX_FLUSH_EPT_ALL_CONTEXTS;
424 else
425 {
426 /*
427 * Should never really happen. EPT is supported but no suitable flush types supported.
428 * We cannot ignore EPT at this point as we've already setup Unrestricted Guest execution.
429 */
430 pVM->hwaccm.s.vmx.enmFlushEPT = VMX_FLUSH_EPT_NOT_SUPPORTED;
431 return VERR_VMX_GENERIC;
432 }
433 }
434
435 /* Determine optimal flush type for VPID. */
436 if (pVM->hwaccm.s.vmx.fVPID)
437 {
438 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_SINGLE_CONTEXT)
439 pVM->hwaccm.s.vmx.enmFlushVPID = VMX_FLUSH_VPID_SINGLE_CONTEXT;
440 else if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_ALL_CONTEXTS)
441 pVM->hwaccm.s.vmx.enmFlushVPID = VMX_FLUSH_VPID_ALL_CONTEXTS;
442 else
443 {
444 /*
445 * Neither SINGLE nor ALL context flush types for VPID supported by the CPU.
446 * We do not handle other flush type combinations, ignore VPID capabilities.
447 */
448 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_INDIV_ADDR)
449 Log(("VMXR0SetupVM: Only VMX_FLUSH_VPID_INDIV_ADDR supported. Ignoring VPID.\n"));
450 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_SINGLE_CONTEXT_RETAIN_GLOBALS)
451 Log(("VMXR0SetupVM: Only VMX_FLUSH_VPID_SINGLE_CONTEXT_RETAIN_GLOBALS supported. Ignoring VPID.\n"));
452 pVM->hwaccm.s.vmx.enmFlushVPID = VMX_FLUSH_VPID_NOT_SUPPORTED;
453 pVM->hwaccm.s.vmx.fVPID = false;
454 }
455 }
456
457 for (VMCPUID i = 0; i < pVM->cCpus; i++)
458 {
459 PVMCPU pVCpu = &pVM->aCpus[i];
460
461 AssertPtr(pVCpu->hwaccm.s.vmx.pvVMCS);
462
463 /* Set revision dword at the beginning of the VMCS structure. */
464 *(uint32_t *)pVCpu->hwaccm.s.vmx.pvVMCS = MSR_IA32_VMX_BASIC_INFO_VMCS_ID(pVM->hwaccm.s.vmx.msr.vmx_basic_info);
465
466 /*
467 * Clear and activate the VMCS.
468 */
469 Log(("HCPhysVMCS = %RHp\n", pVCpu->hwaccm.s.vmx.HCPhysVMCS));
470 rc = VMXClearVMCS(pVCpu->hwaccm.s.vmx.HCPhysVMCS);
471 if (RT_FAILURE(rc))
472 goto vmx_end;
473
474 rc = VMXActivateVMCS(pVCpu->hwaccm.s.vmx.HCPhysVMCS);
475 if (RT_FAILURE(rc))
476 goto vmx_end;
477
478 /*
479 * VMX_VMCS_CTRL_PIN_EXEC_CONTROLS
480 * Set required bits to one and zero according to the MSR capabilities.
481 */
482 val = pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.disallowed0;
483 val |= VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_EXT_INT_EXIT /* External interrupts */
484 | VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_NMI_EXIT; /* Non-maskable interrupts */
485
486 /*
487 * Enable the VMX preemption timer.
488 */
489 if (pVM->hwaccm.s.vmx.fUsePreemptTimer)
490 val |= VMX_VMCS_CTRL_PIN_EXEC_CONTROLS_PREEMPT_TIMER;
491 val &= pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.allowed1;
492
493 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, val);
494 AssertRC(rc);
495
496 /*
497 * VMX_VMCS_CTRL_PROC_EXEC_CONTROLS
498 * Set required bits to one and zero according to the MSR capabilities.
499 */
500 val = pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.disallowed0;
501 /* Program which event cause VM-exits and which features we want to use. */
502 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_HLT_EXIT
503 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_TSC_OFFSET
504 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT
505 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_UNCOND_IO_EXIT
506 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDPMC_EXIT
507 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MONITOR_EXIT
508 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MWAIT_EXIT; /* don't execute mwait or else we'll idle inside
509 the guest (host thinks the cpu load is high) */
510
511 /* Without nested paging we should intercept invlpg and cr3 mov instructions. */
512 if (!pVM->hwaccm.s.fNestedPaging)
513 {
514 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INVLPG_EXIT
515 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_LOAD_EXIT
516 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_STORE_EXIT;
517 }
518
519 /*
520 * VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MWAIT_EXIT might cause a vmlaunch
521 * failure with an invalid control fields error. (combined with some other exit reasons)
522 */
523 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW)
524 {
525 /* CR8 reads from the APIC shadow page; writes cause an exit is they lower the TPR below the threshold */
526 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW;
527 Assert(pVM->hwaccm.s.vmx.pAPIC);
528 }
529 else
530 /* Exit on CR8 reads & writes in case the TPR shadow feature isn't present. */
531 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR8_STORE_EXIT | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR8_LOAD_EXIT;
532
533 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_MSR_BITMAPS)
534 {
535 Assert(pVCpu->hwaccm.s.vmx.pMSRBitmapPhys);
536 val |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_MSR_BITMAPS;
537 }
538
539 /* We will use the secondary control if it's present. */
540 val |= VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL;
541
542 /* Mask away the bits that the CPU doesn't support */
543 /** @todo make sure they don't conflict with the above requirements. */
544 val &= pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1;
545 pVCpu->hwaccm.s.vmx.proc_ctls = val;
546
547 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, val);
548 AssertRC(rc);
549
550 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_USE_SECONDARY_EXEC_CTRL)
551 {
552 /*
553 * VMX_VMCS_CTRL_PROC_EXEC_CONTROLS2
554 * Set required bits to one and zero according to the MSR capabilities.
555 */
556 val = pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.disallowed0;
557 val |= VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT;
558
559 if (pVM->hwaccm.s.fNestedPaging)
560 val |= VMX_VMCS_CTRL_PROC_EXEC2_EPT;
561
562 if (pVM->hwaccm.s.vmx.fVPID)
563 val |= VMX_VMCS_CTRL_PROC_EXEC2_VPID;
564
565 if (pVM->hwaccm.s.fHasIoApic)
566 val |= VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC;
567
568 if (pVM->hwaccm.s.vmx.fUnrestrictedGuest)
569 val |= VMX_VMCS_CTRL_PROC_EXEC2_REAL_MODE;
570
571 /* Mask away the bits that the CPU doesn't support */
572 /** @todo make sure they don't conflict with the above requirements. */
573 val &= pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.allowed1;
574 pVCpu->hwaccm.s.vmx.proc_ctls2 = val;
575 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS2, val);
576 AssertRC(rc);
577 }
578
579 /*
580 * VMX_VMCS_CTRL_CR3_TARGET_COUNT
581 * Set required bits to one and zero according to the MSR capabilities.
582 */
583 rc = VMXWriteVMCS(VMX_VMCS_CTRL_CR3_TARGET_COUNT, 0);
584 AssertRC(rc);
585
586 /*
587 * Forward all exception except #NM & #PF to the guest.
588 * We always need to check pagefaults since our shadow page table can be out of sync.
589 * And we always lazily sync the FPU & XMM state. .
590 */
591
592 /** @todo Possible optimization:
593 * Keep the FPU and XMM state current in the EM thread. That way there's no need to
594 * lazily sync anything, but the downside is that we can't use the FPU stack or XMM
595 * registers ourselves of course.
596 *
597 * Note: only possible if the current state is actually ours (X86_CR0_TS flag)
598 */
599
600 /*
601 * Don't filter page faults, all of them should cause a world switch.
602 */
603 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PAGEFAULT_ERROR_MASK, 0);
604 AssertRC(rc);
605 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PAGEFAULT_ERROR_MATCH, 0);
606 AssertRC(rc);
607
608 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_TSC_OFFSET_FULL, 0);
609 AssertRC(rc);
610 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_IO_BITMAP_A_FULL, 0);
611 AssertRC(rc);
612 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_IO_BITMAP_B_FULL, 0);
613 AssertRC(rc);
614
615 /*
616 * Set the MSR bitmap address.
617 */
618 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_MSR_BITMAPS)
619 {
620 Assert(pVCpu->hwaccm.s.vmx.pMSRBitmapPhys);
621
622 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_MSR_BITMAP_FULL, pVCpu->hwaccm.s.vmx.pMSRBitmapPhys);
623 AssertRC(rc);
624
625 /* Allow the guest to directly modify these MSRs; they are restored and saved automatically. */
626 hmR0VmxSetMSRPermission(pVCpu, MSR_IA32_SYSENTER_CS, true, true);
627 hmR0VmxSetMSRPermission(pVCpu, MSR_IA32_SYSENTER_ESP, true, true);
628 hmR0VmxSetMSRPermission(pVCpu, MSR_IA32_SYSENTER_EIP, true, true);
629 hmR0VmxSetMSRPermission(pVCpu, MSR_K8_LSTAR, true, true);
630 hmR0VmxSetMSRPermission(pVCpu, MSR_K6_STAR, true, true);
631 hmR0VmxSetMSRPermission(pVCpu, MSR_K8_SF_MASK, true, true);
632 hmR0VmxSetMSRPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, true, true);
633 hmR0VmxSetMSRPermission(pVCpu, MSR_K8_GS_BASE, true, true);
634 hmR0VmxSetMSRPermission(pVCpu, MSR_K8_FS_BASE, true, true);
635 }
636
637#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
638 /*
639 * Set the guest & host MSR load/store physical addresses.
640 */
641 Assert(pVCpu->hwaccm.s.vmx.pGuestMSRPhys);
642 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_FULL, pVCpu->hwaccm.s.vmx.pGuestMSRPhys);
643 AssertRC(rc);
644 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_VMEXIT_MSR_STORE_FULL, pVCpu->hwaccm.s.vmx.pGuestMSRPhys);
645 AssertRC(rc);
646
647 Assert(pVCpu->hwaccm.s.vmx.pHostMSRPhys);
648 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_FULL, pVCpu->hwaccm.s.vmx.pHostMSRPhys);
649 AssertRC(rc);
650#endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
651
652 rc = VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_MSR_LOAD_COUNT, 0);
653 AssertRC(rc);
654 rc = VMXWriteVMCS(VMX_VMCS_CTRL_EXIT_MSR_STORE_COUNT, 0);
655 AssertRC(rc);
656
657 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW)
658 {
659 Assert(pVM->hwaccm.s.vmx.pMemObjAPIC);
660 /* Optional */
661 rc = VMXWriteVMCS(VMX_VMCS_CTRL_TPR_THRESHOLD, 0);
662 rc |= VMXWriteVMCS64(VMX_VMCS_CTRL_VAPIC_PAGEADDR_FULL, pVCpu->hwaccm.s.vmx.HCPhysVAPIC);
663
664 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC)
665 rc |= VMXWriteVMCS64(VMX_VMCS_CTRL_APIC_ACCESSADDR_FULL, pVM->hwaccm.s.vmx.pAPICPhys);
666
667 AssertRC(rc);
668 }
669
670 /* Set link pointer to -1. Not currently used. */
671 rc = VMXWriteVMCS64(VMX_VMCS_GUEST_LINK_PTR_FULL, 0xFFFFFFFFFFFFFFFFULL);
672 AssertRC(rc);
673
674 /*
675 * Clear VMCS, marking it inactive. Clear implementation specific data and writing back
676 * VMCS data back to memory.
677 */
678 rc = VMXClearVMCS(pVCpu->hwaccm.s.vmx.HCPhysVMCS);
679 AssertRC(rc);
680
681 /*
682 * Configure the VMCS read cache.
683 */
684 PVMCSCACHE pCache = &pVCpu->hwaccm.s.vmx.VMCSCache;
685
686 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_RIP);
687 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_RSP);
688 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_GUEST_RFLAGS);
689 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE);
690 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_CTRL_CR0_READ_SHADOW);
691 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_CR0);
692 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_CTRL_CR4_READ_SHADOW);
693 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_CR4);
694 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_DR7);
695 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_GUEST_SYSENTER_CS);
696 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_SYSENTER_EIP);
697 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_SYSENTER_ESP);
698 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_GUEST_GDTR_LIMIT);
699 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_GDTR_BASE);
700 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_GUEST_IDTR_LIMIT);
701 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_IDTR_BASE);
702
703 VMX_SETUP_SELREG(ES, pCache);
704 VMX_SETUP_SELREG(SS, pCache);
705 VMX_SETUP_SELREG(CS, pCache);
706 VMX_SETUP_SELREG(DS, pCache);
707 VMX_SETUP_SELREG(FS, pCache);
708 VMX_SETUP_SELREG(GS, pCache);
709 VMX_SETUP_SELREG(LDTR, pCache);
710 VMX_SETUP_SELREG(TR, pCache);
711
712 /*
713 * Status code VMCS reads.
714 */
715 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_REASON);
716 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_VM_INSTR_ERROR);
717 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_INSTR_LENGTH);
718 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_INTERRUPTION_ERRCODE);
719 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO);
720 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_EXIT_INSTR_INFO);
721 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_RO_EXIT_QUALIFICATION);
722 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_IDT_INFO);
723 VMXSetupCachedReadVMCS(pCache, VMX_VMCS32_RO_IDT_ERRCODE);
724
725 if (pVM->hwaccm.s.fNestedPaging)
726 {
727 VMXSetupCachedReadVMCS(pCache, VMX_VMCS64_GUEST_CR3);
728 VMXSetupCachedReadVMCS(pCache, VMX_VMCS_EXIT_PHYS_ADDR_FULL);
729 pCache->Read.cValidEntries = VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX;
730 }
731 else
732 pCache->Read.cValidEntries = VMX_VMCS_MAX_CACHE_IDX;
733 } /* for each VMCPU */
734
735 /*
736 * Setup the right TLB function based on CPU capabilities.
737 */
738 if (pVM->hwaccm.s.fNestedPaging && pVM->hwaccm.s.vmx.fVPID)
739 pVM->hwaccm.s.vmx.pfnSetupTaggedTLB = hmR0VmxSetupTLBBoth;
740 else if (pVM->hwaccm.s.fNestedPaging)
741 pVM->hwaccm.s.vmx.pfnSetupTaggedTLB = hmR0VmxSetupTLBEPT;
742 else if (pVM->hwaccm.s.vmx.fVPID)
743 pVM->hwaccm.s.vmx.pfnSetupTaggedTLB = hmR0VmxSetupTLBVPID;
744 else
745 pVM->hwaccm.s.vmx.pfnSetupTaggedTLB = hmR0VmxSetupTLBDummy;
746
747vmx_end:
748 hmR0VmxCheckError(pVM, &pVM->aCpus[0], rc);
749 return rc;
750}
751
752
753/**
754 * Sets the permission bits for the specified MSR.
755 *
756 * @param pVCpu Pointer to the VMCPU.
757 * @param ulMSR The MSR value.
758 * @param fRead Whether reading is allowed.
759 * @param fWrite Whether writing is allowed.
760 */
761static void hmR0VmxSetMSRPermission(PVMCPU pVCpu, unsigned ulMSR, bool fRead, bool fWrite)
762{
763 unsigned ulBit;
764 uint8_t *pMSRBitmap = (uint8_t *)pVCpu->hwaccm.s.vmx.pMSRBitmap;
765
766 /*
767 * Layout:
768 * 0x000 - 0x3ff - Low MSR read bits
769 * 0x400 - 0x7ff - High MSR read bits
770 * 0x800 - 0xbff - Low MSR write bits
771 * 0xc00 - 0xfff - High MSR write bits
772 */
773 if (ulMSR <= 0x00001FFF)
774 {
775 /* Pentium-compatible MSRs */
776 ulBit = ulMSR;
777 }
778 else if ( ulMSR >= 0xC0000000
779 && ulMSR <= 0xC0001FFF)
780 {
781 /* AMD Sixth Generation x86 Processor MSRs */
782 ulBit = (ulMSR - 0xC0000000);
783 pMSRBitmap += 0x400;
784 }
785 else
786 {
787 AssertFailed();
788 return;
789 }
790
791 Assert(ulBit <= 0x1fff);
792 if (fRead)
793 ASMBitClear(pMSRBitmap, ulBit);
794 else
795 ASMBitSet(pMSRBitmap, ulBit);
796
797 if (fWrite)
798 ASMBitClear(pMSRBitmap + 0x800, ulBit);
799 else
800 ASMBitSet(pMSRBitmap + 0x800, ulBit);
801}
802
803
804/**
805 * Injects an event (trap or external interrupt).
806 *
807 * @returns VBox status code. Note that it may return VINF_EM_RESET to
808 * indicate a triple fault when injecting X86_XCPT_DF.
809 *
810 * @param pVM Pointer to the VM.
811 * @param pVCpu Pointer to the VMCPU.
812 * @param pCtx Pointer to the guest CPU Context.
813 * @param intInfo VMX interrupt info.
814 * @param cbInstr Opcode length of faulting instruction.
815 * @param errCode Error code (optional).
816 */
817static int hmR0VmxInjectEvent(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t intInfo, uint32_t cbInstr, uint32_t errCode)
818{
819 int rc;
820 uint32_t iGate = VMX_EXIT_INTERRUPTION_INFO_VECTOR(intInfo);
821
822#ifdef VBOX_WITH_STATISTICS
823 STAM_COUNTER_INC(&pVCpu->hwaccm.s.paStatInjectedIrqsR0[iGate & MASK_INJECT_IRQ_STAT]);
824#endif
825
826#ifdef VBOX_STRICT
827 if (iGate == 0xE)
828 {
829 LogFlow(("hmR0VmxInjectEvent: Injecting interrupt %d at %RGv error code=%08x CR2=%RGv intInfo=%08x\n", iGate,
830 (RTGCPTR)pCtx->rip, errCode, pCtx->cr2, intInfo));
831 }
832 else if (iGate < 0x20)
833 {
834 LogFlow(("hmR0VmxInjectEvent: Injecting interrupt %d at %RGv error code=%08x\n", iGate, (RTGCPTR)pCtx->rip,
835 errCode));
836 }
837 else
838 {
839 LogFlow(("INJ-EI: %x at %RGv\n", iGate, (RTGCPTR)pCtx->rip));
840 Assert( VMX_EXIT_INTERRUPTION_INFO_TYPE(intInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW
841 || !VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
842 Assert( VMX_EXIT_INTERRUPTION_INFO_TYPE(intInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW
843 || pCtx->eflags.u32 & X86_EFL_IF);
844 }
845#endif
846
847 if ( CPUMIsGuestInRealModeEx(pCtx)
848 && pVM->hwaccm.s.vmx.pRealModeTSS)
849 {
850 RTGCPHYS GCPhysHandler;
851 uint16_t offset, ip;
852 RTSEL sel;
853
854 /*
855 * Injecting events doesn't work right with real mode emulation.
856 * (#GP if we try to inject external hardware interrupts)
857 * Inject the interrupt or trap directly instead.
858 *
859 * ASSUMES no access handlers for the bits we read or write below (should be safe).
860 */
861 Log(("Manual interrupt/trap '%x' inject (real mode)\n", iGate));
862
863 /*
864 * Check if the interrupt handler is present.
865 */
866 if (iGate * 4 + 3 > pCtx->idtr.cbIdt)
867 {
868 Log(("IDT cbIdt violation\n"));
869 if (iGate != X86_XCPT_DF)
870 {
871 uint32_t intInfo2;
872
873 intInfo2 = (iGate == X86_XCPT_GP) ? (uint32_t)X86_XCPT_DF : iGate;
874 intInfo2 |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
875 intInfo2 |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
876 intInfo2 |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HWEXCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
877
878 return hmR0VmxInjectEvent(pVM, pVCpu, pCtx, intInfo2, 0, 0 /* no error code according to the Intel docs */);
879 }
880 Log(("Triple fault -> reset the VM!\n"));
881 return VINF_EM_RESET;
882 }
883 if ( VMX_EXIT_INTERRUPTION_INFO_TYPE(intInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_SW
884 || iGate == 3 /* Both #BP and #OF point to the instruction after. */
885 || iGate == 4)
886 {
887 ip = pCtx->ip + cbInstr;
888 }
889 else
890 ip = pCtx->ip;
891
892 /*
893 * Read the selector:offset pair of the interrupt handler.
894 */
895 GCPhysHandler = (RTGCPHYS)pCtx->idtr.pIdt + iGate * 4;
896 rc = PGMPhysSimpleReadGCPhys(pVM, &offset, GCPhysHandler, sizeof(offset)); AssertRC(rc);
897 rc = PGMPhysSimpleReadGCPhys(pVM, &sel, GCPhysHandler + 2, sizeof(sel)); AssertRC(rc);
898
899 LogFlow(("IDT handler %04X:%04X\n", sel, offset));
900
901 /*
902 * Construct the stack frame.
903 */
904 /** @todo Check stack limit. */
905 pCtx->sp -= 2;
906 LogFlow(("ss:sp %04X:%04X eflags=%x\n", pCtx->ss.Sel, pCtx->sp, pCtx->eflags.u));
907 rc = PGMPhysSimpleWriteGCPhys(pVM, pCtx->ss.u64Base + pCtx->sp, &pCtx->eflags, sizeof(uint16_t)); AssertRC(rc);
908 pCtx->sp -= 2;
909 LogFlow(("ss:sp %04X:%04X cs=%x\n", pCtx->ss.Sel, pCtx->sp, pCtx->cs.Sel));
910 rc = PGMPhysSimpleWriteGCPhys(pVM, pCtx->ss.u64Base + pCtx->sp, &pCtx->cs, sizeof(uint16_t)); AssertRC(rc);
911 pCtx->sp -= 2;
912 LogFlow(("ss:sp %04X:%04X ip=%x\n", pCtx->ss.Sel, pCtx->sp, ip));
913 rc = PGMPhysSimpleWriteGCPhys(pVM, pCtx->ss.u64Base + pCtx->sp, &ip, sizeof(ip)); AssertRC(rc);
914
915 /*
916 * Update the CPU state for executing the handler.
917 */
918 pCtx->rip = offset;
919 pCtx->cs.Sel = sel;
920 pCtx->cs.u64Base = sel << 4;
921 pCtx->eflags.u &= ~(X86_EFL_IF | X86_EFL_TF | X86_EFL_RF | X86_EFL_AC);
922
923 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_SEGMENT_REGS;
924 return VINF_SUCCESS;
925 }
926
927 /*
928 * Set event injection state.
929 */
930 rc = VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_IRQ_INFO, intInfo | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT));
931 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_INSTR_LENGTH, cbInstr);
932 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_EXCEPTION_ERRCODE, errCode);
933
934 AssertRC(rc);
935 return rc;
936}
937
938
939/**
940 * Checks for pending guest interrupts and injects them.
941 *
942 * @returns VBox status code.
943 * @param pVM Pointer to the VM.
944 * @param pVCpu Pointer to the VMCPU.
945 * @param pCtx Pointer to the guest CPU context.
946 */
947static int hmR0VmxCheckPendingInterrupt(PVM pVM, PVMCPU pVCpu, CPUMCTX *pCtx)
948{
949 int rc;
950
951 /*
952 * Dispatch any pending interrupts (injected before, but a VM exit occurred prematurely).
953 */
954 if (pVCpu->hwaccm.s.Event.fPending)
955 {
956 Log(("CPU%d: Reinjecting event %RX64 %08x at %RGv cr2=%RX64\n", pVCpu->idCpu, pVCpu->hwaccm.s.Event.intInfo,
957 pVCpu->hwaccm.s.Event.errCode, (RTGCPTR)pCtx->rip, pCtx->cr2));
958 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatIntReinject);
959 rc = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, pVCpu->hwaccm.s.Event.intInfo, 0, pVCpu->hwaccm.s.Event.errCode);
960 AssertRC(rc);
961
962 pVCpu->hwaccm.s.Event.fPending = false;
963 return VINF_SUCCESS;
964 }
965
966 /*
967 * If an active trap is already pending, we must forward it first!
968 */
969 if (!TRPMHasTrap(pVCpu))
970 {
971 if (VMCPU_FF_TESTANDCLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI))
972 {
973 RTGCUINTPTR intInfo;
974
975 Log(("CPU%d: injecting #NMI\n", pVCpu->idCpu));
976
977 intInfo = X86_XCPT_NMI;
978 intInfo |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
979 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
980
981 rc = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, intInfo, 0, 0);
982 AssertRC(rc);
983
984 return VINF_SUCCESS;
985 }
986
987 /** @todo SMI interrupts. */
988
989 /*
990 * When external interrupts are pending, we should exit the VM when IF is set.
991 */
992 if (VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)))
993 {
994 if (!(pCtx->eflags.u32 & X86_EFL_IF))
995 {
996 if (!(pVCpu->hwaccm.s.vmx.proc_ctls & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_IRQ_WINDOW_EXIT))
997 {
998 LogFlow(("Enable irq window exit!\n"));
999 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_IRQ_WINDOW_EXIT;
1000 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
1001 AssertRC(rc);
1002 }
1003 /* else nothing to do but wait */
1004 }
1005 else if (!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
1006 {
1007 uint8_t u8Interrupt;
1008
1009 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
1010 Log(("CPU%d: Dispatch interrupt: u8Interrupt=%x (%d) rc=%Rrc cs:rip=%04X:%RGv\n", pVCpu->idCpu,
1011 u8Interrupt, u8Interrupt, rc, pCtx->cs.Sel, (RTGCPTR)pCtx->rip));
1012 if (RT_SUCCESS(rc))
1013 {
1014 rc = TRPMAssertTrap(pVCpu, u8Interrupt, TRPM_HARDWARE_INT);
1015 AssertRC(rc);
1016 }
1017 else
1018 {
1019 /* Can only happen in rare cases where a pending interrupt is cleared behind our back */
1020 Assert(!VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)));
1021 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatSwitchGuestIrq);
1022 /* Just continue */
1023 }
1024 }
1025 else
1026 Log(("Pending interrupt blocked at %RGv by VM_FF_INHIBIT_INTERRUPTS!!\n", (RTGCPTR)pCtx->rip));
1027 }
1028 }
1029
1030#ifdef VBOX_STRICT
1031 if (TRPMHasTrap(pVCpu))
1032 {
1033 uint8_t u8Vector;
1034 rc = TRPMQueryTrapAll(pVCpu, &u8Vector, 0, 0, 0);
1035 AssertRC(rc);
1036 }
1037#endif
1038
1039 if ( (pCtx->eflags.u32 & X86_EFL_IF)
1040 && (!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
1041 && TRPMHasTrap(pVCpu)
1042 )
1043 {
1044 uint8_t u8Vector;
1045 TRPMEVENT enmType;
1046 RTGCUINTPTR intInfo;
1047 RTGCUINT errCode;
1048
1049 /*
1050 * If a new event is pending, dispatch it now.
1051 */
1052 rc = TRPMQueryTrapAll(pVCpu, &u8Vector, &enmType, &errCode, 0);
1053 AssertRC(rc);
1054 Assert(pCtx->eflags.Bits.u1IF == 1 || enmType == TRPM_TRAP);
1055 Assert(enmType != TRPM_SOFTWARE_INT);
1056
1057 /*
1058 * Clear the pending trap.
1059 */
1060 rc = TRPMResetTrap(pVCpu);
1061 AssertRC(rc);
1062
1063 intInfo = u8Vector;
1064 intInfo |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
1065
1066 if (enmType == TRPM_TRAP)
1067 {
1068 switch (u8Vector)
1069 {
1070 case X86_XCPT_DF:
1071 case X86_XCPT_TS:
1072 case X86_XCPT_NP:
1073 case X86_XCPT_SS:
1074 case X86_XCPT_GP:
1075 case X86_XCPT_PF:
1076 case X86_XCPT_AC:
1077 {
1078 /* Valid error codes. */
1079 intInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
1080 break;
1081 }
1082
1083 default:
1084 break;
1085 }
1086
1087 if ( u8Vector == X86_XCPT_BP
1088 || u8Vector == X86_XCPT_OF)
1089 {
1090 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SWEXCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
1091 }
1092 else
1093 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HWEXCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
1094 }
1095 else
1096 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
1097
1098 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatIntInject);
1099 rc = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, intInfo, 0, errCode);
1100 AssertRC(rc);
1101 } /* if (interrupts can be dispatched) */
1102
1103 return VINF_SUCCESS;
1104}
1105
1106
1107/**
1108 * Save the host state into the VMCS.
1109 *
1110 * @returns VBox status code.
1111 * @param pVM Pointer to the VM.
1112 * @param pVCpu Pointer to the VMCPU.
1113 */
1114VMMR0DECL(int) VMXR0SaveHostState(PVM pVM, PVMCPU pVCpu)
1115{
1116 int rc = VINF_SUCCESS;
1117 NOREF(pVM);
1118
1119 /*
1120 * Host CPU Context.
1121 */
1122 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_HOST_CONTEXT)
1123 {
1124 RTIDTR idtr;
1125 RTGDTR gdtr;
1126 RTSEL SelTR;
1127 PCX86DESCHC pDesc;
1128 uintptr_t trBase;
1129 RTSEL cs;
1130 RTSEL ss;
1131 uint64_t cr3;
1132
1133 /*
1134 * Control registers.
1135 */
1136 rc = VMXWriteVMCS(VMX_VMCS_HOST_CR0, ASMGetCR0());
1137 Log2(("VMX_VMCS_HOST_CR0 %08x\n", ASMGetCR0()));
1138#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
1139 if (VMX_IS_64BIT_HOST_MODE())
1140 {
1141 cr3 = hwaccmR0Get64bitCR3();
1142 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_CR3, cr3);
1143 }
1144 else
1145#endif
1146 {
1147 cr3 = ASMGetCR3();
1148 rc |= VMXWriteVMCS(VMX_VMCS_HOST_CR3, cr3);
1149 }
1150 Log2(("VMX_VMCS_HOST_CR3 %08RX64\n", cr3));
1151 rc |= VMXWriteVMCS(VMX_VMCS_HOST_CR4, ASMGetCR4());
1152 Log2(("VMX_VMCS_HOST_CR4 %08x\n", ASMGetCR4()));
1153 AssertRC(rc);
1154
1155 /*
1156 * Selector registers.
1157 */
1158#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
1159 if (VMX_IS_64BIT_HOST_MODE())
1160 {
1161 cs = (RTSEL)(uintptr_t)&SUPR0Abs64bitKernelCS;
1162 ss = (RTSEL)(uintptr_t)&SUPR0Abs64bitKernelSS;
1163 }
1164 else
1165 {
1166 /* sysenter loads LDT cs & ss, VMX doesn't like this. Load the GDT ones (safe). */
1167 cs = (RTSEL)(uintptr_t)&SUPR0AbsKernelCS;
1168 ss = (RTSEL)(uintptr_t)&SUPR0AbsKernelSS;
1169 }
1170#else
1171 cs = ASMGetCS();
1172 ss = ASMGetSS();
1173#endif
1174 Assert(!(cs & X86_SEL_LDT)); Assert((cs & X86_SEL_RPL) == 0);
1175 Assert(!(ss & X86_SEL_LDT)); Assert((ss & X86_SEL_RPL) == 0);
1176 rc = VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_CS, cs);
1177 /* Note: VMX is (again) very picky about the RPL of the selectors here; we'll restore them manually. */
1178 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_DS, 0);
1179 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_ES, 0);
1180#if HC_ARCH_BITS == 32
1181 if (!VMX_IS_64BIT_HOST_MODE())
1182 {
1183 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_FS, 0);
1184 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_GS, 0);
1185 }
1186#endif
1187 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_SS, ss);
1188 SelTR = ASMGetTR();
1189 rc |= VMXWriteVMCS(VMX_VMCS16_HOST_FIELD_TR, SelTR);
1190 AssertRC(rc);
1191 Log2(("VMX_VMCS_HOST_FIELD_CS %08x (%08x)\n", cs, ASMGetSS()));
1192 Log2(("VMX_VMCS_HOST_FIELD_DS 00000000 (%08x)\n", ASMGetDS()));
1193 Log2(("VMX_VMCS_HOST_FIELD_ES 00000000 (%08x)\n", ASMGetES()));
1194 Log2(("VMX_VMCS_HOST_FIELD_FS 00000000 (%08x)\n", ASMGetFS()));
1195 Log2(("VMX_VMCS_HOST_FIELD_GS 00000000 (%08x)\n", ASMGetGS()));
1196 Log2(("VMX_VMCS_HOST_FIELD_SS %08x (%08x)\n", ss, ASMGetSS()));
1197 Log2(("VMX_VMCS_HOST_FIELD_TR %08x\n", ASMGetTR()));
1198
1199 /*
1200 * GDTR & IDTR.
1201 */
1202#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
1203 if (VMX_IS_64BIT_HOST_MODE())
1204 {
1205 X86XDTR64 gdtr64, idtr64;
1206 hwaccmR0Get64bitGDTRandIDTR(&gdtr64, &idtr64);
1207 rc = VMXWriteVMCS64(VMX_VMCS_HOST_GDTR_BASE, gdtr64.uAddr);
1208 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_IDTR_BASE, gdtr64.uAddr);
1209 AssertRC(rc);
1210 Log2(("VMX_VMCS_HOST_GDTR_BASE %RX64\n", gdtr64.uAddr));
1211 Log2(("VMX_VMCS_HOST_IDTR_BASE %RX64\n", idtr64.uAddr));
1212 gdtr.cbGdt = gdtr64.cb;
1213 gdtr.pGdt = (uintptr_t)gdtr64.uAddr;
1214 }
1215 else
1216#endif
1217 {
1218 ASMGetGDTR(&gdtr);
1219 rc = VMXWriteVMCS(VMX_VMCS_HOST_GDTR_BASE, gdtr.pGdt);
1220 ASMGetIDTR(&idtr);
1221 rc |= VMXWriteVMCS(VMX_VMCS_HOST_IDTR_BASE, idtr.pIdt);
1222 AssertRC(rc);
1223 Log2(("VMX_VMCS_HOST_GDTR_BASE %RHv\n", gdtr.pGdt));
1224 Log2(("VMX_VMCS_HOST_IDTR_BASE %RHv\n", idtr.pIdt));
1225 }
1226
1227 /*
1228 * Save the base address of the TR selector.
1229 */
1230 if (SelTR > gdtr.cbGdt)
1231 {
1232 AssertMsgFailed(("Invalid TR selector %x. GDTR.cbGdt=%x\n", SelTR, gdtr.cbGdt));
1233 return VERR_VMX_INVALID_HOST_STATE;
1234 }
1235
1236 pDesc = (PCX86DESCHC)(gdtr.pGdt + (SelTR & X86_SEL_MASK));
1237#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
1238 if (VMX_IS_64BIT_HOST_MODE())
1239 {
1240 uint64_t trBase64 = X86DESC64_BASE(*(PX86DESC64)pDesc);
1241 rc = VMXWriteVMCS64(VMX_VMCS_HOST_TR_BASE, trBase64);
1242 Log2(("VMX_VMCS_HOST_TR_BASE %RX64\n", trBase64));
1243 AssertRC(rc);
1244 }
1245 else
1246#endif
1247 {
1248#if HC_ARCH_BITS == 64
1249 trBase = X86DESC64_BASE(*pDesc);
1250#else
1251 trBase = X86DESC_BASE(*pDesc);
1252#endif
1253 rc = VMXWriteVMCS(VMX_VMCS_HOST_TR_BASE, trBase);
1254 AssertRC(rc);
1255 Log2(("VMX_VMCS_HOST_TR_BASE %RHv\n", trBase));
1256 }
1257
1258 /*
1259 * FS base and GS base.
1260 */
1261#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
1262 if (VMX_IS_64BIT_HOST_MODE())
1263 {
1264 Log2(("MSR_K8_FS_BASE = %RX64\n", ASMRdMsr(MSR_K8_FS_BASE)));
1265 Log2(("MSR_K8_GS_BASE = %RX64\n", ASMRdMsr(MSR_K8_GS_BASE)));
1266 rc = VMXWriteVMCS64(VMX_VMCS_HOST_FS_BASE, ASMRdMsr(MSR_K8_FS_BASE));
1267 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_GS_BASE, ASMRdMsr(MSR_K8_GS_BASE));
1268 }
1269#endif
1270 AssertRC(rc);
1271
1272 /*
1273 * Sysenter MSRs.
1274 */
1275 /** @todo expensive!! */
1276 rc = VMXWriteVMCS(VMX_VMCS32_HOST_SYSENTER_CS, ASMRdMsr_Low(MSR_IA32_SYSENTER_CS));
1277 Log2(("VMX_VMCS_HOST_SYSENTER_CS %08x\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_CS)));
1278#ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
1279 if (VMX_IS_64BIT_HOST_MODE())
1280 {
1281 Log2(("VMX_VMCS_HOST_SYSENTER_EIP %RX64\n", ASMRdMsr(MSR_IA32_SYSENTER_EIP)));
1282 Log2(("VMX_VMCS_HOST_SYSENTER_ESP %RX64\n", ASMRdMsr(MSR_IA32_SYSENTER_ESP)));
1283 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
1284 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
1285 }
1286 else
1287 {
1288 rc |= VMXWriteVMCS(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
1289 rc |= VMXWriteVMCS(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
1290 Log2(("VMX_VMCS_HOST_SYSENTER_EIP %RX32\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP)));
1291 Log2(("VMX_VMCS_HOST_SYSENTER_ESP %RX32\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP)));
1292 }
1293#elif HC_ARCH_BITS == 32
1294 rc |= VMXWriteVMCS(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP));
1295 rc |= VMXWriteVMCS(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP));
1296 Log2(("VMX_VMCS_HOST_SYSENTER_EIP %RX32\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_EIP)));
1297 Log2(("VMX_VMCS_HOST_SYSENTER_ESP %RX32\n", ASMRdMsr_Low(MSR_IA32_SYSENTER_ESP)));
1298#else
1299 Log2(("VMX_VMCS_HOST_SYSENTER_EIP %RX64\n", ASMRdMsr(MSR_IA32_SYSENTER_EIP)));
1300 Log2(("VMX_VMCS_HOST_SYSENTER_ESP %RX64\n", ASMRdMsr(MSR_IA32_SYSENTER_ESP)));
1301 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_SYSENTER_ESP, ASMRdMsr(MSR_IA32_SYSENTER_ESP));
1302 rc |= VMXWriteVMCS64(VMX_VMCS_HOST_SYSENTER_EIP, ASMRdMsr(MSR_IA32_SYSENTER_EIP));
1303#endif
1304 AssertRC(rc);
1305
1306
1307#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
1308 /*
1309 * Store all host MSRs in the VM-Exit load area, so they will be reloaded after
1310 * the world switch back to the host.
1311 */
1312 PVMXMSR pMsr = (PVMXMSR)pVCpu->hwaccm.s.vmx.pHostMSR;
1313 unsigned idxMsr = 0;
1314
1315 /*
1316 * Check if EFER MSR present.
1317 */
1318 if (ASMCpuId_EDX(0x80000001) & (X86_CPUID_AMD_FEATURE_EDX_NX|X86_CPUID_AMD_FEATURE_EDX_LONG_MODE))
1319 {
1320 if (ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_SEP)
1321 {
1322 pMsr->u32IndexMSR = MSR_K6_STAR;
1323 pMsr->u32Reserved = 0;
1324 pMsr->u64Value = ASMRdMsr(MSR_K6_STAR); /* legacy syscall eip, cs & ss */
1325 pMsr++; idxMsr++;
1326 }
1327
1328 pMsr->u32IndexMSR = MSR_K6_EFER;
1329 pMsr->u32Reserved = 0;
1330# if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
1331 if (CPUMIsGuestInLongMode(pVCpu))
1332 {
1333 /* Must match the EFER value in our 64 bits switcher. */
1334 pMsr->u64Value = ASMRdMsr(MSR_K6_EFER) | MSR_K6_EFER_LME | MSR_K6_EFER_SCE | MSR_K6_EFER_NXE;
1335 }
1336 else
1337# endif
1338 pMsr->u64Value = ASMRdMsr(MSR_K6_EFER);
1339 pMsr++; idxMsr++;
1340 }
1341
1342# if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
1343 if (VMX_IS_64BIT_HOST_MODE())
1344 {
1345 pMsr->u32IndexMSR = MSR_K8_LSTAR;
1346 pMsr->u32Reserved = 0;
1347 pMsr->u64Value = ASMRdMsr(MSR_K8_LSTAR); /* 64 bits mode syscall rip */
1348 pMsr++; idxMsr++;
1349 pMsr->u32IndexMSR = MSR_K8_SF_MASK;
1350 pMsr->u32Reserved = 0;
1351 pMsr->u64Value = ASMRdMsr(MSR_K8_SF_MASK); /* syscall flag mask */
1352 pMsr++; idxMsr++;
1353 pMsr->u32IndexMSR = MSR_K8_KERNEL_GS_BASE;
1354 pMsr->u32Reserved = 0;
1355 pMsr->u64Value = ASMRdMsr(MSR_K8_KERNEL_GS_BASE); /* swapgs exchange value */
1356 pMsr++; idxMsr++;
1357 }
1358# endif
1359 rc = VMXWriteVMCS(VMX_VMCS_CTRL_EXIT_MSR_LOAD_COUNT, idxMsr);
1360 AssertRC(rc);
1361#endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
1362
1363 pVCpu->hwaccm.s.fContextUseFlags &= ~HWACCM_CHANGED_HOST_CONTEXT;
1364 }
1365 return rc;
1366}
1367
1368
1369/**
1370 * Loads the 4 PDPEs into the guest state when nested paging is used and the
1371 * guest operates in PAE mode.
1372 *
1373 * @returns VBox status code.
1374 * @param pVCpu Pointer to the VMCPU.
1375 * @param pCtx Pointer to the guest CPU context.
1376 */
1377static int hmR0VmxLoadPaePdpes(PVMCPU pVCpu, PCPUMCTX pCtx)
1378{
1379 if (CPUMIsGuestInPAEModeEx(pCtx))
1380 {
1381 X86PDPE aPdpes[4];
1382 int rc = PGMGstGetPaePdpes(pVCpu, &aPdpes[0]);
1383 AssertRCReturn(rc, rc);
1384
1385 rc = VMXWriteVMCS64(VMX_VMCS_GUEST_PDPTR0_FULL, aPdpes[0].u); AssertRCReturn(rc, rc);
1386 rc = VMXWriteVMCS64(VMX_VMCS_GUEST_PDPTR1_FULL, aPdpes[1].u); AssertRCReturn(rc, rc);
1387 rc = VMXWriteVMCS64(VMX_VMCS_GUEST_PDPTR2_FULL, aPdpes[2].u); AssertRCReturn(rc, rc);
1388 rc = VMXWriteVMCS64(VMX_VMCS_GUEST_PDPTR3_FULL, aPdpes[3].u); AssertRCReturn(rc, rc);
1389 }
1390 return VINF_SUCCESS;
1391}
1392
1393
1394/**
1395 * Saves the 4 PDPEs into the guest state when nested paging is used and the
1396 * guest operates in PAE mode.
1397 *
1398 * @returns VBox status code.
1399 * @param pVCpu Pointer to the VM CPU.
1400 * @param pCtx Pointer to the guest CPU context.
1401 *
1402 * @remarks Tell PGM about CR3 changes before calling this helper.
1403 */
1404static int hmR0VmxSavePaePdpes(PVMCPU pVCpu, PCPUMCTX pCtx)
1405{
1406 if (CPUMIsGuestInPAEModeEx(pCtx))
1407 {
1408 int rc;
1409 X86PDPE aPdpes[4];
1410 rc = VMXReadVMCS64(VMX_VMCS_GUEST_PDPTR0_FULL, &aPdpes[0].u); AssertRCReturn(rc, rc);
1411 rc = VMXReadVMCS64(VMX_VMCS_GUEST_PDPTR1_FULL, &aPdpes[1].u); AssertRCReturn(rc, rc);
1412 rc = VMXReadVMCS64(VMX_VMCS_GUEST_PDPTR2_FULL, &aPdpes[2].u); AssertRCReturn(rc, rc);
1413 rc = VMXReadVMCS64(VMX_VMCS_GUEST_PDPTR3_FULL, &aPdpes[3].u); AssertRCReturn(rc, rc);
1414
1415 rc = PGMGstUpdatePaePdpes(pVCpu, &aPdpes[0]);
1416 AssertRCReturn(rc, rc);
1417 }
1418 return VINF_SUCCESS;
1419}
1420
1421
1422/**
1423 * Update the exception bitmap according to the current CPU state.
1424 *
1425 * @param pVM Pointer to the VM.
1426 * @param pVCpu Pointer to the VMCPU.
1427 * @param pCtx Pointer to the guest CPU context.
1428 */
1429static void hmR0VmxUpdateExceptionBitmap(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1430{
1431 uint32_t u32TrapMask;
1432 Assert(pCtx);
1433
1434 /*
1435 * Set up a mask for intercepting traps.
1436 */
1437 /** @todo Do we really need to always intercept #DB? */
1438 u32TrapMask = RT_BIT(X86_XCPT_DB)
1439 | RT_BIT(X86_XCPT_NM)
1440#ifdef VBOX_ALWAYS_TRAP_PF
1441 | RT_BIT(X86_XCPT_PF)
1442#endif
1443#ifdef VBOX_STRICT
1444 | RT_BIT(X86_XCPT_BP)
1445 | RT_BIT(X86_XCPT_DB)
1446 | RT_BIT(X86_XCPT_DE)
1447 | RT_BIT(X86_XCPT_NM)
1448 | RT_BIT(X86_XCPT_UD)
1449 | RT_BIT(X86_XCPT_NP)
1450 | RT_BIT(X86_XCPT_SS)
1451 | RT_BIT(X86_XCPT_GP)
1452 | RT_BIT(X86_XCPT_MF)
1453#endif
1454 ;
1455
1456 /*
1457 * Without nested paging, #PF must be intercepted to implement shadow paging.
1458 */
1459 /** @todo NP state won't change so maybe we should build the initial trap mask up front? */
1460 if (!pVM->hwaccm.s.fNestedPaging)
1461 u32TrapMask |= RT_BIT(X86_XCPT_PF);
1462
1463 /* Catch floating point exceptions if we need to report them to the guest in a different way. */
1464 if (!(pCtx->cr0 & X86_CR0_NE))
1465 u32TrapMask |= RT_BIT(X86_XCPT_MF);
1466
1467#ifdef VBOX_STRICT
1468 Assert(u32TrapMask & RT_BIT(X86_XCPT_GP));
1469#endif
1470
1471 /*
1472 * Intercept all exceptions in real mode as none of them can be injected directly (#GP otherwise).
1473 */
1474 /** @todo Despite the claim to intercept everything, with NP we do not intercept #PF. Should we? */
1475 if ( CPUMIsGuestInRealModeEx(pCtx)
1476 && pVM->hwaccm.s.vmx.pRealModeTSS)
1477 {
1478 u32TrapMask |= RT_BIT(X86_XCPT_DE)
1479 | RT_BIT(X86_XCPT_DB)
1480 | RT_BIT(X86_XCPT_NMI)
1481 | RT_BIT(X86_XCPT_BP)
1482 | RT_BIT(X86_XCPT_OF)
1483 | RT_BIT(X86_XCPT_BR)
1484 | RT_BIT(X86_XCPT_UD)
1485 | RT_BIT(X86_XCPT_DF)
1486 | RT_BIT(X86_XCPT_CO_SEG_OVERRUN)
1487 | RT_BIT(X86_XCPT_TS)
1488 | RT_BIT(X86_XCPT_NP)
1489 | RT_BIT(X86_XCPT_SS)
1490 | RT_BIT(X86_XCPT_GP)
1491 | RT_BIT(X86_XCPT_MF)
1492 | RT_BIT(X86_XCPT_AC)
1493 | RT_BIT(X86_XCPT_MC)
1494 | RT_BIT(X86_XCPT_XF)
1495 ;
1496 }
1497
1498 int rc = VMXWriteVMCS(VMX_VMCS_CTRL_EXCEPTION_BITMAP, u32TrapMask);
1499 AssertRC(rc);
1500}
1501
1502
1503/**
1504 * Loads a minimal guest state.
1505 *
1506 * NOTE: Don't do anything here that can cause a jump back to ring 3!!!!!
1507 *
1508 * @param pVM Pointer to the VM.
1509 * @param pVCpu Pointer to the VMCPU.
1510 * @param pCtx Pointer to the guest CPU context.
1511 */
1512VMMR0DECL(void) VMXR0LoadMinimalGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1513{
1514 int rc;
1515 X86EFLAGS eflags;
1516
1517 Assert(!(pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_ALL_GUEST));
1518
1519 /*
1520 * Load EIP, ESP and EFLAGS.
1521 */
1522 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_RIP, pCtx->rip);
1523 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_RSP, pCtx->rsp);
1524 AssertRC(rc);
1525
1526 /*
1527 * Bits 22-31, 15, 5 & 3 must be zero. Bit 1 must be 1.
1528 */
1529 eflags = pCtx->eflags;
1530 eflags.u32 &= VMX_EFLAGS_RESERVED_0;
1531 eflags.u32 |= VMX_EFLAGS_RESERVED_1;
1532
1533 /*
1534 * Check if real mode emulation using v86 mode.
1535 */
1536 if ( CPUMIsGuestInRealModeEx(pCtx)
1537 && pVM->hwaccm.s.vmx.pRealModeTSS)
1538 {
1539 pVCpu->hwaccm.s.vmx.RealMode.eflags = eflags;
1540
1541 eflags.Bits.u1VM = 1;
1542 eflags.Bits.u2IOPL = 0; /* must always be 0 or else certain instructions won't cause faults. */
1543 }
1544 rc = VMXWriteVMCS(VMX_VMCS_GUEST_RFLAGS, eflags.u32);
1545 AssertRC(rc);
1546}
1547
1548
1549/**
1550 * Loads the guest state.
1551 *
1552 * NOTE: Don't do anything here that can cause a jump back to ring 3!!!!!
1553 *
1554 * @returns VBox status code.
1555 * @param pVM Pointer to the VM.
1556 * @param pVCpu Pointer to the VMCPU.
1557 * @param pCtx Pointer to the guest CPU context.
1558 */
1559VMMR0DECL(int) VMXR0LoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1560{
1561 int rc = VINF_SUCCESS;
1562 RTGCUINTPTR val;
1563
1564 /*
1565 * VMX_VMCS_CTRL_ENTRY_CONTROLS
1566 * Set required bits to one and zero according to the MSR capabilities.
1567 */
1568 val = pVM->hwaccm.s.vmx.msr.vmx_entry.n.disallowed0;
1569
1570 /*
1571 * Load guest debug controls (DR7 & IA32_DEBUGCTL_MSR).
1572 * Forced to 1 on the 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs
1573 */
1574 val |= VMX_VMCS_CTRL_ENTRY_CONTROLS_LOAD_DEBUG;
1575
1576 if (CPUMIsGuestInLongModeEx(pCtx))
1577 val |= VMX_VMCS_CTRL_ENTRY_CONTROLS_IA64_MODE;
1578 /* else Must be zero when AMD64 is not available. */
1579
1580 /*
1581 * Mask away the bits that the CPU doesn't support.
1582 */
1583 val &= pVM->hwaccm.s.vmx.msr.vmx_entry.n.allowed1;
1584 rc = VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_CONTROLS, val);
1585 AssertRC(rc);
1586
1587 /*
1588 * VMX_VMCS_CTRL_EXIT_CONTROLS
1589 * Set required bits to one and zero according to the MSR capabilities.
1590 */
1591 val = pVM->hwaccm.s.vmx.msr.vmx_exit.n.disallowed0;
1592
1593 /*
1594 * Save debug controls (DR7 & IA32_DEBUGCTL_MSR)
1595 * Forced to 1 on the 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs
1596 */
1597 val |= VMX_VMCS_CTRL_EXIT_CONTROLS_SAVE_DEBUG;
1598
1599#if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
1600 if (VMX_IS_64BIT_HOST_MODE())
1601 val |= VMX_VMCS_CTRL_EXIT_CONTROLS_HOST_AMD64;
1602 /* else Must be zero when AMD64 is not available. */
1603#elif HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
1604 if (CPUMIsGuestInLongModeEx(pCtx))
1605 val |= VMX_VMCS_CTRL_EXIT_CONTROLS_HOST_AMD64; /* our switcher goes to long mode */
1606 else
1607 Assert(!(val & VMX_VMCS_CTRL_EXIT_CONTROLS_HOST_AMD64));
1608#endif
1609 val &= pVM->hwaccm.s.vmx.msr.vmx_exit.n.allowed1;
1610
1611 /*
1612 * Don't acknowledge external interrupts on VM-exit.
1613 */
1614 rc = VMXWriteVMCS(VMX_VMCS_CTRL_EXIT_CONTROLS, val);
1615 AssertRC(rc);
1616
1617 /*
1618 * Guest CPU context: ES, CS, SS, DS, FS, GS.
1619 */
1620 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_SEGMENT_REGS)
1621 {
1622 if (pVM->hwaccm.s.vmx.pRealModeTSS)
1623 {
1624 PGMMODE enmGuestMode = PGMGetGuestMode(pVCpu);
1625 if (pVCpu->hwaccm.s.vmx.enmLastSeenGuestMode != enmGuestMode)
1626 {
1627 /*
1628 * Correct weird requirements for switching to protected mode.
1629 */
1630 if ( pVCpu->hwaccm.s.vmx.enmLastSeenGuestMode == PGMMODE_REAL
1631 && enmGuestMode >= PGMMODE_PROTECTED)
1632 {
1633#ifdef VBOX_WITH_REM
1634 /*
1635 * Flush the recompiler code cache as it's not unlikely the guest will rewrite code
1636 * it will later execute in real mode (OpenBSD 4.0 is one such example)
1637 */
1638 REMFlushTBs(pVM);
1639#endif
1640
1641 /*
1642 * DPL of all hidden selector registers must match the current CPL (0).
1643 */
1644 pCtx->cs.Attr.n.u2Dpl = 0;
1645 pCtx->cs.Attr.n.u4Type = X86_SEL_TYPE_CODE | X86_SEL_TYPE_RW_ACC;
1646
1647 pCtx->ds.Attr.n.u2Dpl = 0;
1648 pCtx->es.Attr.n.u2Dpl = 0;
1649 pCtx->fs.Attr.n.u2Dpl = 0;
1650 pCtx->gs.Attr.n.u2Dpl = 0;
1651 pCtx->ss.Attr.n.u2Dpl = 0;
1652 }
1653 pVCpu->hwaccm.s.vmx.enmLastSeenGuestMode = enmGuestMode;
1654 }
1655 else if ( CPUMIsGuestInRealModeEx(pCtx)
1656 && pCtx->cs.u64Base == 0xffff0000)
1657 {
1658 /* VT-x will fail with a guest invalid state otherwise... (CPU state after a reset) */
1659 pCtx->cs.u64Base = 0xf0000;
1660 pCtx->cs.Sel = 0xf000;
1661 }
1662 }
1663
1664 VMX_WRITE_SELREG(ES, es);
1665 AssertRC(rc);
1666
1667 VMX_WRITE_SELREG(CS, cs);
1668 AssertRC(rc);
1669
1670 VMX_WRITE_SELREG(SS, ss);
1671 AssertRC(rc);
1672
1673 VMX_WRITE_SELREG(DS, ds);
1674 AssertRC(rc);
1675
1676 VMX_WRITE_SELREG(FS, fs);
1677 AssertRC(rc);
1678
1679 VMX_WRITE_SELREG(GS, gs);
1680 AssertRC(rc);
1681 }
1682
1683 /*
1684 * Guest CPU context: LDTR.
1685 */
1686 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_LDTR)
1687 {
1688 if (pCtx->ldtr.Sel == 0)
1689 {
1690 rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_LDTR, 0);
1691 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_LDTR_LIMIT, 0);
1692 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_LDTR_BASE, 0);
1693 /* Note: vmlaunch will fail with 0 or just 0x02. No idea why. */
1694 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, 0x82 /* present, LDT */);
1695 }
1696 else
1697 {
1698 rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_LDTR, pCtx->ldtr.Sel);
1699 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_LDTR_LIMIT, pCtx->ldtr.u32Limit);
1700 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_LDTR_BASE, pCtx->ldtr.u64Base);
1701 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS, pCtx->ldtr.Attr.u);
1702 }
1703 AssertRC(rc);
1704 }
1705
1706 /*
1707 * Guest CPU context: TR.
1708 */
1709 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_TR)
1710 {
1711 /*
1712 * Real mode emulation using v86 mode with CR4.VME (interrupt redirection
1713 * using the int bitmap in the TSS).
1714 */
1715 if ( CPUMIsGuestInRealModeEx(pCtx)
1716 && pVM->hwaccm.s.vmx.pRealModeTSS)
1717 {
1718 RTGCPHYS GCPhys;
1719
1720 /* We convert it here every time as PCI regions could be reconfigured. */
1721 rc = PDMVMMDevHeapR3ToGCPhys(pVM, pVM->hwaccm.s.vmx.pRealModeTSS, &GCPhys);
1722 AssertRC(rc);
1723
1724 rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_TR, 0);
1725 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_TR_LIMIT, HWACCM_VTX_TSS_SIZE);
1726 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_TR_BASE, GCPhys /* phys = virt in this mode */);
1727
1728 X86DESCATTR attr;
1729
1730 attr.u = 0;
1731 attr.n.u1Present = 1;
1732 attr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
1733 val = attr.u;
1734 }
1735 else
1736 {
1737 rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_TR, pCtx->tr.Sel);
1738 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_TR_LIMIT, pCtx->tr.u32Limit);
1739 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_TR_BASE, pCtx->tr.u64Base);
1740
1741 val = pCtx->tr.Attr.u;
1742
1743 /* The TSS selector must be busy (REM bugs? see defect #XXXX). */
1744 if (!(val & X86_SEL_TYPE_SYS_TSS_BUSY_MASK))
1745 {
1746 if (val & 0xf)
1747 val |= X86_SEL_TYPE_SYS_TSS_BUSY_MASK;
1748 else
1749 /* Default if no TR selector has been set (otherwise vmlaunch will fail!) */
1750 val = (val & ~0xF) | X86_SEL_TYPE_SYS_386_TSS_BUSY;
1751 }
1752 AssertMsg((val & 0xf) == X86_SEL_TYPE_SYS_386_TSS_BUSY || (val & 0xf) == X86_SEL_TYPE_SYS_286_TSS_BUSY, ("%#x\n", val));
1753 }
1754 rc |= VMXWriteVMCS(VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS, val);
1755 AssertRC(rc);
1756 }
1757
1758 /*
1759 * Guest CPU context: GDTR.
1760 */
1761 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_GDTR)
1762 {
1763 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_GDTR_LIMIT, pCtx->gdtr.cbGdt);
1764 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_GDTR_BASE, pCtx->gdtr.pGdt);
1765 AssertRC(rc);
1766 }
1767
1768 /*
1769 * Guest CPU context: IDTR.
1770 */
1771 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_IDTR)
1772 {
1773 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_IDTR_LIMIT, pCtx->idtr.cbIdt);
1774 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_IDTR_BASE, pCtx->idtr.pIdt);
1775 AssertRC(rc);
1776 }
1777
1778 /*
1779 * Sysenter MSRs.
1780 */
1781 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_MSR)
1782 {
1783 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_SYSENTER_CS, pCtx->SysEnter.cs);
1784 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_SYSENTER_EIP, pCtx->SysEnter.eip);
1785 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_SYSENTER_ESP, pCtx->SysEnter.esp);
1786 AssertRC(rc);
1787 }
1788
1789 /*
1790 * Guest CPU context: Control registers.
1791 */
1792 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR0)
1793 {
1794 val = pCtx->cr0;
1795 rc = VMXWriteVMCS(VMX_VMCS_CTRL_CR0_READ_SHADOW, val);
1796 Log2(("Guest CR0-shadow %08x\n", val));
1797 if (CPUMIsGuestFPUStateActive(pVCpu) == false)
1798 {
1799 /* Always use #NM exceptions to load the FPU/XMM state on demand. */
1800 val |= X86_CR0_TS | X86_CR0_ET | X86_CR0_NE | X86_CR0_MP;
1801 }
1802 else
1803 {
1804 /** @todo check if we support the old style mess correctly. */
1805 if (!(val & X86_CR0_NE))
1806 Log(("Forcing X86_CR0_NE!!!\n"));
1807
1808 val |= X86_CR0_NE; /* always turn on the native mechanism to report FPU errors (old style uses interrupts) */
1809 }
1810 /* Note: protected mode & paging are always enabled; we use them for emulating real and protected mode without paging too. */
1811 if (!pVM->hwaccm.s.vmx.fUnrestrictedGuest)
1812 val |= X86_CR0_PE | X86_CR0_PG;
1813
1814 if (pVM->hwaccm.s.fNestedPaging)
1815 {
1816 if (CPUMIsGuestInPagedProtectedModeEx(pCtx))
1817 {
1818 /* Disable CR3 read/write monitoring as we don't need it for EPT. */
1819 pVCpu->hwaccm.s.vmx.proc_ctls &= ~( VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_LOAD_EXIT
1820 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_STORE_EXIT);
1821 }
1822 else
1823 {
1824 /* Reenable CR3 read/write monitoring as our identity mapped page table is active. */
1825 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_LOAD_EXIT
1826 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_STORE_EXIT;
1827 }
1828 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
1829 AssertRC(rc);
1830 }
1831 else
1832 {
1833 /* Note: We must also set this as we rely on protecting various pages for which supervisor writes must be caught. */
1834 val |= X86_CR0_WP;
1835 }
1836
1837 /* Always enable caching. */
1838 val &= ~(X86_CR0_CD|X86_CR0_NW);
1839
1840 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_CR0, val);
1841 Log2(("Guest CR0 %08x\n", val));
1842
1843 /*
1844 * CR0 flags owned by the host; if the guests attempts to change them, then the VM will exit.
1845 */
1846 val = X86_CR0_PE /* Must monitor this bit (assumptions are made for real mode emulation) */
1847 | X86_CR0_WP /* Must monitor this bit (it must always be enabled). */
1848 | X86_CR0_PG /* Must monitor this bit (assumptions are made for real mode & protected mode without paging emulation) */
1849 | X86_CR0_CD /* Bit not restored during VM-exit! */
1850 | X86_CR0_NW /* Bit not restored during VM-exit! */
1851 | X86_CR0_NE;
1852
1853 /*
1854 * When the guest's FPU state is active, then we no longer care about the FPU related bits.
1855 */
1856 if (CPUMIsGuestFPUStateActive(pVCpu) == false)
1857 val |= X86_CR0_TS | X86_CR0_ET | X86_CR0_MP;
1858
1859 pVCpu->hwaccm.s.vmx.cr0_mask = val;
1860
1861 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_CR0_MASK, val);
1862 Log2(("Guest CR0-mask %08x\n", val));
1863 AssertRC(rc);
1864 }
1865
1866 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR4)
1867 {
1868 rc = VMXWriteVMCS(VMX_VMCS_CTRL_CR4_READ_SHADOW, pCtx->cr4);
1869 Log2(("Guest CR4-shadow %08x\n", pCtx->cr4));
1870 /* Set the required bits in cr4 too (currently X86_CR4_VMXE). */
1871 val = pCtx->cr4 | (uint32_t)pVM->hwaccm.s.vmx.msr.vmx_cr4_fixed0;
1872
1873 if (!pVM->hwaccm.s.fNestedPaging)
1874 {
1875 switch(pVCpu->hwaccm.s.enmShadowMode)
1876 {
1877 case PGMMODE_REAL: /* Real mode -> emulated using v86 mode */
1878 case PGMMODE_PROTECTED: /* Protected mode, no paging -> emulated using identity mapping. */
1879 case PGMMODE_32_BIT: /* 32-bit paging. */
1880 val &= ~X86_CR4_PAE;
1881 break;
1882
1883 case PGMMODE_PAE: /* PAE paging. */
1884 case PGMMODE_PAE_NX: /* PAE paging with NX enabled. */
1885 /** Must use PAE paging as we could use physical memory > 4 GB */
1886 val |= X86_CR4_PAE;
1887 break;
1888
1889 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
1890 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
1891#ifdef VBOX_ENABLE_64_BITS_GUESTS
1892 break;
1893#else
1894 AssertFailed();
1895 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1896#endif
1897 default: /* shut up gcc */
1898 AssertFailed();
1899 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1900 }
1901 }
1902 else if ( !CPUMIsGuestInPagedProtectedModeEx(pCtx)
1903 && !pVM->hwaccm.s.vmx.fUnrestrictedGuest)
1904 {
1905 /* We use 4 MB pages in our identity mapping page table for real and protected mode without paging. */
1906 val |= X86_CR4_PSE;
1907 /* Our identity mapping is a 32 bits page directory. */
1908 val &= ~X86_CR4_PAE;
1909 }
1910
1911 /*
1912 * Turn off VME if we're in emulated real mode.
1913 */
1914 if ( CPUMIsGuestInRealModeEx(pCtx)
1915 && pVM->hwaccm.s.vmx.pRealModeTSS)
1916 {
1917 val &= ~X86_CR4_VME;
1918 }
1919
1920 rc |= VMXWriteVMCS64(VMX_VMCS64_GUEST_CR4, val);
1921 Log2(("Guest CR4 %08x\n", val));
1922
1923 /*
1924 * CR4 flags owned by the host; if the guests attempts to change them, then the VM will exit.
1925 */
1926 val = 0
1927 | X86_CR4_VME
1928 | X86_CR4_PAE
1929 | X86_CR4_PGE
1930 | X86_CR4_PSE
1931 | X86_CR4_VMXE;
1932 pVCpu->hwaccm.s.vmx.cr4_mask = val;
1933
1934 rc |= VMXWriteVMCS(VMX_VMCS_CTRL_CR4_MASK, val);
1935 Log2(("Guest CR4-mask %08x\n", val));
1936 AssertRC(rc);
1937 }
1938
1939#if 0
1940 /* Enable single stepping if requested and CPU supports it. */
1941 if (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MONITOR_TRAP_FLAG)
1942 if (DBGFIsStepping(pVCpu))
1943 {
1944 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MONITOR_TRAP_FLAG;
1945 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
1946 AssertRC(rc);
1947 }
1948#endif
1949
1950 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR3)
1951 {
1952 if (pVM->hwaccm.s.fNestedPaging)
1953 {
1954 Assert(PGMGetHyperCR3(pVCpu));
1955 pVCpu->hwaccm.s.vmx.GCPhysEPTP = PGMGetHyperCR3(pVCpu);
1956
1957 Assert(!(pVCpu->hwaccm.s.vmx.GCPhysEPTP & 0xfff));
1958 /** @todo Check the IA32_VMX_EPT_VPID_CAP MSR for other supported memory types. */
1959 pVCpu->hwaccm.s.vmx.GCPhysEPTP |= VMX_EPT_MEMTYPE_WB
1960 | (VMX_EPT_PAGE_WALK_LENGTH_DEFAULT << VMX_EPT_PAGE_WALK_LENGTH_SHIFT);
1961
1962 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_EPTP_FULL, pVCpu->hwaccm.s.vmx.GCPhysEPTP);
1963 AssertRC(rc);
1964
1965 if ( !CPUMIsGuestInPagedProtectedModeEx(pCtx)
1966 && !pVM->hwaccm.s.vmx.fUnrestrictedGuest)
1967 {
1968 RTGCPHYS GCPhys;
1969
1970 /* We convert it here every time as PCI regions could be reconfigured. */
1971 rc = PDMVMMDevHeapR3ToGCPhys(pVM, pVM->hwaccm.s.vmx.pNonPagingModeEPTPageTable, &GCPhys);
1972 AssertMsgRC(rc, ("pNonPagingModeEPTPageTable = %RGv\n", pVM->hwaccm.s.vmx.pNonPagingModeEPTPageTable));
1973
1974 /*
1975 * We use our identity mapping page table here as we need to map guest virtual to
1976 * guest physical addresses; EPT will take care of the translation to host physical addresses.
1977 */
1978 val = GCPhys;
1979 }
1980 else
1981 {
1982 /* Save the real guest CR3 in VMX_VMCS_GUEST_CR3 */
1983 val = pCtx->cr3;
1984 rc = hmR0VmxLoadPaePdpes(pVCpu, pCtx);
1985 AssertRCReturn(rc, rc);
1986 }
1987 }
1988 else
1989 {
1990 val = PGMGetHyperCR3(pVCpu);
1991 Assert(val || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL));
1992 }
1993
1994 /* Save our shadow CR3 register. */
1995 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_CR3, val);
1996 AssertRC(rc);
1997 }
1998
1999 /*
2000 * Guest CPU context: Debug registers.
2001 */
2002 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_DEBUG)
2003 {
2004 pCtx->dr[6] |= X86_DR6_INIT_VAL; /* set all reserved bits to 1. */
2005 pCtx->dr[6] &= ~RT_BIT(12); /* must be zero. */
2006
2007 pCtx->dr[7] &= 0xffffffff; /* upper 32 bits reserved */
2008 pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
2009 pCtx->dr[7] |= 0x400; /* must be one */
2010
2011 /* Resync DR7 */
2012 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_DR7, pCtx->dr[7]);
2013 AssertRC(rc);
2014
2015#ifdef DEBUG
2016 /* Sync the hypervisor debug state now if any breakpoint is armed. */
2017 if ( CPUMGetHyperDR7(pVCpu) & (X86_DR7_ENABLED_MASK|X86_DR7_GD)
2018 && !CPUMIsHyperDebugStateActive(pVCpu)
2019 && !DBGFIsStepping(pVCpu))
2020 {
2021 /* Save the host and load the hypervisor debug state. */
2022 rc = CPUMR0LoadHyperDebugState(pVM, pVCpu, pCtx, true /* include DR6 */);
2023 AssertRC(rc);
2024
2025 /* DRx intercepts remain enabled. */
2026
2027 /* Override dr7 with the hypervisor value. */
2028 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_DR7, CPUMGetHyperDR7(pVCpu));
2029 AssertRC(rc);
2030 }
2031 else
2032#endif
2033 /* Sync the debug state now if any breakpoint is armed. */
2034 if ( (pCtx->dr[7] & (X86_DR7_ENABLED_MASK|X86_DR7_GD))
2035 && !CPUMIsGuestDebugStateActive(pVCpu)
2036 && !DBGFIsStepping(pVCpu))
2037 {
2038 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxArmed);
2039
2040 /* Disable DRx move intercepts. */
2041 pVCpu->hwaccm.s.vmx.proc_ctls &= ~VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT;
2042 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
2043 AssertRC(rc);
2044
2045 /* Save the host and load the guest debug state. */
2046 rc = CPUMR0LoadGuestDebugState(pVM, pVCpu, pCtx, true /* include DR6 */);
2047 AssertRC(rc);
2048 }
2049
2050 /* IA32_DEBUGCTL MSR. */
2051 rc = VMXWriteVMCS64(VMX_VMCS_GUEST_DEBUGCTL_FULL, 0);
2052 AssertRC(rc);
2053
2054 /** @todo do we really ever need this? */
2055 rc |= VMXWriteVMCS(VMX_VMCS_GUEST_DEBUG_EXCEPTIONS, 0);
2056 AssertRC(rc);
2057 }
2058
2059 /*
2060 * 64-bit guest mode.
2061 */
2062 if (CPUMIsGuestInLongModeEx(pCtx))
2063 {
2064#if !defined(VBOX_ENABLE_64_BITS_GUESTS)
2065 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
2066#elif HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
2067 pVCpu->hwaccm.s.vmx.pfnStartVM = VMXR0SwitcherStartVM64;
2068#else
2069# ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
2070 if (!pVM->hwaccm.s.fAllow64BitGuests)
2071 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
2072# endif
2073 pVCpu->hwaccm.s.vmx.pfnStartVM = VMXR0StartVM64;
2074#endif
2075 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_MSR)
2076 {
2077 /* Update these as wrmsr might have changed them. */
2078 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_FS_BASE, pCtx->fs.u64Base);
2079 AssertRC(rc);
2080 rc = VMXWriteVMCS64(VMX_VMCS64_GUEST_GS_BASE, pCtx->gs.u64Base);
2081 AssertRC(rc);
2082 }
2083 }
2084 else
2085 {
2086 pVCpu->hwaccm.s.vmx.pfnStartVM = VMXR0StartVM32;
2087 }
2088
2089 hmR0VmxUpdateExceptionBitmap(pVM, pVCpu, pCtx);
2090
2091#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
2092 /* Store all guest MSRs in the VM-Entry load area, so they will be loaded during the world switch. */
2093 PVMXMSR pMsr = (PVMXMSR)pVCpu->hwaccm.s.vmx.pGuestMSR;
2094 unsigned idxMsr = 0;
2095
2096 uint32_t ulEdx;
2097 uint32_t ulTemp;
2098 CPUMGetGuestCpuId(pVCpu, 0x80000001, &ulTemp, &ulTemp, &ulTemp, &ulEdx);
2099 /* EFER MSR present? */
2100 if (ulEdx & (X86_CPUID_AMD_FEATURE_EDX_NX|X86_CPUID_AMD_FEATURE_EDX_LONG_MODE))
2101 {
2102 pMsr->u32IndexMSR = MSR_K6_EFER;
2103 pMsr->u32Reserved = 0;
2104 pMsr->u64Value = pCtx->msrEFER;
2105 /* VT-x will complain if only MSR_K6_EFER_LME is set. */
2106 if (!CPUMIsGuestInLongModeEx(pCtx))
2107 pMsr->u64Value &= ~(MSR_K6_EFER_LMA|MSR_K6_EFER_LME);
2108 pMsr++; idxMsr++;
2109
2110 if (ulEdx & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE)
2111 {
2112 pMsr->u32IndexMSR = MSR_K8_LSTAR;
2113 pMsr->u32Reserved = 0;
2114 pMsr->u64Value = pCtx->msrLSTAR; /* 64 bits mode syscall rip */
2115 pMsr++; idxMsr++;
2116 pMsr->u32IndexMSR = MSR_K6_STAR;
2117 pMsr->u32Reserved = 0;
2118 pMsr->u64Value = pCtx->msrSTAR; /* legacy syscall eip, cs & ss */
2119 pMsr++; idxMsr++;
2120 pMsr->u32IndexMSR = MSR_K8_SF_MASK;
2121 pMsr->u32Reserved = 0;
2122 pMsr->u64Value = pCtx->msrSFMASK; /* syscall flag mask */
2123 pMsr++; idxMsr++;
2124 pMsr->u32IndexMSR = MSR_K8_KERNEL_GS_BASE;
2125 pMsr->u32Reserved = 0;
2126 pMsr->u64Value = pCtx->msrKERNELGSBASE; /* swapgs exchange value */
2127 pMsr++; idxMsr++;
2128 }
2129 }
2130 pVCpu->hwaccm.s.vmx.cCachedMSRs = idxMsr;
2131
2132 rc = VMXWriteVMCS(VMX_VMCS_CTRL_ENTRY_MSR_LOAD_COUNT, idxMsr);
2133 AssertRC(rc);
2134
2135 rc = VMXWriteVMCS(VMX_VMCS_CTRL_EXIT_MSR_STORE_COUNT, idxMsr);
2136 AssertRC(rc);
2137#endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
2138
2139 bool fOffsettedTsc;
2140 if (pVM->hwaccm.s.vmx.fUsePreemptTimer)
2141 {
2142 uint64_t cTicksToDeadline = TMCpuTickGetDeadlineAndTscOffset(pVCpu, &fOffsettedTsc, &pVCpu->hwaccm.s.vmx.u64TSCOffset);
2143
2144 /* Make sure the returned values have sane upper and lower boundaries. */
2145 uint64_t u64CpuHz = SUPGetCpuHzFromGIP(g_pSUPGlobalInfoPage);
2146
2147 cTicksToDeadline = RT_MIN(cTicksToDeadline, u64CpuHz / 64); /* 1/64 of a second */
2148 cTicksToDeadline = RT_MAX(cTicksToDeadline, u64CpuHz / 2048); /* 1/2048th of a second */
2149
2150 cTicksToDeadline >>= pVM->hwaccm.s.vmx.cPreemptTimerShift;
2151 uint32_t cPreemptionTickCount = (uint32_t)RT_MIN(cTicksToDeadline, UINT32_MAX - 16);
2152 rc = VMXWriteVMCS(VMX_VMCS32_GUEST_PREEMPTION_TIMER_VALUE, cPreemptionTickCount);
2153 AssertRC(rc);
2154 }
2155 else
2156 fOffsettedTsc = TMCpuTickCanUseRealTSC(pVCpu, &pVCpu->hwaccm.s.vmx.u64TSCOffset);
2157
2158 if (fOffsettedTsc)
2159 {
2160 uint64_t u64CurTSC = ASMReadTSC();
2161 if (u64CurTSC + pVCpu->hwaccm.s.vmx.u64TSCOffset >= TMCpuTickGetLastSeen(pVCpu))
2162 {
2163 /* Note: VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDTSC_EXIT takes precedence over TSC_OFFSET */
2164 rc = VMXWriteVMCS64(VMX_VMCS_CTRL_TSC_OFFSET_FULL, pVCpu->hwaccm.s.vmx.u64TSCOffset);
2165 AssertRC(rc);
2166
2167 pVCpu->hwaccm.s.vmx.proc_ctls &= ~VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDTSC_EXIT;
2168 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
2169 AssertRC(rc);
2170 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTSCOffset);
2171 }
2172 else
2173 {
2174 /* Fall back to rdtsc emulation as we would otherwise pass decreasing tsc values to the guest. */
2175 LogFlow(("TSC %RX64 offset %RX64 time=%RX64 last=%RX64 (diff=%RX64, virt_tsc=%RX64)\n", u64CurTSC,
2176 pVCpu->hwaccm.s.vmx.u64TSCOffset, u64CurTSC + pVCpu->hwaccm.s.vmx.u64TSCOffset,
2177 TMCpuTickGetLastSeen(pVCpu), TMCpuTickGetLastSeen(pVCpu) - u64CurTSC - pVCpu->hwaccm.s.vmx.u64TSCOffset,
2178 TMCpuTickGet(pVCpu)));
2179 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDTSC_EXIT;
2180 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
2181 AssertRC(rc);
2182 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTSCInterceptOverFlow);
2183 }
2184 }
2185 else
2186 {
2187 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDTSC_EXIT;
2188 rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
2189 AssertRC(rc);
2190 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTSCIntercept);
2191 }
2192
2193 /* Done with the major changes */
2194 pVCpu->hwaccm.s.fContextUseFlags &= ~HWACCM_CHANGED_ALL_GUEST;
2195
2196 /* Minimal guest state update (ESP, EIP, EFLAGS mostly) */
2197 VMXR0LoadMinimalGuestState(pVM, pVCpu, pCtx);
2198 return rc;
2199}
2200
2201
2202/**
2203 * Syncs back the guest state from VMCS.
2204 *
2205 * @returns VBox status code.
2206 * @param pVM Pointer to the VM.
2207 * @param pVCpu Pointer to the VMCPU.
2208 * @param pCtx Pointer to the guest CPU context.
2209 */
2210DECLINLINE(int) VMXR0SaveGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
2211{
2212 RTGCUINTREG val, valShadow;
2213 RTGCUINTPTR uInterruptState;
2214 int rc;
2215
2216 /* First sync back EIP, ESP, and EFLAGS. */
2217 rc = VMXReadCachedVMCS(VMX_VMCS64_GUEST_RIP, &val);
2218 AssertRC(rc);
2219 pCtx->rip = val;
2220 rc = VMXReadCachedVMCS(VMX_VMCS64_GUEST_RSP, &val);
2221 AssertRC(rc);
2222 pCtx->rsp = val;
2223 rc = VMXReadCachedVMCS(VMX_VMCS_GUEST_RFLAGS, &val);
2224 AssertRC(rc);
2225 pCtx->eflags.u32 = val;
2226
2227 /* Take care of instruction fusing (sti, mov ss) */
2228 rc |= VMXReadCachedVMCS(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, &val);
2229 uInterruptState = val;
2230 if (uInterruptState != 0)
2231 {
2232 Assert(uInterruptState <= 2); /* only sti & mov ss */
2233 Log(("uInterruptState %x eip=%RGv\n", (uint32_t)uInterruptState, pCtx->rip));
2234 EMSetInhibitInterruptsPC(pVCpu, pCtx->rip);
2235 }
2236 else
2237 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
2238
2239 /* Control registers. */
2240 VMXReadCachedVMCS(VMX_VMCS_CTRL_CR0_READ_SHADOW, &valShadow);
2241 VMXReadCachedVMCS(VMX_VMCS64_GUEST_CR0, &val);
2242 val = (valShadow & pVCpu->hwaccm.s.vmx.cr0_mask) | (val & ~pVCpu->hwaccm.s.vmx.cr0_mask);
2243 CPUMSetGuestCR0(pVCpu, val);
2244
2245 VMXReadCachedVMCS(VMX_VMCS_CTRL_CR4_READ_SHADOW, &valShadow);
2246 VMXReadCachedVMCS(VMX_VMCS64_GUEST_CR4, &val);
2247 val = (valShadow & pVCpu->hwaccm.s.vmx.cr4_mask) | (val & ~pVCpu->hwaccm.s.vmx.cr4_mask);
2248 CPUMSetGuestCR4(pVCpu, val);
2249
2250 /*
2251 * No reason to sync back the CRx registers. They can't be changed by the guest unless in
2252 * the nested paging case where CR3 & CR4 can be changed by the guest.
2253 */
2254 if ( pVM->hwaccm.s.fNestedPaging
2255 && CPUMIsGuestInPagedProtectedModeEx(pCtx)) /** @todo check if we will always catch mode switches and such... */
2256 {
2257 PVMCSCACHE pCache = &pVCpu->hwaccm.s.vmx.VMCSCache;
2258
2259 /* Can be updated behind our back in the nested paging case. */
2260 CPUMSetGuestCR2(pVCpu, pCache->cr2);
2261
2262 VMXReadCachedVMCS(VMX_VMCS64_GUEST_CR3, &val);
2263
2264 if (val != pCtx->cr3)
2265 {
2266 CPUMSetGuestCR3(pVCpu, val);
2267 PGMUpdateCR3(pVCpu, val);
2268 }
2269 rc = hmR0VmxSavePaePdpes(pVCpu, pCtx);
2270 AssertRCReturn(rc, rc);
2271 }
2272
2273 /* Sync back DR7. */
2274 VMXReadCachedVMCS(VMX_VMCS64_GUEST_DR7, &val);
2275 pCtx->dr[7] = val;
2276
2277 /* Guest CPU context: ES, CS, SS, DS, FS, GS. */
2278 VMX_READ_SELREG(ES, es);
2279 VMX_READ_SELREG(SS, ss);
2280 VMX_READ_SELREG(CS, cs);
2281 VMX_READ_SELREG(DS, ds);
2282 VMX_READ_SELREG(FS, fs);
2283 VMX_READ_SELREG(GS, gs);
2284
2285 /* System MSRs */
2286 VMXReadCachedVMCS(VMX_VMCS32_GUEST_SYSENTER_CS, &val);
2287 pCtx->SysEnter.cs = val;
2288 VMXReadCachedVMCS(VMX_VMCS64_GUEST_SYSENTER_EIP, &val);
2289 pCtx->SysEnter.eip = val;
2290 VMXReadCachedVMCS(VMX_VMCS64_GUEST_SYSENTER_ESP, &val);
2291 pCtx->SysEnter.esp = val;
2292
2293 /* Misc. registers; must sync everything otherwise we can get out of sync when jumping to ring 3. */
2294 VMX_READ_SELREG(LDTR, ldtr);
2295
2296 VMXReadCachedVMCS(VMX_VMCS32_GUEST_GDTR_LIMIT, &val);
2297 pCtx->gdtr.cbGdt = val;
2298 VMXReadCachedVMCS(VMX_VMCS64_GUEST_GDTR_BASE, &val);
2299 pCtx->gdtr.pGdt = val;
2300
2301 VMXReadCachedVMCS(VMX_VMCS32_GUEST_IDTR_LIMIT, &val);
2302 pCtx->idtr.cbIdt = val;
2303 VMXReadCachedVMCS(VMX_VMCS64_GUEST_IDTR_BASE, &val);
2304 pCtx->idtr.pIdt = val;
2305
2306 /* Real mode emulation using v86 mode. */
2307 if ( CPUMIsGuestInRealModeEx(pCtx)
2308 && pVM->hwaccm.s.vmx.pRealModeTSS)
2309 {
2310 /* Hide our emulation flags */
2311 pCtx->eflags.Bits.u1VM = 0;
2312
2313 /* Restore original IOPL setting as we always use 0. */
2314 pCtx->eflags.Bits.u2IOPL = pVCpu->hwaccm.s.vmx.RealMode.eflags.Bits.u2IOPL;
2315
2316 /* Force a TR resync every time in case we switch modes. */
2317 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_TR;
2318 }
2319 else
2320 {
2321 /* In real mode we have a fake TSS, so only sync it back when it's supposed to be valid. */
2322 VMX_READ_SELREG(TR, tr);
2323 }
2324
2325#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
2326 /* Save the possibly changed MSRs that we automatically restore and save during a world switch. */
2327 for (unsigned i = 0; i < pVCpu->hwaccm.s.vmx.cCachedMSRs; i++)
2328 {
2329 PVMXMSR pMsr = (PVMXMSR)pVCpu->hwaccm.s.vmx.pGuestMSR;
2330 pMsr += i;
2331
2332 switch (pMsr->u32IndexMSR)
2333 {
2334 case MSR_K8_LSTAR:
2335 pCtx->msrLSTAR = pMsr->u64Value;
2336 break;
2337 case MSR_K6_STAR:
2338 pCtx->msrSTAR = pMsr->u64Value;
2339 break;
2340 case MSR_K8_SF_MASK:
2341 pCtx->msrSFMASK = pMsr->u64Value;
2342 break;
2343 case MSR_K8_KERNEL_GS_BASE:
2344 pCtx->msrKERNELGSBASE = pMsr->u64Value;
2345 break;
2346 case MSR_K6_EFER:
2347 /* EFER can't be changed without causing a VM-exit. */
2348 /* Assert(pCtx->msrEFER == pMsr->u64Value); */
2349 break;
2350 default:
2351 AssertFailed();
2352 return VERR_HM_UNEXPECTED_LD_ST_MSR;
2353 }
2354 }
2355#endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
2356 return VINF_SUCCESS;
2357}
2358
2359
2360/**
2361 * Dummy placeholder for TLB flush handling before VM-entry. Used in the case
2362 * where neither EPT nor VPID is supported by the CPU.
2363 *
2364 * @param pVM Pointer to the VM.
2365 * @param pVCpu Pointer to the VMCPU.
2366 */
2367static DECLCALLBACK(void) hmR0VmxSetupTLBDummy(PVM pVM, PVMCPU pVCpu)
2368{
2369 NOREF(pVM);
2370 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
2371 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
2372 pVCpu->hwaccm.s.TlbShootdown.cPages = 0;
2373 return;
2374}
2375
2376
2377/**
2378 * Setup the tagged TLB for EPT+VPID.
2379 *
2380 * @param pVM Pointer to the VM.
2381 * @param pVCpu Pointer to the VMCPU.
2382 */
2383static DECLCALLBACK(void) hmR0VmxSetupTLBBoth(PVM pVM, PVMCPU pVCpu)
2384{
2385 PHMGLOBLCPUINFO pCpu;
2386
2387 Assert(pVM->hwaccm.s.fNestedPaging && pVM->hwaccm.s.vmx.fVPID);
2388
2389 pCpu = HWACCMR0GetCurrentCpu();
2390
2391 /*
2392 * Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last
2393 * This can happen both for start & resume due to long jumps back to ring-3.
2394 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB,
2395 * so we cannot reuse the current ASID anymore.
2396 */
2397 bool fNewASID = false;
2398 if ( pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu
2399 || pVCpu->hwaccm.s.cTLBFlushes != pCpu->cTLBFlushes)
2400 {
2401 pVCpu->hwaccm.s.fForceTLBFlush = true;
2402 fNewASID = true;
2403 }
2404
2405 /*
2406 * Check for explicit TLB shootdowns.
2407 */
2408 if (VMCPU_FF_TESTANDCLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2409 pVCpu->hwaccm.s.fForceTLBFlush = true;
2410
2411 pVCpu->hwaccm.s.idLastCpu = pCpu->idCpu;
2412
2413 if (pVCpu->hwaccm.s.fForceTLBFlush)
2414 {
2415 if (fNewASID)
2416 {
2417 ++pCpu->uCurrentASID;
2418 if (pCpu->uCurrentASID >= pVM->hwaccm.s.uMaxASID)
2419 {
2420 pCpu->uCurrentASID = 1; /* start at 1; host uses 0 */
2421 pCpu->cTLBFlushes++;
2422 pCpu->fFlushASIDBeforeUse = true;
2423 }
2424
2425 pVCpu->hwaccm.s.uCurrentASID = pCpu->uCurrentASID;
2426 if (pCpu->fFlushASIDBeforeUse)
2427 {
2428 hmR0VmxFlushVPID(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushVPID, 0 /* GCPtr */);
2429#ifdef VBOX_WITH_STATISTICS
2430 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushASID);
2431#endif
2432 }
2433 }
2434 else
2435 {
2436 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_SINGLE_CONTEXT)
2437 hmR0VmxFlushVPID(pVM, pVCpu, VMX_FLUSH_VPID_SINGLE_CONTEXT, 0 /* GCPtr */);
2438 else
2439 hmR0VmxFlushEPT(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushEPT);
2440
2441#ifdef VBOX_WITH_STATISTICS
2442 /*
2443 * This is not terribly accurate (i.e. we don't have any StatFlushEPT counter). We currently count these
2444 * as ASID flushes too, better than including them under StatFlushTLBWorldSwitch.
2445 */
2446 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushASID);
2447#endif
2448 }
2449
2450 pVCpu->hwaccm.s.cTLBFlushes = pCpu->cTLBFlushes;
2451 pVCpu->hwaccm.s.fForceTLBFlush = false;
2452 }
2453 else
2454 {
2455 AssertMsg(pVCpu->hwaccm.s.uCurrentASID && pCpu->uCurrentASID, ("hwaccm uCurrentASID=%lu cpu uCurrentASID=%lu\n",
2456 pVCpu->hwaccm.s.uCurrentASID, pCpu->uCurrentASID));
2457
2458 /** @todo We never set VMCPU_FF_TLB_SHOOTDOWN anywhere so this path should
2459 * not be executed. See hwaccmQueueInvlPage() where it is commented
2460 * out. Support individual entry flushing someday. */
2461 if (VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_TLB_SHOOTDOWN))
2462 {
2463 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdown);
2464
2465 /*
2466 * Flush individual guest entries using VPID from the TLB or as little as possible with EPT
2467 * as supported by the CPU.
2468 */
2469 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_INDIV_ADDR)
2470 {
2471 for (unsigned i = 0; i < pVCpu->hwaccm.s.TlbShootdown.cPages; i++)
2472 hmR0VmxFlushVPID(pVM, pVCpu, VMX_FLUSH_VPID_INDIV_ADDR, pVCpu->hwaccm.s.TlbShootdown.aPages[i]);
2473 }
2474 else
2475 hmR0VmxFlushEPT(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushEPT);
2476 }
2477 else
2478 {
2479#ifdef VBOX_WITH_STATISTICS
2480 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatNoFlushTLBWorldSwitch);
2481#endif
2482 }
2483 }
2484 pVCpu->hwaccm.s.TlbShootdown.cPages = 0;
2485 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
2486
2487 AssertMsg(pVCpu->hwaccm.s.cTLBFlushes == pCpu->cTLBFlushes,
2488 ("Flush count mismatch for cpu %d (%x vs %x)\n", pCpu->idCpu, pVCpu->hwaccm.s.cTLBFlushes, pCpu->cTLBFlushes));
2489 AssertMsg(pCpu->uCurrentASID >= 1 && pCpu->uCurrentASID < pVM->hwaccm.s.uMaxASID,
2490 ("cpu%d uCurrentASID = %x\n", pCpu->idCpu, pCpu->uCurrentASID));
2491 AssertMsg(pVCpu->hwaccm.s.uCurrentASID >= 1 && pVCpu->hwaccm.s.uCurrentASID < pVM->hwaccm.s.uMaxASID,
2492 ("cpu%d VM uCurrentASID = %x\n", pCpu->idCpu, pVCpu->hwaccm.s.uCurrentASID));
2493
2494 /* Update VMCS with the VPID. */
2495 int rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_VPID, pVCpu->hwaccm.s.uCurrentASID);
2496 AssertRC(rc);
2497}
2498
2499
2500/**
2501 * Setup the tagged TLB for EPT only.
2502 *
2503 * @returns VBox status code.
2504 * @param pVM Pointer to the VM.
2505 * @param pVCpu Pointer to the VMCPU.
2506 */
2507static DECLCALLBACK(void) hmR0VmxSetupTLBEPT(PVM pVM, PVMCPU pVCpu)
2508{
2509 PHMGLOBLCPUINFO pCpu;
2510
2511 Assert(pVM->hwaccm.s.fNestedPaging);
2512 Assert(!pVM->hwaccm.s.vmx.fVPID);
2513
2514 pCpu = HWACCMR0GetCurrentCpu();
2515
2516 /*
2517 * Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last
2518 * This can happen both for start & resume due to long jumps back to ring-3.
2519 * If the TLB flush count shouldn't really change in this EPT-only case.
2520 */
2521 if ( pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu
2522 || pVCpu->hwaccm.s.cTLBFlushes != pCpu->cTLBFlushes)
2523 {
2524 pVCpu->hwaccm.s.fForceTLBFlush = true;
2525 }
2526
2527 /*
2528 * Check for explicit TLB shootdown flushes.
2529 */
2530 if (VMCPU_FF_TESTANDCLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2531 pVCpu->hwaccm.s.fForceTLBFlush = true;
2532
2533 pVCpu->hwaccm.s.idLastCpu = pCpu->idCpu;
2534 pVCpu->hwaccm.s.cTLBFlushes = pCpu->cTLBFlushes;
2535
2536 if (pVCpu->hwaccm.s.fForceTLBFlush)
2537 hmR0VmxFlushEPT(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushEPT);
2538 else
2539 {
2540 /** @todo We never set VMCPU_FF_TLB_SHOOTDOWN anywhere so this path should
2541 * not be executed. See hwaccmQueueInvlPage() where it is commented
2542 * out. Support individual entry flushing someday. */
2543 if (VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_TLB_SHOOTDOWN))
2544 {
2545 /*
2546 * We cannot flush individual entries without VPID support. Flush using EPT.
2547 */
2548 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdown);
2549 hmR0VmxFlushEPT(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushEPT);
2550 }
2551 }
2552 pVCpu->hwaccm.s.TlbShootdown.cPages= 0;
2553 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
2554
2555#ifdef VBOX_WITH_STATISTICS
2556 if (pVCpu->hwaccm.s.fForceTLBFlush)
2557 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushTLBWorldSwitch);
2558 else
2559 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatNoFlushTLBWorldSwitch);
2560#endif
2561}
2562
2563
2564/**
2565 * Setup the tagged TLB for VPID.
2566 *
2567 * @returns VBox status code.
2568 * @param pVM Pointer to the VM.
2569 * @param pVCpu Pointer to the VMCPU.
2570 */
2571static DECLCALLBACK(void) hmR0VmxSetupTLBVPID(PVM pVM, PVMCPU pVCpu)
2572{
2573 PHMGLOBLCPUINFO pCpu;
2574
2575 Assert(pVM->hwaccm.s.vmx.fVPID);
2576 Assert(!pVM->hwaccm.s.fNestedPaging);
2577
2578 pCpu = HWACCMR0GetCurrentCpu();
2579
2580 /*
2581 * Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last
2582 * This can happen both for start & resume due to long jumps back to ring-3.
2583 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB,
2584 * so we cannot reuse the current ASID anymore.
2585 */
2586 if ( pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu
2587 || pVCpu->hwaccm.s.cTLBFlushes != pCpu->cTLBFlushes)
2588 {
2589 /* Force a TLB flush on VM entry. */
2590 pVCpu->hwaccm.s.fForceTLBFlush = true;
2591 }
2592
2593 /*
2594 * Check for explicit TLB shootdown flushes.
2595 */
2596 if (VMCPU_FF_TESTANDCLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
2597 pVCpu->hwaccm.s.fForceTLBFlush = true;
2598
2599 pVCpu->hwaccm.s.idLastCpu = pCpu->idCpu;
2600
2601 if (pVCpu->hwaccm.s.fForceTLBFlush)
2602 {
2603 ++pCpu->uCurrentASID;
2604 if (pCpu->uCurrentASID >= pVM->hwaccm.s.uMaxASID)
2605 {
2606 pCpu->uCurrentASID = 1; /* start at 1; host uses 0 */
2607 pCpu->cTLBFlushes++;
2608 pCpu->fFlushASIDBeforeUse = true;
2609 }
2610 else
2611 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushASID);
2612
2613 pVCpu->hwaccm.s.fForceTLBFlush = false;
2614 pVCpu->hwaccm.s.cTLBFlushes = pCpu->cTLBFlushes;
2615 pVCpu->hwaccm.s.uCurrentASID = pCpu->uCurrentASID;
2616 if (pCpu->fFlushASIDBeforeUse)
2617 hmR0VmxFlushVPID(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushVPID, 0 /* GCPtr */);
2618 }
2619 else
2620 {
2621 Assert(pVCpu->hwaccm.s.uCurrentASID && pCpu->uCurrentASID);
2622
2623 /** @todo We never set VMCPU_FF_TLB_SHOOTDOWN anywhere so this path should
2624 * not be executed. See hwaccmQueueInvlPage() where it is commented
2625 * out. Support individual entry flushing someday. */
2626 if (VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_TLB_SHOOTDOWN))
2627 {
2628 /*
2629 * Flush individual guest entries using VPID from the TLB or as little as possible with EPT
2630 * as supported by the CPU.
2631 */
2632 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_INDIV_ADDR)
2633 {
2634 for (unsigned i = 0; i < pVCpu->hwaccm.s.TlbShootdown.cPages; i++)
2635 hmR0VmxFlushVPID(pVM, pVCpu, VMX_FLUSH_VPID_INDIV_ADDR, pVCpu->hwaccm.s.TlbShootdown.aPages[i]);
2636 }
2637 else
2638 hmR0VmxFlushVPID(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushVPID, 0 /* GCPtr */);
2639 }
2640 }
2641 pVCpu->hwaccm.s.TlbShootdown.cPages = 0;
2642 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
2643
2644 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));
2645 AssertMsg(pCpu->uCurrentASID >= 1 && pCpu->uCurrentASID < pVM->hwaccm.s.uMaxASID, ("cpu%d uCurrentASID = %x\n", pCpu->idCpu, pCpu->uCurrentASID));
2646 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));
2647
2648 int rc = VMXWriteVMCS(VMX_VMCS16_GUEST_FIELD_VPID, pVCpu->hwaccm.s.uCurrentASID);
2649 AssertRC(rc);
2650
2651# ifdef VBOX_WITH_STATISTICS
2652 if (pVCpu->hwaccm.s.fForceTLBFlush)
2653 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushTLBWorldSwitch);
2654 else
2655 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatNoFlushTLBWorldSwitch);
2656# endif
2657}
2658
2659
2660/**
2661 * Runs guest code in a VT-x VM.
2662 *
2663 * @returns VBox status code.
2664 * @param pVM Pointer to the VM.
2665 * @param pVCpu Pointer to the VMCPU.
2666 * @param pCtx Pointer to the guest CPU context.
2667 */
2668VMMR0DECL(int) VMXR0RunGuestCode(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
2669{
2670 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatEntry, x);
2671 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hwaccm.s.StatExit1);
2672 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hwaccm.s.StatExit2);
2673
2674 VBOXSTRICTRC rc = VINF_SUCCESS;
2675 int rc2;
2676 RTGCUINTREG val;
2677 RTGCUINTREG exitReason = (RTGCUINTREG)VMX_EXIT_INVALID;
2678 RTGCUINTREG instrError, cbInstr;
2679 RTGCUINTPTR exitQualification = 0;
2680 RTGCUINTPTR intInfo = 0; /* shut up buggy gcc 4 */
2681 RTGCUINTPTR errCode, instrInfo;
2682 bool fSetupTPRCaching = false;
2683 uint64_t u64OldLSTAR = 0;
2684 uint8_t u8LastTPR = 0;
2685 RTCCUINTREG uOldEFlags = ~(RTCCUINTREG)0;
2686 unsigned cResume = 0;
2687#ifdef VBOX_STRICT
2688 RTCPUID idCpuCheck;
2689 bool fWasInLongMode = false;
2690#endif
2691#ifdef VBOX_HIGH_RES_TIMERS_HACK_IN_RING0
2692 uint64_t u64LastTime = RTTimeMilliTS();
2693#endif
2694
2695 Assert(!(pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC) || (pVCpu->hwaccm.s.vmx.pbVAPIC && pVM->hwaccm.s.vmx.pAPIC));
2696
2697 /*
2698 * Check if we need to use TPR shadowing.
2699 */
2700 if ( CPUMIsGuestInLongModeEx(pCtx)
2701 || ( ((pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC) || pVM->hwaccm.s.fTRPPatchingAllowed)
2702 && pVM->hwaccm.s.fHasIoApic)
2703 )
2704 {
2705 fSetupTPRCaching = true;
2706 }
2707
2708 Log2(("\nE"));
2709
2710#ifdef VBOX_STRICT
2711 {
2712 RTCCUINTREG val2;
2713
2714 rc2 = VMXReadVMCS(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, &val2);
2715 AssertRC(rc2);
2716 Log2(("VMX_VMCS_CTRL_PIN_EXEC_CONTROLS = %08x\n", val2));
2717
2718 /* allowed zero */
2719 if ((val2 & pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.disallowed0) != pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.disallowed0)
2720 Log(("Invalid VMX_VMCS_CTRL_PIN_EXEC_CONTROLS: zero\n"));
2721
2722 /* allowed one */
2723 if ((val2 & ~pVM->hwaccm.s.vmx.msr.vmx_pin_ctls.n.allowed1) != 0)
2724 Log(("Invalid VMX_VMCS_CTRL_PIN_EXEC_CONTROLS: one\n"));
2725
2726 rc2 = VMXReadVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, &val2);
2727 AssertRC(rc2);
2728 Log2(("VMX_VMCS_CTRL_PROC_EXEC_CONTROLS = %08x\n", val2));
2729
2730 /*
2731 * Must be set according to the MSR, but can be cleared if nested paging is used.
2732 */
2733 if (pVM->hwaccm.s.fNestedPaging)
2734 {
2735 val2 |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_INVLPG_EXIT
2736 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_LOAD_EXIT
2737 | VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_CR3_STORE_EXIT;
2738 }
2739
2740 /* allowed zero */
2741 if ((val2 & pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.disallowed0) != pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.disallowed0)
2742 Log(("Invalid VMX_VMCS_CTRL_PROC_EXEC_CONTROLS: zero\n"));
2743
2744 /* allowed one */
2745 if ((val2 & ~pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1) != 0)
2746 Log(("Invalid VMX_VMCS_CTRL_PROC_EXEC_CONTROLS: one\n"));
2747
2748 rc2 = VMXReadVMCS(VMX_VMCS_CTRL_ENTRY_CONTROLS, &val2);
2749 AssertRC(rc2);
2750 Log2(("VMX_VMCS_CTRL_ENTRY_CONTROLS = %08x\n", val2));
2751
2752 /* allowed zero */
2753 if ((val2 & pVM->hwaccm.s.vmx.msr.vmx_entry.n.disallowed0) != pVM->hwaccm.s.vmx.msr.vmx_entry.n.disallowed0)
2754 Log(("Invalid VMX_VMCS_CTRL_ENTRY_CONTROLS: zero\n"));
2755
2756 /* allowed one */
2757 if ((val2 & ~pVM->hwaccm.s.vmx.msr.vmx_entry.n.allowed1) != 0)
2758 Log(("Invalid VMX_VMCS_CTRL_ENTRY_CONTROLS: one\n"));
2759
2760 rc2 = VMXReadVMCS(VMX_VMCS_CTRL_EXIT_CONTROLS, &val2);
2761 AssertRC(rc2);
2762 Log2(("VMX_VMCS_CTRL_EXIT_CONTROLS = %08x\n", val2));
2763
2764 /* allowed zero */
2765 if ((val2 & pVM->hwaccm.s.vmx.msr.vmx_exit.n.disallowed0) != pVM->hwaccm.s.vmx.msr.vmx_exit.n.disallowed0)
2766 Log(("Invalid VMX_VMCS_CTRL_EXIT_CONTROLS: zero\n"));
2767
2768 /* allowed one */
2769 if ((val2 & ~pVM->hwaccm.s.vmx.msr.vmx_exit.n.allowed1) != 0)
2770 Log(("Invalid VMX_VMCS_CTRL_EXIT_CONTROLS: one\n"));
2771 }
2772 fWasInLongMode = CPUMIsGuestInLongModeEx(pCtx);
2773#endif /* VBOX_STRICT */
2774
2775#ifdef VBOX_WITH_CRASHDUMP_MAGIC
2776 pVCpu->hwaccm.s.vmx.VMCSCache.u64TimeEntry = RTTimeNanoTS();
2777#endif
2778
2779 /*
2780 * We can jump to this point to resume execution after determining that a VM-exit is innocent.
2781 */
2782ResumeExecution:
2783 if (!STAM_REL_PROFILE_ADV_IS_RUNNING(&pVCpu->hwaccm.s.StatEntry))
2784 STAM_REL_PROFILE_ADV_STOP_START(&pVCpu->hwaccm.s.StatExit2, &pVCpu->hwaccm.s.StatEntry, x);
2785 AssertMsg(pVCpu->hwaccm.s.idEnteredCpu == RTMpCpuId(),
2786 ("Expected %d, I'm %d; cResume=%d exitReason=%RGv exitQualification=%RGv\n",
2787 (int)pVCpu->hwaccm.s.idEnteredCpu, (int)RTMpCpuId(), cResume, exitReason, exitQualification));
2788 Assert(!HWACCMR0SuspendPending());
2789 /* Not allowed to switch modes without reloading the host state (32->64 switcher)!! */
2790 Assert(fWasInLongMode == CPUMIsGuestInLongModeEx(pCtx));
2791
2792 /*
2793 * Safety precaution; looping for too long here can have a very bad effect on the host.
2794 */
2795 if (RT_UNLIKELY(++cResume > pVM->hwaccm.s.cMaxResumeLoops))
2796 {
2797 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitMaxResume);
2798 rc = VINF_EM_RAW_INTERRUPT;
2799 goto end;
2800 }
2801
2802 /*
2803 * Check for IRQ inhibition due to instruction fusing (sti, mov ss).
2804 */
2805 if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
2806 {
2807 Log(("VM_FF_INHIBIT_INTERRUPTS at %RGv successor %RGv\n", (RTGCPTR)pCtx->rip, EMGetInhibitInterruptsPC(pVCpu)));
2808 if (pCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
2809 {
2810 /*
2811 * Note: we intentionally don't clear VM_FF_INHIBIT_INTERRUPTS here.
2812 * Before we are able to execute this instruction in raw mode (iret to guest code) an external interrupt might
2813 * force a world switch again. Possibly allowing a guest interrupt to be dispatched in the process. This could
2814 * break the guest. Sounds very unlikely, but such timing sensitive problems are not as rare as you might think.
2815 */
2816 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
2817 /* Irq inhibition is no longer active; clear the corresponding VMX state. */
2818 rc2 = VMXWriteVMCS(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, 0);
2819 AssertRC(rc2);
2820 }
2821 }
2822 else
2823 {
2824 /* Irq inhibition is no longer active; clear the corresponding VMX state. */
2825 rc2 = VMXWriteVMCS(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE, 0);
2826 AssertRC(rc2);
2827 }
2828
2829#ifdef VBOX_HIGH_RES_TIMERS_HACK_IN_RING0
2830 if (RT_UNLIKELY((cResume & 0xf) == 0))
2831 {
2832 uint64_t u64CurTime = RTTimeMilliTS();
2833
2834 if (RT_UNLIKELY(u64CurTime > u64LastTime))
2835 {
2836 u64LastTime = u64CurTime;
2837 TMTimerPollVoid(pVM, pVCpu);
2838 }
2839 }
2840#endif
2841
2842 /*
2843 * Check for pending actions that force us to go back to ring-3.
2844 */
2845 if ( VM_FF_ISPENDING(pVM, VM_FF_HWACCM_TO_R3_MASK | VM_FF_REQUEST | VM_FF_PGM_POOL_FLUSH_PENDING | VM_FF_PDM_DMA)
2846 || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_HWACCM_TO_R3_MASK | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_REQUEST))
2847 {
2848 /* Check if a sync operation is pending. */
2849 if (VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
2850 {
2851 rc = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
2852 if (rc != VINF_SUCCESS)
2853 {
2854 AssertRC(VBOXSTRICTRC_VAL(rc));
2855 Log(("Pending pool sync is forcing us back to ring 3; rc=%d\n", VBOXSTRICTRC_VAL(rc)));
2856 goto end;
2857 }
2858 }
2859
2860#ifdef DEBUG
2861 /* Intercept X86_XCPT_DB if stepping is enabled */
2862 if (!DBGFIsStepping(pVCpu))
2863#endif
2864 {
2865 if ( VM_FF_ISPENDING(pVM, VM_FF_HWACCM_TO_R3_MASK)
2866 || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_HWACCM_TO_R3_MASK))
2867 {
2868 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatSwitchToR3);
2869 rc = RT_UNLIKELY(VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
2870 goto end;
2871 }
2872 }
2873
2874 /* Pending request packets might contain actions that need immediate attention, such as pending hardware interrupts. */
2875 if ( VM_FF_ISPENDING(pVM, VM_FF_REQUEST)
2876 || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_REQUEST))
2877 {
2878 rc = VINF_EM_PENDING_REQUEST;
2879 goto end;
2880 }
2881
2882 /* Check if a pgm pool flush is in progress. */
2883 if (VM_FF_ISPENDING(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
2884 {
2885 rc = VINF_PGM_POOL_FLUSH_PENDING;
2886 goto end;
2887 }
2888
2889 /* Check if DMA work is pending (2nd+ run). */
2890 if (VM_FF_ISPENDING(pVM, VM_FF_PDM_DMA) && cResume > 1)
2891 {
2892 rc = VINF_EM_RAW_TO_R3;
2893 goto end;
2894 }
2895 }
2896
2897#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
2898 /*
2899 * Exit to ring-3 preemption/work is pending.
2900 *
2901 * Interrupts are disabled before the call to make sure we don't miss any interrupt
2902 * that would flag preemption (IPI, timer tick, ++). (Would've been nice to do this
2903 * further down, but hmR0VmxCheckPendingInterrupt makes that impossible.)
2904 *
2905 * Note! Interrupts must be disabled done *before* we check for TLB flushes; TLB
2906 * shootdowns rely on this.
2907 */
2908 uOldEFlags = ASMIntDisableFlags();
2909 if (RTThreadPreemptIsPending(NIL_RTTHREAD))
2910 {
2911 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitPreemptPending);
2912 rc = VINF_EM_RAW_INTERRUPT;
2913 goto end;
2914 }
2915 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
2916#endif
2917
2918 /*
2919 * When external interrupts are pending, we should exit the VM when IF is et.
2920 * Note: *After* VM_FF_INHIBIT_INTERRUPTS check!
2921 */
2922 rc = hmR0VmxCheckPendingInterrupt(pVM, pVCpu, pCtx);
2923 if (RT_FAILURE(rc))
2924 goto end;
2925
2926 /** @todo check timers?? */
2927
2928 /*
2929 * TPR caching using CR8 is only available in 64-bit mode.
2930 * Note: The 32-bit exception for AMD (X86_CPUID_AMD_FEATURE_ECX_CR8L), but this appears missing in Intel CPUs.
2931 * Note: We can't do this in LoadGuestState() as PDMApicGetTPR can jump back to ring-3 (lock)!! (no longer true) .
2932 */
2933 /** @todo query and update the TPR only when it could have been changed (mmio
2934 * access & wrsmr (x2apic) */
2935 if (fSetupTPRCaching)
2936 {
2937 /* TPR caching in CR8 */
2938 bool fPending;
2939
2940 rc2 = PDMApicGetTPR(pVCpu, &u8LastTPR, &fPending);
2941 AssertRC(rc2);
2942 /* The TPR can be found at offset 0x80 in the APIC mmio page. */
2943 pVCpu->hwaccm.s.vmx.pbVAPIC[0x80] = u8LastTPR;
2944
2945 /*
2946 * Two options here:
2947 * - external interrupt pending, but masked by the TPR value.
2948 * -> a CR8 update that lower the current TPR value should cause an exit
2949 * - no pending interrupts
2950 * -> We don't need to be explicitely notified. There are enough world switches for detecting pending interrupts.
2951 */
2952 rc = VMXWriteVMCS(VMX_VMCS_CTRL_TPR_THRESHOLD, (fPending) ? (u8LastTPR >> 4) : 0); /* cr8 bits 3-0 correspond to bits 7-4 of the task priority mmio register. */
2953 AssertRC(VBOXSTRICTRC_VAL(rc));
2954
2955 if (pVM->hwaccm.s.fTPRPatchingActive)
2956 {
2957 Assert(!CPUMIsGuestInLongModeEx(pCtx));
2958 /* Our patch code uses LSTAR for TPR caching. */
2959 pCtx->msrLSTAR = u8LastTPR;
2960
2961 if (fPending)
2962 {
2963 /* A TPR change could activate a pending interrupt, so catch lstar writes. */
2964 hmR0VmxSetMSRPermission(pVCpu, MSR_K8_LSTAR, true, false);
2965 }
2966 else
2967 {
2968 /*
2969 * No interrupts are pending, so we don't need to be explicitely notified.
2970 * There are enough world switches for detecting pending interrupts.
2971 */
2972 hmR0VmxSetMSRPermission(pVCpu, MSR_K8_LSTAR, true, true);
2973 }
2974 }
2975 }
2976
2977#ifdef LOG_ENABLED
2978 if ( pVM->hwaccm.s.fNestedPaging
2979 || pVM->hwaccm.s.vmx.fVPID)
2980 {
2981 PHMGLOBLCPUINFO pCpu = HWACCMR0GetCurrentCpu();
2982 if ( pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu
2983 || pVCpu->hwaccm.s.cTLBFlushes != pCpu->cTLBFlushes)
2984 {
2985 if (pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu)
2986 LogFlow(("Force TLB flush due to rescheduling to a different cpu (%d vs %d)\n", pVCpu->hwaccm.s.idLastCpu, pCpu->idCpu));
2987 else
2988 LogFlow(("Force TLB flush due to changed TLB flush count (%x vs %x)\n", pVCpu->hwaccm.s.cTLBFlushes, pCpu->cTLBFlushes));
2989 }
2990 else if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_TLB_FLUSH))
2991 LogFlow(("Manual TLB flush\n"));
2992 }
2993#endif
2994#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
2995 PGMRZDynMapFlushAutoSet(pVCpu);
2996#endif
2997
2998 /*
2999 * NOTE: DO NOT DO ANYTHING AFTER THIS POINT THAT MIGHT JUMP BACK TO RING-3!
3000 * (until the actual world switch)
3001 */
3002#ifdef VBOX_STRICT
3003 idCpuCheck = RTMpCpuId();
3004#endif
3005#ifdef LOG_ENABLED
3006 VMMR0LogFlushDisable(pVCpu);
3007#endif
3008
3009 /*
3010 * Save the host state first.
3011 */
3012 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_HOST_CONTEXT)
3013 {
3014 rc = VMXR0SaveHostState(pVM, pVCpu);
3015 if (RT_UNLIKELY(rc != VINF_SUCCESS))
3016 {
3017 VMMR0LogFlushEnable(pVCpu);
3018 goto end;
3019 }
3020 }
3021
3022 /*
3023 * Load the guest state.
3024 */
3025 if (!pVCpu->hwaccm.s.fContextUseFlags)
3026 {
3027 VMXR0LoadMinimalGuestState(pVM, pVCpu, pCtx);
3028 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatLoadMinimal);
3029 }
3030 else
3031 {
3032 rc = VMXR0LoadGuestState(pVM, pVCpu, pCtx);
3033 if (RT_UNLIKELY(rc != VINF_SUCCESS))
3034 {
3035 VMMR0LogFlushEnable(pVCpu);
3036 goto end;
3037 }
3038 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatLoadFull);
3039 }
3040
3041#ifndef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
3042 /*
3043 * Disable interrupts to make sure a poke will interrupt execution.
3044 * This must be done *before* we check for TLB flushes; TLB shootdowns rely on this.
3045 */
3046 uOldEFlags = ASMIntDisableFlags();
3047 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
3048#endif
3049
3050 /* Non-register state Guest Context */
3051 /** @todo change me according to cpu state */
3052 rc2 = VMXWriteVMCS(VMX_VMCS32_GUEST_ACTIVITY_STATE, VMX_CMS_GUEST_ACTIVITY_ACTIVE);
3053 AssertRC(rc2);
3054
3055 /* Set TLB flush state as checked until we return from the world switch. */
3056 ASMAtomicWriteBool(&pVCpu->hwaccm.s.fCheckedTLBFlush, true);
3057 /* Deal with tagged TLB setup and invalidation. */
3058 pVM->hwaccm.s.vmx.pfnSetupTaggedTLB(pVM, pVCpu);
3059
3060 /*
3061 * Manual save and restore:
3062 * - General purpose registers except RIP, RSP
3063 *
3064 * Trashed:
3065 * - CR2 (we don't care)
3066 * - LDTR (reset to 0)
3067 * - DRx (presumably not changed at all)
3068 * - DR7 (reset to 0x400)
3069 * - EFLAGS (reset to RT_BIT(1); not relevant)
3070 */
3071
3072 /* All done! Let's start VM execution. */
3073 STAM_PROFILE_ADV_STOP_START(&pVCpu->hwaccm.s.StatEntry, &pVCpu->hwaccm.s.StatInGC, x);
3074 Assert(idCpuCheck == RTMpCpuId());
3075
3076#ifdef VBOX_WITH_CRASHDUMP_MAGIC
3077 pVCpu->hwaccm.s.vmx.VMCSCache.cResume = cResume;
3078 pVCpu->hwaccm.s.vmx.VMCSCache.u64TimeSwitch = RTTimeNanoTS();
3079#endif
3080
3081 /*
3082 * Save the current TPR value in the LSTAR MSR so our patches can access it.
3083 */
3084 if (pVM->hwaccm.s.fTPRPatchingActive)
3085 {
3086 Assert(pVM->hwaccm.s.fTPRPatchingActive);
3087 u64OldLSTAR = ASMRdMsr(MSR_K8_LSTAR);
3088 ASMWrMsr(MSR_K8_LSTAR, u8LastTPR);
3089 }
3090
3091 TMNotifyStartOfExecution(pVCpu);
3092#ifdef VBOX_WITH_KERNEL_USING_XMM
3093 rc = hwaccmR0VMXStartVMWrapXMM(pVCpu->hwaccm.s.fResumeVM, pCtx, &pVCpu->hwaccm.s.vmx.VMCSCache, pVM, pVCpu, pVCpu->hwaccm.s.vmx.pfnStartVM);
3094#else
3095 rc = pVCpu->hwaccm.s.vmx.pfnStartVM(pVCpu->hwaccm.s.fResumeVM, pCtx, &pVCpu->hwaccm.s.vmx.VMCSCache, pVM, pVCpu);
3096#endif
3097 ASMAtomicWriteBool(&pVCpu->hwaccm.s.fCheckedTLBFlush, false);
3098 ASMAtomicIncU32(&pVCpu->hwaccm.s.cWorldSwitchExits);
3099 /* Possibly the last TSC value seen by the guest (too high) (only when we're in TSC offset mode). */
3100 if (!(pVCpu->hwaccm.s.vmx.proc_ctls & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_RDTSC_EXIT))
3101 {
3102 TMCpuTickSetLastSeen(pVCpu,
3103 ASMReadTSC() + pVCpu->hwaccm.s.vmx.u64TSCOffset - 0x400 /* guestimate of world switch overhead in clock ticks */);
3104 }
3105
3106 TMNotifyEndOfExecution(pVCpu);
3107 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
3108 Assert(!(ASMGetFlags() & X86_EFL_IF));
3109
3110 /*
3111 * Restore the host LSTAR MSR if the guest could have changed it.
3112 */
3113 if (pVM->hwaccm.s.fTPRPatchingActive)
3114 {
3115 Assert(pVM->hwaccm.s.fTPRPatchingActive);
3116 pVCpu->hwaccm.s.vmx.pbVAPIC[0x80] = pCtx->msrLSTAR = ASMRdMsr(MSR_K8_LSTAR);
3117 ASMWrMsr(MSR_K8_LSTAR, u64OldLSTAR);
3118 }
3119
3120 STAM_PROFILE_ADV_STOP_START(&pVCpu->hwaccm.s.StatInGC, &pVCpu->hwaccm.s.StatExit1, x);
3121 ASMSetFlags(uOldEFlags);
3122#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
3123 uOldEFlags = ~(RTCCUINTREG)0;
3124#endif
3125
3126 AssertMsg(!pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries, ("pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries=%d\n", pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries));
3127
3128 /* In case we execute a goto ResumeExecution later on. */
3129 pVCpu->hwaccm.s.fResumeVM = true;
3130 pVCpu->hwaccm.s.fForceTLBFlush = false;
3131
3132 /*
3133 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3134 * 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
3135 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3136 */
3137
3138 if (RT_UNLIKELY(rc != VINF_SUCCESS))
3139 {
3140 hmR0VmxReportWorldSwitchError(pVM, pVCpu, rc, pCtx);
3141 VMMR0LogFlushEnable(pVCpu);
3142 goto end;
3143 }
3144
3145 /* Success. Query the guest state and figure out what has happened. */
3146
3147 /* Investigate why there was a VM-exit. */
3148 rc2 = VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_REASON, &exitReason);
3149 STAM_COUNTER_INC(&pVCpu->hwaccm.s.paStatExitReasonR0[exitReason & MASK_EXITREASON_STAT]);
3150
3151 exitReason &= 0xffff; /* bit 0-15 contain the exit code. */
3152 rc2 |= VMXReadCachedVMCS(VMX_VMCS32_RO_VM_INSTR_ERROR, &instrError);
3153 rc2 |= VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_INSTR_LENGTH, &cbInstr);
3154 rc2 |= VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO, &intInfo);
3155 /* might not be valid; depends on VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID. */
3156 rc2 |= VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_INTERRUPTION_ERRCODE, &errCode);
3157 rc2 |= VMXReadCachedVMCS(VMX_VMCS32_RO_EXIT_INSTR_INFO, &instrInfo);
3158 rc2 |= VMXReadCachedVMCS(VMX_VMCS_RO_EXIT_QUALIFICATION, &exitQualification);
3159 AssertRC(rc2);
3160
3161 /*
3162 * Sync back the guest state.
3163 */
3164 rc2 = VMXR0SaveGuestState(pVM, pVCpu, pCtx);
3165 AssertRC(rc2);
3166
3167 /* Note! NOW IT'S SAFE FOR LOGGING! */
3168 VMMR0LogFlushEnable(pVCpu);
3169 Log2(("Raw exit reason %08x\n", exitReason));
3170#if ARCH_BITS == 64 /* for the time being */
3171 VBOXVMM_R0_HMVMX_VMEXIT(pVCpu, pCtx, exitReason);
3172#endif
3173
3174 /*
3175 * Check if an injected event was interrupted prematurely.
3176 */
3177 rc2 = VMXReadCachedVMCS(VMX_VMCS32_RO_IDT_INFO, &val);
3178 AssertRC(rc2);
3179 pVCpu->hwaccm.s.Event.intInfo = VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(val);
3180 if ( VMX_EXIT_INTERRUPTION_INFO_VALID(pVCpu->hwaccm.s.Event.intInfo)
3181 /* Ignore 'int xx' as they'll be restarted anyway. */
3182 && VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hwaccm.s.Event.intInfo) != VMX_EXIT_INTERRUPTION_INFO_TYPE_SW
3183 /* Ignore software exceptions (such as int3) as they'll reoccur when we restart the instruction anyway. */
3184 && VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hwaccm.s.Event.intInfo) != VMX_EXIT_INTERRUPTION_INFO_TYPE_SWEXCPT)
3185 {
3186 Assert(!pVCpu->hwaccm.s.Event.fPending);
3187 pVCpu->hwaccm.s.Event.fPending = true;
3188 /* Error code present? */
3189 if (VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(pVCpu->hwaccm.s.Event.intInfo))
3190 {
3191 rc2 = VMXReadCachedVMCS(VMX_VMCS32_RO_IDT_ERRCODE, &val);
3192 AssertRC(rc2);
3193 pVCpu->hwaccm.s.Event.errCode = val;
3194 Log(("Pending inject %RX64 at %RGv exit=%08x intInfo=%08x exitQualification=%RGv pending error=%RX64\n",
3195 pVCpu->hwaccm.s.Event.intInfo, (RTGCPTR)pCtx->rip, exitReason, intInfo, exitQualification, val));
3196 }
3197 else
3198 {
3199 Log(("Pending inject %RX64 at %RGv exit=%08x intInfo=%08x exitQualification=%RGv\n", pVCpu->hwaccm.s.Event.intInfo,
3200 (RTGCPTR)pCtx->rip, exitReason, intInfo, exitQualification));
3201 pVCpu->hwaccm.s.Event.errCode = 0;
3202 }
3203 }
3204#ifdef VBOX_STRICT
3205 else if ( VMX_EXIT_INTERRUPTION_INFO_VALID(pVCpu->hwaccm.s.Event.intInfo)
3206 /* Ignore software exceptions (such as int3) as they're reoccur when we restart the instruction anyway. */
3207 && VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hwaccm.s.Event.intInfo) == VMX_EXIT_INTERRUPTION_INFO_TYPE_SWEXCPT)
3208 {
3209 Log(("Ignore pending inject %RX64 at %RGv exit=%08x intInfo=%08x exitQualification=%RGv\n",
3210 pVCpu->hwaccm.s.Event.intInfo, (RTGCPTR)pCtx->rip, exitReason, intInfo, exitQualification));
3211 }
3212
3213 if (exitReason == VMX_EXIT_ERR_INVALID_GUEST_STATE)
3214 HWACCMDumpRegs(pVM, pVCpu, pCtx);
3215#endif
3216
3217 Log2(("E%d: New EIP=%x:%RGv\n", (uint32_t)exitReason, pCtx->cs.Sel, (RTGCPTR)pCtx->rip));
3218 Log2(("Exit reason %d, exitQualification %RGv\n", (uint32_t)exitReason, exitQualification));
3219 Log2(("instrInfo=%d instrError=%d instr length=%d\n", (uint32_t)instrInfo, (uint32_t)instrError, (uint32_t)cbInstr));
3220 Log2(("Interruption error code %d\n", (uint32_t)errCode));
3221 Log2(("IntInfo = %08x\n", (uint32_t)intInfo));
3222
3223 /*
3224 * Sync back the TPR if it was changed.
3225 */
3226 if ( fSetupTPRCaching
3227 && u8LastTPR != pVCpu->hwaccm.s.vmx.pbVAPIC[0x80])
3228 {
3229 rc2 = PDMApicSetTPR(pVCpu, pVCpu->hwaccm.s.vmx.pbVAPIC[0x80]);
3230 AssertRC(rc2);
3231 }
3232
3233#ifdef DBGFTRACE_ENABLED /** @todo DTrace later. */
3234 RTTraceBufAddMsgF(pVM->CTX_SUFF(hTraceBuf), "vmexit %08x %016RX64 at %04:%08RX64 %RX64",
3235 exitReason, (uint64_t)exitQualification, pCtx->cs.Sel, pCtx->rip, (uint64_t)intInfo);
3236#endif
3237 STAM_PROFILE_ADV_STOP_START(&pVCpu->hwaccm.s.StatExit1, &pVCpu->hwaccm.s.StatExit2, x);
3238
3239 /* Some cases don't need a complete resync of the guest CPU state; handle them here. */
3240 Assert(rc == VINF_SUCCESS); /* might consider VERR_IPE_UNINITIALIZED_STATUS here later... */
3241 switch (exitReason)
3242 {
3243 case VMX_EXIT_EXCEPTION: /* 0 Exception or non-maskable interrupt (NMI). */
3244 case VMX_EXIT_EXTERNAL_IRQ: /* 1 External interrupt. */
3245 {
3246 uint32_t vector = VMX_EXIT_INTERRUPTION_INFO_VECTOR(intInfo);
3247
3248 if (!VMX_EXIT_INTERRUPTION_INFO_VALID(intInfo))
3249 {
3250 Assert(exitReason == VMX_EXIT_EXTERNAL_IRQ);
3251#if 0 //def VBOX_WITH_VMMR0_DISABLE_PREEMPTION
3252 if ( RTThreadPreemptIsPendingTrusty()
3253 && !RTThreadPreemptIsPending(NIL_RTTHREAD))
3254 goto ResumeExecution;
3255#endif
3256 /* External interrupt; leave to allow it to be dispatched again. */
3257 rc = VINF_EM_RAW_INTERRUPT;
3258 break;
3259 }
3260 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3261 switch (VMX_EXIT_INTERRUPTION_INFO_TYPE(intInfo))
3262 {
3263 case VMX_EXIT_INTERRUPTION_INFO_TYPE_NMI: /* Non-maskable interrupt. */
3264 /* External interrupt; leave to allow it to be dispatched again. */
3265 rc = VINF_EM_RAW_INTERRUPT;
3266 break;
3267
3268 case VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT: /* External hardware interrupt. */
3269 AssertFailed(); /* can't come here; fails the first check. */
3270 break;
3271
3272 case VMX_EXIT_INTERRUPTION_INFO_TYPE_DBEXCPT: /* Unknown why we get this type for #DB */
3273 case VMX_EXIT_INTERRUPTION_INFO_TYPE_SWEXCPT: /* Software exception. (#BP or #OF) */
3274 Assert(vector == 1 || vector == 3 || vector == 4);
3275 /* no break */
3276 case VMX_EXIT_INTERRUPTION_INFO_TYPE_HWEXCPT: /* Hardware exception. */
3277 Log2(("Hardware/software interrupt %d\n", vector));
3278 switch (vector)
3279 {
3280 case X86_XCPT_NM:
3281 {
3282 Log(("#NM fault at %RGv error code %x\n", (RTGCPTR)pCtx->rip, errCode));
3283
3284 /** @todo don't intercept #NM exceptions anymore when we've activated the guest FPU state. */
3285 /* If we sync the FPU/XMM state on-demand, then we can continue execution as if nothing has happened. */
3286 rc = CPUMR0LoadGuestFPU(pVM, pVCpu, pCtx);
3287 if (rc == VINF_SUCCESS)
3288 {
3289 Assert(CPUMIsGuestFPUStateActive(pVCpu));
3290
3291 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitShadowNM);
3292
3293 /* Continue execution. */
3294 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
3295
3296 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3297 goto ResumeExecution;
3298 }
3299
3300 Log(("Forward #NM fault to the guest\n"));
3301 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestNM);
3302 rc2 = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
3303 cbInstr, 0);
3304 AssertRC(rc2);
3305 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3306 goto ResumeExecution;
3307 }
3308
3309 case X86_XCPT_PF: /* Page fault */
3310 {
3311#ifdef VBOX_ALWAYS_TRAP_PF
3312 if (pVM->hwaccm.s.fNestedPaging)
3313 {
3314 /*
3315 * A genuine pagefault. Forward the trap to the guest by injecting the exception and resuming execution.
3316 */
3317 Log(("Guest page fault at %RGv cr2=%RGv error code %RGv rsp=%RGv\n", (RTGCPTR)pCtx->rip, exitQualification,
3318 errCode, (RTGCPTR)pCtx->rsp));
3319
3320 Assert(CPUMIsGuestInPagedProtectedModeEx(pCtx));
3321
3322 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestPF);
3323
3324 /* Now we must update CR2. */
3325 pCtx->cr2 = exitQualification;
3326 rc2 = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
3327 cbInstr, errCode);
3328 AssertRC(rc2);
3329
3330 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3331 goto ResumeExecution;
3332 }
3333#else
3334 Assert(!pVM->hwaccm.s.fNestedPaging);
3335#endif
3336
3337#ifdef VBOX_HWACCM_WITH_GUEST_PATCHING
3338 /* Shortcut for APIC TPR reads and writes; 32 bits guests only */
3339 if ( pVM->hwaccm.s.fTRPPatchingAllowed
3340 && pVM->hwaccm.s.pGuestPatchMem
3341 && (exitQualification & 0xfff) == 0x080
3342 && !(errCode & X86_TRAP_PF_P) /* not present */
3343 && CPUMGetGuestCPL(pVCpu) == 0
3344 && !CPUMIsGuestInLongModeEx(pCtx)
3345 && pVM->hwaccm.s.cPatches < RT_ELEMENTS(pVM->hwaccm.s.aPatches))
3346 {
3347 RTGCPHYS GCPhysApicBase, GCPhys;
3348 PDMApicGetBase(pVM, &GCPhysApicBase); /** @todo cache this */
3349 GCPhysApicBase &= PAGE_BASE_GC_MASK;
3350
3351 rc = PGMGstGetPage(pVCpu, (RTGCPTR)exitQualification, NULL, &GCPhys);
3352 if ( rc == VINF_SUCCESS
3353 && GCPhys == GCPhysApicBase)
3354 {
3355 /* Only attempt to patch the instruction once. */
3356 PHWACCMTPRPATCH pPatch = (PHWACCMTPRPATCH)RTAvloU32Get(&pVM->hwaccm.s.PatchTree, (AVLOU32KEY)pCtx->eip);
3357 if (!pPatch)
3358 {
3359 rc = VINF_EM_HWACCM_PATCH_TPR_INSTR;
3360 break;
3361 }
3362 }
3363 }
3364#endif
3365
3366 Log2(("Page fault at %RGv error code %x\n", exitQualification, errCode));
3367 /* Exit qualification contains the linear address of the page fault. */
3368 TRPMAssertTrap(pVCpu, X86_XCPT_PF, TRPM_TRAP);
3369 TRPMSetErrorCode(pVCpu, errCode);
3370 TRPMSetFaultAddress(pVCpu, exitQualification);
3371
3372 /* Shortcut for APIC TPR reads and writes. */
3373 if ( (exitQualification & 0xfff) == 0x080
3374 && !(errCode & X86_TRAP_PF_P) /* not present */
3375 && fSetupTPRCaching
3376 && (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC))
3377 {
3378 RTGCPHYS GCPhysApicBase, GCPhys;
3379 PDMApicGetBase(pVM, &GCPhysApicBase); /* @todo cache this */
3380 GCPhysApicBase &= PAGE_BASE_GC_MASK;
3381
3382 rc = PGMGstGetPage(pVCpu, (RTGCPTR)exitQualification, NULL, &GCPhys);
3383 if ( rc == VINF_SUCCESS
3384 && GCPhys == GCPhysApicBase)
3385 {
3386 Log(("Enable VT-x virtual APIC access filtering\n"));
3387 rc2 = IOMMMIOMapMMIOHCPage(pVM, GCPhysApicBase, pVM->hwaccm.s.vmx.pAPICPhys, X86_PTE_RW | X86_PTE_P);
3388 AssertRC(rc2);
3389 }
3390 }
3391
3392 /* Forward it to our trap handler first, in case our shadow pages are out of sync. */
3393 rc = PGMTrap0eHandler(pVCpu, errCode, CPUMCTX2CORE(pCtx), (RTGCPTR)exitQualification);
3394 Log2(("PGMTrap0eHandler %RGv returned %Rrc\n", (RTGCPTR)pCtx->rip, VBOXSTRICTRC_VAL(rc)));
3395
3396 if (rc == VINF_SUCCESS)
3397 { /* We've successfully synced our shadow pages, so let's just continue execution. */
3398 Log2(("Shadow page fault at %RGv cr2=%RGv error code %x\n", (RTGCPTR)pCtx->rip, exitQualification ,errCode));
3399 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitShadowPF);
3400
3401 TRPMResetTrap(pVCpu);
3402 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3403 goto ResumeExecution;
3404 }
3405 else if (rc == VINF_EM_RAW_GUEST_TRAP)
3406 {
3407 /*
3408 * A genuine pagefault. Forward the trap to the guest by injecting the exception and resuming execution.
3409 */
3410 Log2(("Forward page fault to the guest\n"));
3411
3412 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestPF);
3413 /* The error code might have been changed. */
3414 errCode = TRPMGetErrorCode(pVCpu);
3415
3416 TRPMResetTrap(pVCpu);
3417
3418 /* Now we must update CR2. */
3419 pCtx->cr2 = exitQualification;
3420 rc2 = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
3421 cbInstr, errCode);
3422 AssertRC(rc2);
3423
3424 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3425 goto ResumeExecution;
3426 }
3427#ifdef VBOX_STRICT
3428 if (rc != VINF_EM_RAW_EMULATE_INSTR && rc != VINF_EM_RAW_EMULATE_IO_BLOCK)
3429 Log2(("PGMTrap0eHandler failed with %d\n", VBOXSTRICTRC_VAL(rc)));
3430#endif
3431 /* Need to go back to the recompiler to emulate the instruction. */
3432 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitShadowPFEM);
3433 TRPMResetTrap(pVCpu);
3434 break;
3435 }
3436
3437 case X86_XCPT_MF: /* Floating point exception. */
3438 {
3439 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestMF);
3440 if (!(pCtx->cr0 & X86_CR0_NE))
3441 {
3442 /* old style FPU error reporting needs some extra work. */
3443 /** @todo don't fall back to the recompiler, but do it manually. */
3444 rc = VINF_EM_RAW_EMULATE_INSTR;
3445 break;
3446 }
3447 Log(("Trap %x at %04X:%RGv\n", vector, pCtx->cs.Sel, (RTGCPTR)pCtx->rip));
3448 rc2 = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
3449 cbInstr, errCode);
3450 AssertRC(rc2);
3451
3452 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3453 goto ResumeExecution;
3454 }
3455
3456 case X86_XCPT_DB: /* Debug exception. */
3457 {
3458 uint64_t uDR6;
3459
3460 /*
3461 * DR6, DR7.GD and IA32_DEBUGCTL.LBR are not updated yet.
3462 *
3463 * Exit qualification bits:
3464 * 3:0 B0-B3 which breakpoint condition was met
3465 * 12:4 Reserved (0)
3466 * 13 BD - debug register access detected
3467 * 14 BS - single step execution or branch taken
3468 * 63:15 Reserved (0)
3469 */
3470 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestDB);
3471
3472 /* Note that we don't support guest and host-initiated debugging at the same time. */
3473
3474 uDR6 = X86_DR6_INIT_VAL;
3475 uDR6 |= (exitQualification & (X86_DR6_B0|X86_DR6_B1|X86_DR6_B2|X86_DR6_B3|X86_DR6_BD|X86_DR6_BS));
3476 rc = DBGFRZTrap01Handler(pVM, pVCpu, CPUMCTX2CORE(pCtx), uDR6);
3477 if (rc == VINF_EM_RAW_GUEST_TRAP)
3478 {
3479 /* Update DR6 here. */
3480 pCtx->dr[6] = uDR6;
3481
3482 /* Resync DR6 if the debug state is active. */
3483 if (CPUMIsGuestDebugStateActive(pVCpu))
3484 ASMSetDR6(pCtx->dr[6]);
3485
3486 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
3487 pCtx->dr[7] &= ~X86_DR7_GD;
3488
3489 /* Paranoia. */
3490 pCtx->dr[7] &= 0xffffffff; /* upper 32 bits reserved */
3491 pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
3492 pCtx->dr[7] |= 0x400; /* must be one */
3493
3494 /* Resync DR7 */
3495 rc2 = VMXWriteVMCS64(VMX_VMCS64_GUEST_DR7, pCtx->dr[7]);
3496 AssertRC(rc2);
3497
3498 Log(("Trap %x (debug) at %RGv exit qualification %RX64 dr6=%x dr7=%x\n", vector, (RTGCPTR)pCtx->rip,
3499 exitQualification, (uint32_t)pCtx->dr[6], (uint32_t)pCtx->dr[7]));
3500 rc2 = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
3501 cbInstr, errCode);
3502 AssertRC(rc2);
3503
3504 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3505 goto ResumeExecution;
3506 }
3507 /* Return to ring 3 to deal with the debug exit code. */
3508 Log(("Debugger hardware BP at %04x:%RGv (rc=%Rrc)\n", pCtx->cs.Sel, pCtx->rip, VBOXSTRICTRC_VAL(rc)));
3509 break;
3510 }
3511
3512 case X86_XCPT_BP: /* Breakpoint. */
3513 {
3514 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestBP);
3515 rc = DBGFRZTrap03Handler(pVM, pVCpu, CPUMCTX2CORE(pCtx));
3516 if (rc == VINF_EM_RAW_GUEST_TRAP)
3517 {
3518 Log(("Guest #BP at %04x:%RGv\n", pCtx->cs.Sel, pCtx->rip));
3519 rc2 = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
3520 cbInstr, errCode);
3521 AssertRC(rc2);
3522 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3523 goto ResumeExecution;
3524 }
3525 if (rc == VINF_SUCCESS)
3526 {
3527 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3528 goto ResumeExecution;
3529 }
3530 Log(("Debugger BP at %04x:%RGv (rc=%Rrc)\n", pCtx->cs.Sel, pCtx->rip, VBOXSTRICTRC_VAL(rc)));
3531 break;
3532 }
3533
3534 case X86_XCPT_GP: /* General protection failure exception. */
3535 {
3536 uint32_t cbOp;
3537 PDISCPUSTATE pDis = &pVCpu->hwaccm.s.DisState;
3538
3539 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestGP);
3540#ifdef VBOX_STRICT
3541 if ( !CPUMIsGuestInRealModeEx(pCtx)
3542 || !pVM->hwaccm.s.vmx.pRealModeTSS)
3543 {
3544 Log(("Trap %x at %04X:%RGv errorCode=%RGv\n", vector, pCtx->cs.Sel, (RTGCPTR)pCtx->rip, errCode));
3545 rc2 = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
3546 cbInstr, errCode);
3547 AssertRC(rc2);
3548 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3549 goto ResumeExecution;
3550 }
3551#endif
3552 Assert(CPUMIsGuestInRealModeEx(pCtx));
3553
3554 LogFlow(("Real mode X86_XCPT_GP instruction emulation at %x:%RGv\n", pCtx->cs.Sel, (RTGCPTR)pCtx->rip));
3555
3556 rc2 = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), pDis, &cbOp);
3557 if (RT_SUCCESS(rc2))
3558 {
3559 bool fUpdateRIP = true;
3560
3561 rc = VINF_SUCCESS;
3562 Assert(cbOp == pDis->cbInstr);
3563 switch (pDis->pCurInstr->uOpcode)
3564 {
3565 case OP_CLI:
3566 pCtx->eflags.Bits.u1IF = 0;
3567 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCli);
3568 break;
3569
3570 case OP_STI:
3571 pCtx->eflags.Bits.u1IF = 1;
3572 EMSetInhibitInterruptsPC(pVCpu, pCtx->rip + pDis->cbInstr);
3573 Assert(VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
3574 rc2 = VMXWriteVMCS(VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE,
3575 VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI);
3576 AssertRC(rc2);
3577 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitSti);
3578 break;
3579
3580 case OP_HLT:
3581 fUpdateRIP = false;
3582 rc = VINF_EM_HALT;
3583 pCtx->rip += pDis->cbInstr;
3584 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitHlt);
3585 break;
3586
3587 case OP_POPF:
3588 {
3589 RTGCPTR GCPtrStack;
3590 uint32_t cbParm;
3591 uint32_t uMask;
3592 X86EFLAGS eflags;
3593
3594 if (pDis->fPrefix & DISPREFIX_OPSIZE)
3595 {
3596 cbParm = 4;
3597 uMask = 0xffffffff;
3598 }
3599 else
3600 {
3601 cbParm = 2;
3602 uMask = 0xffff;
3603 }
3604
3605 rc2 = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pCtx), pCtx->esp & uMask, 0, &GCPtrStack);
3606 if (RT_FAILURE(rc2))
3607 {
3608 rc = VERR_EM_INTERPRETER;
3609 break;
3610 }
3611 eflags.u = 0;
3612 rc2 = PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &eflags.u, cbParm);
3613 if (RT_FAILURE(rc2))
3614 {
3615 rc = VERR_EM_INTERPRETER;
3616 break;
3617 }
3618 LogFlow(("POPF %x -> %RGv mask=%x\n", eflags.u, pCtx->rsp, uMask));
3619 pCtx->eflags.u = (pCtx->eflags.u & ~(X86_EFL_POPF_BITS & uMask)) | (eflags.u & X86_EFL_POPF_BITS & uMask);
3620 /* RF cleared when popped in real mode; see pushf description in AMD manual. */
3621 pCtx->eflags.Bits.u1RF = 0;
3622 pCtx->esp += cbParm;
3623 pCtx->esp &= uMask;
3624
3625 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitPopf);
3626 break;
3627 }
3628
3629 case OP_PUSHF:
3630 {
3631 RTGCPTR GCPtrStack;
3632 uint32_t cbParm;
3633 uint32_t uMask;
3634 X86EFLAGS eflags;
3635
3636 if (pDis->fPrefix & DISPREFIX_OPSIZE)
3637 {
3638 cbParm = 4;
3639 uMask = 0xffffffff;
3640 }
3641 else
3642 {
3643 cbParm = 2;
3644 uMask = 0xffff;
3645 }
3646
3647 rc2 = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pCtx), (pCtx->esp - cbParm) & uMask, 0,
3648 &GCPtrStack);
3649 if (RT_FAILURE(rc2))
3650 {
3651 rc = VERR_EM_INTERPRETER;
3652 break;
3653 }
3654 eflags = pCtx->eflags;
3655 /* RF & VM cleared when pushed in real mode; see pushf description in AMD manual. */
3656 eflags.Bits.u1RF = 0;
3657 eflags.Bits.u1VM = 0;
3658
3659 rc2 = PGMPhysWrite(pVM, (RTGCPHYS)GCPtrStack, &eflags.u, cbParm);
3660 if (RT_FAILURE(rc2))
3661 {
3662 rc = VERR_EM_INTERPRETER;
3663 break;
3664 }
3665 LogFlow(("PUSHF %x -> %RGv\n", eflags.u, GCPtrStack));
3666 pCtx->esp -= cbParm;
3667 pCtx->esp &= uMask;
3668 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitPushf);
3669 break;
3670 }
3671
3672 case OP_IRET:
3673 {
3674 RTGCPTR GCPtrStack;
3675 uint32_t uMask = 0xffff;
3676 uint16_t aIretFrame[3];
3677
3678 if (pDis->fPrefix & (DISPREFIX_OPSIZE | DISPREFIX_ADDRSIZE))
3679 {
3680 rc = VERR_EM_INTERPRETER;
3681 break;
3682 }
3683
3684 rc2 = SELMToFlatEx(pVCpu, DISSELREG_SS, CPUMCTX2CORE(pCtx), pCtx->esp & uMask, 0, &GCPtrStack);
3685 if (RT_FAILURE(rc2))
3686 {
3687 rc = VERR_EM_INTERPRETER;
3688 break;
3689 }
3690 rc2 = PGMPhysRead(pVM, (RTGCPHYS)GCPtrStack, &aIretFrame[0], sizeof(aIretFrame));
3691 if (RT_FAILURE(rc2))
3692 {
3693 rc = VERR_EM_INTERPRETER;
3694 break;
3695 }
3696 pCtx->ip = aIretFrame[0];
3697 pCtx->cs.Sel = aIretFrame[1];
3698 pCtx->cs.ValidSel = aIretFrame[1];
3699 pCtx->cs.u64Base = (uint32_t)pCtx->cs.Sel << 4;
3700 pCtx->eflags.u = (pCtx->eflags.u & ~(X86_EFL_POPF_BITS & uMask))
3701 | (aIretFrame[2] & X86_EFL_POPF_BITS & uMask);
3702 pCtx->sp += sizeof(aIretFrame);
3703
3704 LogFlow(("iret to %04x:%x\n", pCtx->cs.Sel, pCtx->ip));
3705 fUpdateRIP = false;
3706 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIret);
3707 break;
3708 }
3709
3710 case OP_INT:
3711 {
3712 uint32_t intInfo2;
3713
3714 LogFlow(("Realmode: INT %x\n", pDis->Param1.uValue & 0xff));
3715 intInfo2 = pDis->Param1.uValue & 0xff;
3716 intInfo2 |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
3717 intInfo2 |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
3718
3719 rc = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, intInfo2, cbOp, 0);
3720 AssertRC(VBOXSTRICTRC_VAL(rc));
3721 fUpdateRIP = false;
3722 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitInt);
3723 break;
3724 }
3725
3726 case OP_INTO:
3727 {
3728 if (pCtx->eflags.Bits.u1OF)
3729 {
3730 uint32_t intInfo2;
3731
3732 LogFlow(("Realmode: INTO\n"));
3733 intInfo2 = X86_XCPT_OF;
3734 intInfo2 |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
3735 intInfo2 |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
3736
3737 rc = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, intInfo2, cbOp, 0);
3738 AssertRC(VBOXSTRICTRC_VAL(rc));
3739 fUpdateRIP = false;
3740 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitInt);
3741 }
3742 break;
3743 }
3744
3745 case OP_INT3:
3746 {
3747 uint32_t intInfo2;
3748
3749 LogFlow(("Realmode: INT 3\n"));
3750 intInfo2 = 3;
3751 intInfo2 |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
3752 intInfo2 |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_SW << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
3753
3754 rc = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, intInfo2, cbOp, 0);
3755 AssertRC(VBOXSTRICTRC_VAL(rc));
3756 fUpdateRIP = false;
3757 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitInt);
3758 break;
3759 }
3760
3761 default:
3762 rc = EMInterpretInstructionDisasState(pVCpu, pDis, CPUMCTX2CORE(pCtx), 0, EMCODETYPE_SUPERVISOR);
3763 fUpdateRIP = false;
3764 break;
3765 }
3766
3767 if (rc == VINF_SUCCESS)
3768 {
3769 if (fUpdateRIP)
3770 pCtx->rip += cbOp; /* Move on to the next instruction. */
3771
3772 /*
3773 * LIDT, LGDT can end up here. In the future CRx changes as well. Just reload the
3774 * whole context to be done with it.
3775 */
3776 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_ALL;
3777
3778 /* Only resume if successful. */
3779 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3780 goto ResumeExecution;
3781 }
3782 }
3783 else
3784 rc = VERR_EM_INTERPRETER;
3785
3786 AssertMsg(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_EM_HALT, ("Unexpected rc=%Rrc\n", VBOXSTRICTRC_VAL(rc)));
3787 break;
3788 }
3789
3790#ifdef VBOX_STRICT
3791 case X86_XCPT_XF: /* SIMD exception. */
3792 case X86_XCPT_DE: /* Divide error. */
3793 case X86_XCPT_UD: /* Unknown opcode exception. */
3794 case X86_XCPT_SS: /* Stack segment exception. */
3795 case X86_XCPT_NP: /* Segment not present exception. */
3796 {
3797 switch(vector)
3798 {
3799 case X86_XCPT_DE:
3800 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestDE);
3801 break;
3802 case X86_XCPT_UD:
3803 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestUD);
3804 break;
3805 case X86_XCPT_SS:
3806 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestSS);
3807 break;
3808 case X86_XCPT_NP:
3809 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestNP);
3810 break;
3811 case X86_XCPT_XF:
3812 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestXF);
3813 break;
3814 }
3815
3816 Log(("Trap %x at %04X:%RGv\n", vector, pCtx->cs.Sel, (RTGCPTR)pCtx->rip));
3817 rc2 = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
3818 cbInstr, errCode);
3819 AssertRC(rc2);
3820
3821 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3822 goto ResumeExecution;
3823 }
3824#endif
3825 default:
3826 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestXcpUnk);
3827 if ( CPUMIsGuestInRealModeEx(pCtx)
3828 && pVM->hwaccm.s.vmx.pRealModeTSS)
3829 {
3830 Log(("Real Mode Trap %x at %04x:%04X error code %x\n", vector, pCtx->cs.Sel, pCtx->eip, errCode));
3831 rc = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
3832 cbInstr, errCode);
3833 AssertRC(VBOXSTRICTRC_VAL(rc)); /* Strict RC check below. */
3834
3835 /* Go back to ring-3 in case of a triple fault. */
3836 if ( vector == X86_XCPT_DF
3837 && rc == VINF_EM_RESET)
3838 {
3839 break;
3840 }
3841
3842 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3843 goto ResumeExecution;
3844 }
3845 AssertMsgFailed(("Unexpected vm-exit caused by exception %x\n", vector));
3846 rc = VERR_VMX_UNEXPECTED_EXCEPTION;
3847 break;
3848 } /* switch (vector) */
3849
3850 break;
3851
3852 default:
3853 rc = VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_CODE;
3854 AssertMsgFailed(("Unexpected interruption code %x\n", intInfo));
3855 break;
3856 }
3857
3858 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub3, y3);
3859 break;
3860 }
3861
3862 /*
3863 * 48 EPT violation. An attemp to access memory with a guest-physical address was disallowed
3864 * by the configuration of the EPT paging structures.
3865 */
3866 case VMX_EXIT_EPT_VIOLATION:
3867 {
3868 RTGCPHYS GCPhys;
3869
3870 Assert(pVM->hwaccm.s.fNestedPaging);
3871
3872 rc2 = VMXReadVMCS64(VMX_VMCS_EXIT_PHYS_ADDR_FULL, &GCPhys);
3873 AssertRC(rc2);
3874 Assert(((exitQualification >> 7) & 3) != 2);
3875
3876 /* Determine the kind of violation. */
3877 errCode = 0;
3878 if (exitQualification & VMX_EXIT_QUALIFICATION_EPT_INSTR_FETCH)
3879 errCode |= X86_TRAP_PF_ID;
3880
3881 if (exitQualification & VMX_EXIT_QUALIFICATION_EPT_DATA_WRITE)
3882 errCode |= X86_TRAP_PF_RW;
3883
3884 /* If the page is present, then it's a page level protection fault. */
3885 if (exitQualification & VMX_EXIT_QUALIFICATION_EPT_ENTRY_PRESENT)
3886 errCode |= X86_TRAP_PF_P;
3887 else
3888 {
3889 /* Shortcut for APIC TPR reads and writes. */
3890 if ( (GCPhys & 0xfff) == 0x080
3891 && GCPhys > 0x1000000 /* to skip VGA frame buffer accesses */
3892 && fSetupTPRCaching
3893 && (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC))
3894 {
3895 RTGCPHYS GCPhysApicBase;
3896 PDMApicGetBase(pVM, &GCPhysApicBase); /* @todo cache this */
3897 GCPhysApicBase &= PAGE_BASE_GC_MASK;
3898 if (GCPhys == GCPhysApicBase + 0x80)
3899 {
3900 Log(("Enable VT-x virtual APIC access filtering\n"));
3901 rc2 = IOMMMIOMapMMIOHCPage(pVM, GCPhysApicBase, pVM->hwaccm.s.vmx.pAPICPhys, X86_PTE_RW | X86_PTE_P);
3902 AssertRC(rc2);
3903 }
3904 }
3905 }
3906 Log(("EPT Page fault %x at %RGp error code %x\n", (uint32_t)exitQualification, GCPhys, errCode));
3907
3908 /* GCPhys contains the guest physical address of the page fault. */
3909 TRPMAssertTrap(pVCpu, X86_XCPT_PF, TRPM_TRAP);
3910 TRPMSetErrorCode(pVCpu, errCode);
3911 TRPMSetFaultAddress(pVCpu, GCPhys);
3912
3913 /* Handle the pagefault trap for the nested shadow table. */
3914 rc = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, PGMMODE_EPT, errCode, CPUMCTX2CORE(pCtx), GCPhys);
3915
3916 /*
3917 * Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment below, @bugref{6043}.
3918 */
3919 if ( rc == VINF_SUCCESS
3920 || rc == VERR_PAGE_TABLE_NOT_PRESENT
3921 || rc == VERR_PAGE_NOT_PRESENT)
3922 {
3923 /* We've successfully synced our shadow pages, so let's just continue execution. */
3924 Log2(("Shadow page fault at %RGv cr2=%RGp error code %x\n", (RTGCPTR)pCtx->rip, exitQualification , errCode));
3925 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitReasonNPF);
3926
3927 TRPMResetTrap(pVCpu);
3928 goto ResumeExecution;
3929 }
3930
3931#ifdef VBOX_STRICT
3932 if (rc != VINF_EM_RAW_EMULATE_INSTR)
3933 LogFlow(("PGMTrap0eHandlerNestedPaging at %RGv failed with %Rrc\n", (RTGCPTR)pCtx->rip, VBOXSTRICTRC_VAL(rc)));
3934#endif
3935 /* Need to go back to the recompiler to emulate the instruction. */
3936 TRPMResetTrap(pVCpu);
3937 break;
3938 }
3939
3940 case VMX_EXIT_EPT_MISCONFIG:
3941 {
3942 RTGCPHYS GCPhys;
3943
3944 Assert(pVM->hwaccm.s.fNestedPaging);
3945
3946 rc2 = VMXReadVMCS64(VMX_VMCS_EXIT_PHYS_ADDR_FULL, &GCPhys);
3947 AssertRC(rc2);
3948 Log(("VMX_EXIT_EPT_MISCONFIG for %RGp\n", GCPhys));
3949
3950 /* Shortcut for APIC TPR reads and writes. */
3951 if ( (GCPhys & 0xfff) == 0x080
3952 && GCPhys > 0x1000000 /* to skip VGA frame buffer accesses */
3953 && fSetupTPRCaching
3954 && (pVM->hwaccm.s.vmx.msr.vmx_proc_ctls2.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC))
3955 {
3956 RTGCPHYS GCPhysApicBase;
3957 PDMApicGetBase(pVM, &GCPhysApicBase); /* @todo cache this */
3958 GCPhysApicBase &= PAGE_BASE_GC_MASK;
3959 if (GCPhys == GCPhysApicBase + 0x80)
3960 {
3961 Log(("Enable VT-x virtual APIC access filtering\n"));
3962 rc2 = IOMMMIOMapMMIOHCPage(pVM, GCPhysApicBase, pVM->hwaccm.s.vmx.pAPICPhys, X86_PTE_RW | X86_PTE_P);
3963 AssertRC(rc2);
3964 }
3965 }
3966
3967 rc = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, PGMMODE_EPT, CPUMCTX2CORE(pCtx), GCPhys, UINT32_MAX);
3968
3969 /*
3970 * If we succeed, resume execution.
3971 * Or, if fail in interpreting the instruction because we couldn't get the guest physical address
3972 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
3973 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
3974 * weird case. See @bugref{6043}.
3975 */
3976 if ( rc == VINF_SUCCESS
3977 || rc == VERR_PAGE_TABLE_NOT_PRESENT
3978 || rc == VERR_PAGE_NOT_PRESENT)
3979 {
3980 Log2(("PGMR0Trap0eHandlerNPMisconfig(,,,%RGp) at %RGv -> resume\n", GCPhys, (RTGCPTR)pCtx->rip));
3981 goto ResumeExecution;
3982 }
3983
3984 Log2(("PGMR0Trap0eHandlerNPMisconfig(,,,%RGp) at %RGv -> %Rrc\n", GCPhys, (RTGCPTR)pCtx->rip, VBOXSTRICTRC_VAL(rc)));
3985 break;
3986 }
3987
3988 case VMX_EXIT_IRQ_WINDOW: /* 7 Interrupt window. */
3989 /* Clear VM-exit on IF=1 change. */
3990 LogFlow(("VMX_EXIT_IRQ_WINDOW %RGv pending=%d IF=%d\n", (RTGCPTR)pCtx->rip,
3991 VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)), pCtx->eflags.Bits.u1IF));
3992 pVCpu->hwaccm.s.vmx.proc_ctls &= ~VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_IRQ_WINDOW_EXIT;
3993 rc2 = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
3994 AssertRC(rc2);
3995 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIrqWindow);
3996 goto ResumeExecution; /* we check for pending guest interrupts there */
3997
3998 case VMX_EXIT_WBINVD: /* 54 Guest software attempted to execute WBINVD. (conditional) */
3999 case VMX_EXIT_INVD: /* 13 Guest software attempted to execute INVD. (unconditional) */
4000 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitInvd);
4001 /* Skip instruction and continue directly. */
4002 pCtx->rip += cbInstr;
4003 /* Continue execution.*/
4004 goto ResumeExecution;
4005
4006 case VMX_EXIT_CPUID: /* 10 Guest software attempted to execute CPUID. */
4007 {
4008 Log2(("VMX: Cpuid %x\n", pCtx->eax));
4009 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCpuid);
4010 rc = EMInterpretCpuId(pVM, pVCpu, CPUMCTX2CORE(pCtx));
4011 if (rc == VINF_SUCCESS)
4012 {
4013 /* Update EIP and continue execution. */
4014 Assert(cbInstr == 2);
4015 pCtx->rip += cbInstr;
4016 goto ResumeExecution;
4017 }
4018 AssertMsgFailed(("EMU: cpuid failed with %Rrc\n", VBOXSTRICTRC_VAL(rc)));
4019 rc = VINF_EM_RAW_EMULATE_INSTR;
4020 break;
4021 }
4022
4023 case VMX_EXIT_RDPMC: /* 15 Guest software attempted to execute RDPMC. */
4024 {
4025 Log2(("VMX: Rdpmc %x\n", pCtx->ecx));
4026 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitRdpmc);
4027 rc = EMInterpretRdpmc(pVM, pVCpu, CPUMCTX2CORE(pCtx));
4028 if (rc == VINF_SUCCESS)
4029 {
4030 /* Update EIP and continue execution. */
4031 Assert(cbInstr == 2);
4032 pCtx->rip += cbInstr;
4033 goto ResumeExecution;
4034 }
4035 rc = VINF_EM_RAW_EMULATE_INSTR;
4036 break;
4037 }
4038
4039 case VMX_EXIT_RDTSC: /* 16 Guest software attempted to execute RDTSC. */
4040 {
4041 Log2(("VMX: Rdtsc\n"));
4042 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitRdtsc);
4043 rc = EMInterpretRdtsc(pVM, pVCpu, CPUMCTX2CORE(pCtx));
4044 if (rc == VINF_SUCCESS)
4045 {
4046 /* Update EIP and continue execution. */
4047 Assert(cbInstr == 2);
4048 pCtx->rip += cbInstr;
4049 goto ResumeExecution;
4050 }
4051 rc = VINF_EM_RAW_EMULATE_INSTR;
4052 break;
4053 }
4054
4055 case VMX_EXIT_INVPG: /* 14 Guest software attempted to execute INVPG. */
4056 {
4057 Log2(("VMX: invlpg\n"));
4058 Assert(!pVM->hwaccm.s.fNestedPaging);
4059
4060 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitInvpg);
4061 rc = EMInterpretInvlpg(pVM, pVCpu, CPUMCTX2CORE(pCtx), exitQualification);
4062 if (rc == VINF_SUCCESS)
4063 {
4064 /* Update EIP and continue execution. */
4065 pCtx->rip += cbInstr;
4066 goto ResumeExecution;
4067 }
4068 AssertMsg(rc == VERR_EM_INTERPRETER, ("EMU: invlpg %RGv failed with %Rrc\n", exitQualification, VBOXSTRICTRC_VAL(rc)));
4069 break;
4070 }
4071
4072 case VMX_EXIT_MONITOR: /* 39 Guest software attempted to execute MONITOR. */
4073 {
4074 Log2(("VMX: monitor\n"));
4075
4076 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitMonitor);
4077 rc = EMInterpretMonitor(pVM, pVCpu, CPUMCTX2CORE(pCtx));
4078 if (rc == VINF_SUCCESS)
4079 {
4080 /* Update EIP and continue execution. */
4081 pCtx->rip += cbInstr;
4082 goto ResumeExecution;
4083 }
4084 AssertMsg(rc == VERR_EM_INTERPRETER, ("EMU: monitor failed with %Rrc\n", VBOXSTRICTRC_VAL(rc)));
4085 break;
4086 }
4087
4088 case VMX_EXIT_WRMSR: /* 32 WRMSR. Guest software attempted to execute WRMSR. */
4089 /* When an interrupt is pending, we'll let MSR_K8_LSTAR writes fault in our TPR patch code. */
4090 if ( pVM->hwaccm.s.fTPRPatchingActive
4091 && pCtx->ecx == MSR_K8_LSTAR)
4092 {
4093 Assert(!CPUMIsGuestInLongModeEx(pCtx));
4094 if ((pCtx->eax & 0xff) != u8LastTPR)
4095 {
4096 Log(("VMX: Faulting MSR_K8_LSTAR write with new TPR value %x\n", pCtx->eax & 0xff));
4097
4098 /* Our patch code uses LSTAR for TPR caching. */
4099 rc2 = PDMApicSetTPR(pVCpu, pCtx->eax & 0xff);
4100 AssertRC(rc2);
4101 }
4102
4103 /* Skip the instruction and continue. */
4104 pCtx->rip += cbInstr; /* wrmsr = [0F 30] */
4105
4106 /* Only resume if successful. */
4107 goto ResumeExecution;
4108 }
4109 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_MSR;
4110 /* no break */
4111 case VMX_EXIT_RDMSR: /* 31 RDMSR. Guest software attempted to execute RDMSR. */
4112 {
4113 STAM_COUNTER_INC((exitReason == VMX_EXIT_RDMSR) ? &pVCpu->hwaccm.s.StatExitRdmsr : &pVCpu->hwaccm.s.StatExitWrmsr);
4114
4115 /*
4116 * Note: The Intel spec. claims there's an REX version of RDMSR that's slightly different,
4117 * so we play safe by completely disassembling the instruction.
4118 */
4119 Log2(("VMX: %s\n", (exitReason == VMX_EXIT_RDMSR) ? "rdmsr" : "wrmsr"));
4120 rc = EMInterpretInstruction(pVCpu, CPUMCTX2CORE(pCtx), 0);
4121 if (rc == VINF_SUCCESS)
4122 {
4123 /* EIP has been updated already. */
4124 /* Only resume if successful. */
4125 goto ResumeExecution;
4126 }
4127 AssertMsg(rc == VERR_EM_INTERPRETER, ("EMU: %s failed with %Rrc\n",
4128 (exitReason == VMX_EXIT_RDMSR) ? "rdmsr" : "wrmsr", VBOXSTRICTRC_VAL(rc)));
4129 break;
4130 }
4131
4132 case VMX_EXIT_CRX_MOVE: /* 28 Control-register accesses. */
4133 {
4134 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatExit2Sub2, y2);
4135
4136 switch (VMX_EXIT_QUALIFICATION_CRX_ACCESS(exitQualification))
4137 {
4138 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_WRITE:
4139 {
4140 Log2(("VMX: %RGv mov cr%d, x\n", (RTGCPTR)pCtx->rip, VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification)));
4141 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCRxWrite[VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification)]);
4142 rc = EMInterpretCRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
4143 VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification),
4144 VMX_EXIT_QUALIFICATION_CRX_GENREG(exitQualification));
4145 switch (VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification))
4146 {
4147 case 0:
4148 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0 | HWACCM_CHANGED_GUEST_CR3;
4149 break;
4150 case 2:
4151 break;
4152 case 3:
4153 Assert(!pVM->hwaccm.s.fNestedPaging || !CPUMIsGuestInPagedProtectedModeEx(pCtx));
4154 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR3;
4155 break;
4156 case 4:
4157 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR4;
4158 break;
4159 case 8:
4160 /* CR8 contains the APIC TPR */
4161 Assert(!(pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1
4162 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW));
4163 break;
4164
4165 default:
4166 AssertFailed();
4167 break;
4168 }
4169 break;
4170 }
4171
4172 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_READ:
4173 {
4174 Log2(("VMX: mov x, crx\n"));
4175 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCRxRead[VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification)]);
4176
4177 Assert( !pVM->hwaccm.s.fNestedPaging
4178 || !CPUMIsGuestInPagedProtectedModeEx(pCtx)
4179 || VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification) != DISCREG_CR3);
4180
4181 /* CR8 reads only cause an exit when the TPR shadow feature isn't present. */
4182 Assert( VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification) != 8
4183 || !(pVM->hwaccm.s.vmx.msr.vmx_proc_ctls.n.allowed1 & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_USE_TPR_SHADOW));
4184
4185 rc = EMInterpretCRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
4186 VMX_EXIT_QUALIFICATION_CRX_GENREG(exitQualification),
4187 VMX_EXIT_QUALIFICATION_CRX_REGISTER(exitQualification));
4188 break;
4189 }
4190
4191 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_CLTS:
4192 {
4193 Log2(("VMX: clts\n"));
4194 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCLTS);
4195 rc = EMInterpretCLTS(pVM, pVCpu);
4196 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
4197 break;
4198 }
4199
4200 case VMX_EXIT_QUALIFICATION_CRX_ACCESS_LMSW:
4201 {
4202 Log2(("VMX: lmsw %x\n", VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(exitQualification)));
4203 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitLMSW);
4204 rc = EMInterpretLMSW(pVM, pVCpu, CPUMCTX2CORE(pCtx), VMX_EXIT_QUALIFICATION_CRX_LMSW_DATA(exitQualification));
4205 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
4206 break;
4207 }
4208 }
4209
4210 /* Update EIP if no error occurred. */
4211 if (RT_SUCCESS(rc))
4212 pCtx->rip += cbInstr;
4213
4214 if (rc == VINF_SUCCESS)
4215 {
4216 /* Only resume if successful. */
4217 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub2, y2);
4218 goto ResumeExecution;
4219 }
4220 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
4221 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub2, y2);
4222 break;
4223 }
4224
4225 case VMX_EXIT_DRX_MOVE: /* 29 Debug-register accesses. */
4226 {
4227 if ( !DBGFIsStepping(pVCpu)
4228 && !CPUMIsHyperDebugStateActive(pVCpu))
4229 {
4230 /* Disable DRx move intercepts. */
4231 pVCpu->hwaccm.s.vmx.proc_ctls &= ~VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT;
4232 rc2 = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
4233 AssertRC(rc2);
4234
4235 /* Save the host and load the guest debug state. */
4236 rc2 = CPUMR0LoadGuestDebugState(pVM, pVCpu, pCtx, true /* include DR6 */);
4237 AssertRC(rc2);
4238
4239#ifdef LOG_ENABLED
4240 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
4241 {
4242 Log(("VMX_EXIT_DRX_MOVE: write DR%d genreg %d\n", VMX_EXIT_QUALIFICATION_DRX_REGISTER(exitQualification),
4243 VMX_EXIT_QUALIFICATION_DRX_GENREG(exitQualification)));
4244 }
4245 else
4246 Log(("VMX_EXIT_DRX_MOVE: read DR%d\n", VMX_EXIT_QUALIFICATION_DRX_REGISTER(exitQualification)));
4247#endif
4248
4249#ifdef VBOX_WITH_STATISTICS
4250 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxContextSwitch);
4251 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
4252 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxWrite);
4253 else
4254 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxRead);
4255#endif
4256
4257 goto ResumeExecution;
4258 }
4259
4260 /** @todo clear VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT after the first
4261 * time and restore DRx registers afterwards */
4262 if (VMX_EXIT_QUALIFICATION_DRX_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_DRX_DIRECTION_WRITE)
4263 {
4264 Log2(("VMX: mov DRx%d, genreg%d\n", VMX_EXIT_QUALIFICATION_DRX_REGISTER(exitQualification),
4265 VMX_EXIT_QUALIFICATION_DRX_GENREG(exitQualification)));
4266 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxWrite);
4267 rc = EMInterpretDRxWrite(pVM, pVCpu, CPUMCTX2CORE(pCtx),
4268 VMX_EXIT_QUALIFICATION_DRX_REGISTER(exitQualification),
4269 VMX_EXIT_QUALIFICATION_DRX_GENREG(exitQualification));
4270 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_DEBUG;
4271 Log2(("DR7=%08x\n", pCtx->dr[7]));
4272 }
4273 else
4274 {
4275 Log2(("VMX: mov x, DRx\n"));
4276 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxRead);
4277 rc = EMInterpretDRxRead(pVM, pVCpu, CPUMCTX2CORE(pCtx),
4278 VMX_EXIT_QUALIFICATION_DRX_GENREG(exitQualification),
4279 VMX_EXIT_QUALIFICATION_DRX_REGISTER(exitQualification));
4280 }
4281 /* Update EIP if no error occurred. */
4282 if (RT_SUCCESS(rc))
4283 pCtx->rip += cbInstr;
4284
4285 if (rc == VINF_SUCCESS)
4286 {
4287 /* Only resume if successful. */
4288 goto ResumeExecution;
4289 }
4290 Assert(rc == VERR_EM_INTERPRETER);
4291 break;
4292 }
4293
4294 /* Note: We'll get a #GP if the IO instruction isn't allowed (IOPL or TSS bitmap); no need to double check. */
4295 case VMX_EXIT_PORT_IO: /* 30 I/O instruction. */
4296 {
4297 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
4298 uint32_t uPort;
4299 uint32_t uIOWidth = VMX_EXIT_QUALIFICATION_IO_WIDTH(exitQualification);
4300 bool fIOWrite = (VMX_EXIT_QUALIFICATION_IO_DIRECTION(exitQualification) == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT);
4301
4302 /** @todo necessary to make the distinction? */
4303 if (VMX_EXIT_QUALIFICATION_IO_ENCODING(exitQualification) == VMX_EXIT_QUALIFICATION_IO_ENCODING_DX)
4304 uPort = pCtx->edx & 0xffff;
4305 else
4306 uPort = VMX_EXIT_QUALIFICATION_IO_PORT(exitQualification); /* Immediate encoding. */
4307
4308 if (RT_UNLIKELY(uIOWidth == 2 || uIOWidth >= 4)) /* paranoia */
4309 {
4310 rc = fIOWrite ? VINF_IOM_R3_IOPORT_WRITE : VINF_IOM_R3_IOPORT_READ;
4311 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
4312 break;
4313 }
4314
4315 uint32_t cbSize = g_aIOSize[uIOWidth];
4316 if (VMX_EXIT_QUALIFICATION_IO_STRING(exitQualification))
4317 {
4318 /* ins/outs */
4319 PDISCPUSTATE pDis = &pVCpu->hwaccm.s.DisState;
4320
4321 /* Disassemble manually to deal with segment prefixes. */
4322 /** @todo VMX_VMCS_EXIT_GUEST_LINEAR_ADDR contains the flat pointer operand of the instruction. */
4323 /** @todo VMX_VMCS32_RO_EXIT_INSTR_INFO also contains segment prefix info. */
4324 rc2 = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), pDis, NULL);
4325 if (RT_SUCCESS(rc))
4326 {
4327 if (fIOWrite)
4328 {
4329 Log2(("IOMInterpretOUTSEx %RGv %x size=%d\n", (RTGCPTR)pCtx->rip, uPort, cbSize));
4330 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIOStringWrite);
4331 rc = IOMInterpretOUTSEx(pVM, CPUMCTX2CORE(pCtx), uPort, pDis->fPrefix, (DISCPUMODE)pDis->uAddrMode, cbSize);
4332 }
4333 else
4334 {
4335 Log2(("IOMInterpretINSEx %RGv %x size=%d\n", (RTGCPTR)pCtx->rip, uPort, cbSize));
4336 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIOStringRead);
4337 rc = IOMInterpretINSEx(pVM, CPUMCTX2CORE(pCtx), uPort, pDis->fPrefix, (DISCPUMODE)pDis->uAddrMode, cbSize);
4338 }
4339 }
4340 else
4341 rc = VINF_EM_RAW_EMULATE_INSTR;
4342 }
4343 else
4344 {
4345 /* Normal in/out */
4346 uint32_t uAndVal = g_aIOOpAnd[uIOWidth];
4347
4348 Assert(!VMX_EXIT_QUALIFICATION_IO_REP(exitQualification));
4349
4350 if (fIOWrite)
4351 {
4352 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIOWrite);
4353 rc = IOMIOPortWrite(pVM, uPort, pCtx->eax & uAndVal, cbSize);
4354 if (rc == VINF_IOM_R3_IOPORT_WRITE)
4355 HWACCMR0SavePendingIOPortWrite(pVCpu, pCtx->rip, pCtx->rip + cbInstr, uPort, uAndVal, cbSize);
4356 }
4357 else
4358 {
4359 uint32_t u32Val = 0;
4360
4361 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIORead);
4362 rc = IOMIOPortRead(pVM, uPort, &u32Val, cbSize);
4363 if (IOM_SUCCESS(rc))
4364 {
4365 /* Write back to the EAX register. */
4366 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Val & uAndVal);
4367 }
4368 else
4369 if (rc == VINF_IOM_R3_IOPORT_READ)
4370 HWACCMR0SavePendingIOPortRead(pVCpu, pCtx->rip, pCtx->rip + cbInstr, uPort, uAndVal, cbSize);
4371 }
4372 }
4373
4374 /*
4375 * Handled the I/O return codes.
4376 * (The unhandled cases end up with rc == VINF_EM_RAW_EMULATE_INSTR.)
4377 */
4378 if (IOM_SUCCESS(rc))
4379 {
4380 /* Update EIP and continue execution. */
4381 pCtx->rip += cbInstr;
4382 if (RT_LIKELY(rc == VINF_SUCCESS))
4383 {
4384 /* If any IO breakpoints are armed, then we should check if a debug trap needs to be generated. */
4385 if (pCtx->dr[7] & X86_DR7_ENABLED_MASK)
4386 {
4387 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxIOCheck);
4388 for (unsigned i = 0; i < 4; i++)
4389 {
4390 unsigned uBPLen = g_aIOSize[X86_DR7_GET_LEN(pCtx->dr[7], i)];
4391
4392 if ( (uPort >= pCtx->dr[i] && uPort < pCtx->dr[i] + uBPLen)
4393 && (pCtx->dr[7] & (X86_DR7_L(i) | X86_DR7_G(i)))
4394 && (pCtx->dr[7] & X86_DR7_RW(i, X86_DR7_RW_IO)) == X86_DR7_RW(i, X86_DR7_RW_IO))
4395 {
4396 uint64_t uDR6;
4397
4398 Assert(CPUMIsGuestDebugStateActive(pVCpu));
4399
4400 uDR6 = ASMGetDR6();
4401
4402 /* Clear all breakpoint status flags and set the one we just hit. */
4403 uDR6 &= ~(X86_DR6_B0|X86_DR6_B1|X86_DR6_B2|X86_DR6_B3);
4404 uDR6 |= (uint64_t)RT_BIT(i);
4405
4406 /*
4407 * Note: AMD64 Architecture Programmer's Manual 13.1:
4408 * Bits 15:13 of the DR6 register is never cleared by the processor and must
4409 * be cleared by software after the contents have been read.
4410 */
4411 ASMSetDR6(uDR6);
4412
4413 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */
4414 pCtx->dr[7] &= ~X86_DR7_GD;
4415
4416 /* Paranoia. */
4417 pCtx->dr[7] &= 0xffffffff; /* upper 32 bits reserved */
4418 pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
4419 pCtx->dr[7] |= 0x400; /* must be one */
4420
4421 /* Resync DR7 */
4422 rc2 = VMXWriteVMCS64(VMX_VMCS64_GUEST_DR7, pCtx->dr[7]);
4423 AssertRC(rc2);
4424
4425 /* Construct inject info. */
4426 intInfo = X86_XCPT_DB;
4427 intInfo |= (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);
4428 intInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HWEXCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);
4429
4430 Log(("Inject IO debug trap at %RGv\n", (RTGCPTR)pCtx->rip));
4431 rc2 = hmR0VmxInjectEvent(pVM, pVCpu, pCtx, VMX_VMCS_CTRL_ENTRY_IRQ_INFO_FROM_EXIT_INT_INFO(intInfo),
4432 0 /* cbInstr */, 0 /* errCode */);
4433 AssertRC(rc2);
4434
4435 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
4436 goto ResumeExecution;
4437 }
4438 }
4439 }
4440 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
4441 goto ResumeExecution;
4442 }
4443 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
4444 break;
4445 }
4446
4447#ifdef VBOX_STRICT
4448 if (rc == VINF_IOM_R3_IOPORT_READ)
4449 Assert(!fIOWrite);
4450 else if (rc == VINF_IOM_R3_IOPORT_WRITE)
4451 Assert(fIOWrite);
4452 else
4453 {
4454 AssertMsg( RT_FAILURE(rc)
4455 || rc == VINF_EM_RAW_EMULATE_INSTR
4456 || rc == VINF_EM_RAW_GUEST_TRAP
4457 || rc == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rc)));
4458 }
4459#endif
4460 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2Sub1, y1);
4461 break;
4462 }
4463
4464 case VMX_EXIT_TPR: /* 43 TPR below threshold. Guest software executed MOV to CR8. */
4465 LogFlow(("VMX_EXIT_TPR\n"));
4466 /* RIP is already set to the next instruction and the TPR has been synced back. Just resume. */
4467 goto ResumeExecution;
4468
4469 case VMX_EXIT_APIC_ACCESS: /* 44 APIC access. Guest software attempted to access memory at a physical address
4470 on the APIC-access page. */
4471 {
4472 LogFlow(("VMX_EXIT_APIC_ACCESS\n"));
4473 unsigned uAccessType = VMX_EXIT_QUALIFICATION_APIC_ACCESS_TYPE(exitQualification);
4474
4475 switch(uAccessType)
4476 {
4477 case VMX_APIC_ACCESS_TYPE_LINEAR_READ:
4478 case VMX_APIC_ACCESS_TYPE_LINEAR_WRITE:
4479 {
4480 RTGCPHYS GCPhys;
4481 PDMApicGetBase(pVM, &GCPhys);
4482 GCPhys &= PAGE_BASE_GC_MASK;
4483 GCPhys += VMX_EXIT_QUALIFICATION_APIC_ACCESS_OFFSET(exitQualification);
4484
4485 LogFlow(("Apic access at %RGp\n", GCPhys));
4486 rc = IOMMMIOPhysHandler(pVM, (uAccessType == VMX_APIC_ACCESS_TYPE_LINEAR_READ) ? 0 : X86_TRAP_PF_RW,
4487 CPUMCTX2CORE(pCtx), GCPhys);
4488 if (rc == VINF_SUCCESS)
4489 goto ResumeExecution; /* rip already updated */
4490 break;
4491 }
4492
4493 default:
4494 rc = VINF_EM_RAW_EMULATE_INSTR;
4495 break;
4496 }
4497 break;
4498 }
4499
4500 case VMX_EXIT_PREEMPTION_TIMER: /* 52 VMX-preemption timer expired. The preemption timer counted down to zero. */
4501 if (!TMTimerPollBool(pVM, pVCpu))
4502 goto ResumeExecution;
4503 rc = VINF_EM_RAW_TIMER_PENDING;
4504 break;
4505
4506 default:
4507 /* The rest is handled after syncing the entire CPU state. */
4508 break;
4509 }
4510
4511
4512 /*
4513 * Note: The guest state is not entirely synced back at this stage!
4514 */
4515
4516 /* Investigate why there was a VM-exit. (part 2) */
4517 switch (exitReason)
4518 {
4519 case VMX_EXIT_EXCEPTION: /* 0 Exception or non-maskable interrupt (NMI). */
4520 case VMX_EXIT_EXTERNAL_IRQ: /* 1 External interrupt. */
4521 case VMX_EXIT_EPT_VIOLATION:
4522 case VMX_EXIT_EPT_MISCONFIG: /* 49 EPT misconfig is used by the PGM/MMIO optimizations. */
4523 case VMX_EXIT_PREEMPTION_TIMER: /* 52 VMX-preemption timer expired. The preemption timer counted down to zero. */
4524 /* Already handled above. */
4525 break;
4526
4527 case VMX_EXIT_TRIPLE_FAULT: /* 2 Triple fault. */
4528 rc = VINF_EM_RESET; /* Triple fault equals a reset. */
4529 break;
4530
4531 case VMX_EXIT_INIT_SIGNAL: /* 3 INIT signal. */
4532 case VMX_EXIT_SIPI: /* 4 Start-up IPI (SIPI). */
4533 rc = VINF_EM_RAW_INTERRUPT;
4534 AssertFailed(); /* Can't happen. Yet. */
4535 break;
4536
4537 case VMX_EXIT_IO_SMI_IRQ: /* 5 I/O system-management interrupt (SMI). */
4538 case VMX_EXIT_SMI_IRQ: /* 6 Other SMI. */
4539 rc = VINF_EM_RAW_INTERRUPT;
4540 AssertFailed(); /* Can't happen afaik. */
4541 break;
4542
4543 case VMX_EXIT_TASK_SWITCH: /* 9 Task switch: too complicated to emulate, so fall back to the recompiler */
4544 Log(("VMX_EXIT_TASK_SWITCH: exit=%RX64\n", exitQualification));
4545 if ( (VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE(exitQualification) == VMX_EXIT_QUALIFICATION_TASK_SWITCH_TYPE_IDT)
4546 && pVCpu->hwaccm.s.Event.fPending)
4547 {
4548 /* Caused by an injected interrupt. */
4549 pVCpu->hwaccm.s.Event.fPending = false;
4550
4551 Log(("VMX_EXIT_TASK_SWITCH: reassert trap %d\n", VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVCpu->hwaccm.s.Event.intInfo)));
4552 Assert(!VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_IS_VALID(pVCpu->hwaccm.s.Event.intInfo));
4553 rc2 = TRPMAssertTrap(pVCpu, VMX_EXIT_INTERRUPTION_INFO_VECTOR(pVCpu->hwaccm.s.Event.intInfo), TRPM_HARDWARE_INT);
4554 AssertRC(rc2);
4555 }
4556 /* else Exceptions and software interrupts can just be restarted. */
4557 rc = VERR_EM_INTERPRETER;
4558 break;
4559
4560 case VMX_EXIT_HLT: /* 12 Guest software attempted to execute HLT. */
4561 /* Check if external interrupts are pending; if so, don't switch back. */
4562 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitHlt);
4563 pCtx->rip++; /* skip hlt */
4564 if (EMShouldContinueAfterHalt(pVCpu, pCtx))
4565 goto ResumeExecution;
4566
4567 rc = VINF_EM_HALT;
4568 break;
4569
4570 case VMX_EXIT_MWAIT: /* 36 Guest software executed MWAIT. */
4571 Log2(("VMX: mwait\n"));
4572 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitMwait);
4573 rc = EMInterpretMWait(pVM, pVCpu, CPUMCTX2CORE(pCtx));
4574 if ( rc == VINF_EM_HALT
4575 || rc == VINF_SUCCESS)
4576 {
4577 /* Update EIP and continue execution. */
4578 pCtx->rip += cbInstr;
4579
4580 /* Check if external interrupts are pending; if so, don't switch back. */
4581 if ( rc == VINF_SUCCESS
4582 || ( rc == VINF_EM_HALT
4583 && EMShouldContinueAfterHalt(pVCpu, pCtx))
4584 )
4585 goto ResumeExecution;
4586 }
4587 AssertMsg(rc == VERR_EM_INTERPRETER || rc == VINF_EM_HALT, ("EMU: mwait failed with %Rrc\n", VBOXSTRICTRC_VAL(rc)));
4588 break;
4589
4590 case VMX_EXIT_RSM: /* 17 Guest software attempted to execute RSM in SMM. */
4591 AssertFailed(); /* can't happen. */
4592 rc = VERR_EM_INTERPRETER;
4593 break;
4594
4595 case VMX_EXIT_MTF: /* 37 Exit due to Monitor Trap Flag. */
4596 LogFlow(("VMX_EXIT_MTF at %RGv\n", (RTGCPTR)pCtx->rip));
4597 pVCpu->hwaccm.s.vmx.proc_ctls &= ~VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MONITOR_TRAP_FLAG;
4598 rc2 = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
4599 AssertRC(rc2);
4600 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitMTF);
4601#if 0
4602 DBGFDoneStepping(pVCpu);
4603#endif
4604 rc = VINF_EM_DBG_STOP;
4605 break;
4606
4607 case VMX_EXIT_VMCALL: /* 18 Guest software executed VMCALL. */
4608 case VMX_EXIT_VMCLEAR: /* 19 Guest software executed VMCLEAR. */
4609 case VMX_EXIT_VMLAUNCH: /* 20 Guest software executed VMLAUNCH. */
4610 case VMX_EXIT_VMPTRLD: /* 21 Guest software executed VMPTRLD. */
4611 case VMX_EXIT_VMPTRST: /* 22 Guest software executed VMPTRST. */
4612 case VMX_EXIT_VMREAD: /* 23 Guest software executed VMREAD. */
4613 case VMX_EXIT_VMRESUME: /* 24 Guest software executed VMRESUME. */
4614 case VMX_EXIT_VMWRITE: /* 25 Guest software executed VMWRITE. */
4615 case VMX_EXIT_VMXOFF: /* 26 Guest software executed VMXOFF. */
4616 case VMX_EXIT_VMXON: /* 27 Guest software executed VMXON. */
4617 /** @todo inject #UD immediately */
4618 rc = VERR_EM_INTERPRETER;
4619 break;
4620
4621 case VMX_EXIT_CPUID: /* 10 Guest software attempted to execute CPUID. */
4622 case VMX_EXIT_RDTSC: /* 16 Guest software attempted to execute RDTSC. */
4623 case VMX_EXIT_INVPG: /* 14 Guest software attempted to execute INVPG. */
4624 case VMX_EXIT_CRX_MOVE: /* 28 Control-register accesses. */
4625 case VMX_EXIT_DRX_MOVE: /* 29 Debug-register accesses. */
4626 case VMX_EXIT_PORT_IO: /* 30 I/O instruction. */
4627 case VMX_EXIT_RDPMC: /* 15 Guest software attempted to execute RDPMC. */
4628 /* already handled above */
4629 AssertMsg( rc == VINF_PGM_CHANGE_MODE
4630 || rc == VINF_EM_RAW_INTERRUPT
4631 || rc == VERR_EM_INTERPRETER
4632 || rc == VINF_EM_RAW_EMULATE_INSTR
4633 || rc == VINF_PGM_SYNC_CR3
4634 || rc == VINF_IOM_R3_IOPORT_READ
4635 || rc == VINF_IOM_R3_IOPORT_WRITE
4636 || rc == VINF_EM_RAW_GUEST_TRAP
4637 || rc == VINF_TRPM_XCPT_DISPATCHED
4638 || rc == VINF_EM_RESCHEDULE_REM,
4639 ("rc = %d\n", VBOXSTRICTRC_VAL(rc)));
4640 break;
4641
4642 case VMX_EXIT_TPR: /* 43 TPR below threshold. Guest software executed MOV to CR8. */
4643 case VMX_EXIT_RDMSR: /* 31 RDMSR. Guest software attempted to execute RDMSR. */
4644 case VMX_EXIT_WRMSR: /* 32 WRMSR. Guest software attempted to execute WRMSR. */
4645 case VMX_EXIT_PAUSE: /* 40 Guest software attempted to execute PAUSE. */
4646 case VMX_EXIT_MONITOR: /* 39 Guest software attempted to execute MONITOR. */
4647 case VMX_EXIT_APIC_ACCESS: /* 44 APIC access. Guest software attempted to access memory at a physical address
4648 on the APIC-access page. */
4649 {
4650 /*
4651 * If we decided to emulate them here, then we must sync the MSRs that could have been changed (sysenter, FS/GS base)
4652 */
4653 rc = VERR_EM_INTERPRETER;
4654 break;
4655 }
4656
4657 case VMX_EXIT_IRQ_WINDOW: /* 7 Interrupt window. */
4658 Assert(rc == VINF_EM_RAW_INTERRUPT);
4659 break;
4660
4661 case VMX_EXIT_ERR_INVALID_GUEST_STATE: /* 33 VM-entry failure due to invalid guest state. */
4662 {
4663#ifdef VBOX_STRICT
4664 RTCCUINTREG val2 = 0;
4665
4666 Log(("VMX_EXIT_ERR_INVALID_GUEST_STATE\n"));
4667
4668 VMXReadVMCS(VMX_VMCS64_GUEST_RIP, &val2);
4669 Log(("Old eip %RGv new %RGv\n", (RTGCPTR)pCtx->rip, (RTGCPTR)val2));
4670
4671 VMXReadVMCS(VMX_VMCS64_GUEST_CR0, &val2);
4672 Log(("VMX_VMCS_GUEST_CR0 %RX64\n", (uint64_t)val2));
4673
4674 VMXReadVMCS(VMX_VMCS64_GUEST_CR3, &val2);
4675 Log(("VMX_VMCS_GUEST_CR3 %RX64\n", (uint64_t)val2));
4676
4677 VMXReadVMCS(VMX_VMCS64_GUEST_CR4, &val2);
4678 Log(("VMX_VMCS_GUEST_CR4 %RX64\n", (uint64_t)val2));
4679
4680 VMXReadVMCS(VMX_VMCS_GUEST_RFLAGS, &val2);
4681 Log(("VMX_VMCS_GUEST_RFLAGS %08x\n", val2));
4682
4683 VMX_LOG_SELREG(CS, "CS", val2);
4684 VMX_LOG_SELREG(DS, "DS", val2);
4685 VMX_LOG_SELREG(ES, "ES", val2);
4686 VMX_LOG_SELREG(FS, "FS", val2);
4687 VMX_LOG_SELREG(GS, "GS", val2);
4688 VMX_LOG_SELREG(SS, "SS", val2);
4689 VMX_LOG_SELREG(TR, "TR", val2);
4690 VMX_LOG_SELREG(LDTR, "LDTR", val2);
4691
4692 VMXReadVMCS(VMX_VMCS64_GUEST_GDTR_BASE, &val2);
4693 Log(("VMX_VMCS_GUEST_GDTR_BASE %RX64\n", (uint64_t)val2));
4694 VMXReadVMCS(VMX_VMCS64_GUEST_IDTR_BASE, &val2);
4695 Log(("VMX_VMCS_GUEST_IDTR_BASE %RX64\n", (uint64_t)val2));
4696#endif /* VBOX_STRICT */
4697 rc = VERR_VMX_INVALID_GUEST_STATE;
4698 break;
4699 }
4700
4701 case VMX_EXIT_ERR_MSR_LOAD: /* 34 VM-entry failure due to MSR loading. */
4702 case VMX_EXIT_ERR_MACHINE_CHECK: /* 41 VM-entry failure due to machine-check. */
4703 default:
4704 rc = VERR_VMX_UNEXPECTED_EXIT_CODE;
4705 AssertMsgFailed(("Unexpected exit code %d\n", exitReason)); /* Can't happen. */
4706 break;
4707
4708 }
4709
4710end:
4711 /* We now going back to ring-3, so clear the action flag. */
4712 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
4713
4714 /*
4715 * Signal changes for the recompiler.
4716 */
4717 CPUMSetChangedFlags(pVCpu,
4718 CPUM_CHANGED_SYSENTER_MSR
4719 | CPUM_CHANGED_LDTR
4720 | CPUM_CHANGED_GDTR
4721 | CPUM_CHANGED_IDTR
4722 | CPUM_CHANGED_TR
4723 | CPUM_CHANGED_HIDDEN_SEL_REGS);
4724
4725 /*
4726 * If we executed vmlaunch/vmresume and an external IRQ was pending, then we don't have to do a full sync the next time.
4727 */
4728 if ( exitReason == VMX_EXIT_EXTERNAL_IRQ
4729 && !VMX_EXIT_INTERRUPTION_INFO_VALID(intInfo))
4730 {
4731 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatPendingHostIrq);
4732 /* On the next entry we'll only sync the host context. */
4733 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_HOST_CONTEXT;
4734 }
4735 else
4736 {
4737 /* On the next entry we'll sync everything. */
4738 /** @todo we can do better than this */
4739 /* Not in the VINF_PGM_CHANGE_MODE though! */
4740 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_ALL;
4741 }
4742
4743 /* Translate into a less severe return code */
4744 if (rc == VERR_EM_INTERPRETER)
4745 rc = VINF_EM_RAW_EMULATE_INSTR;
4746 else if (rc == VERR_VMX_INVALID_VMCS_PTR)
4747 {
4748 /* Try to extract more information about what might have gone wrong here. */
4749 VMXGetActivateVMCS(&pVCpu->hwaccm.s.vmx.lasterror.u64VMCSPhys);
4750 pVCpu->hwaccm.s.vmx.lasterror.ulVMCSRevision = *(uint32_t *)pVCpu->hwaccm.s.vmx.pvVMCS;
4751 pVCpu->hwaccm.s.vmx.lasterror.idEnteredCpu = pVCpu->hwaccm.s.idEnteredCpu;
4752 pVCpu->hwaccm.s.vmx.lasterror.idCurrentCpu = RTMpCpuId();
4753 }
4754
4755 /* Just set the correct state here instead of trying to catch every goto above. */
4756 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC);
4757
4758#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
4759 /* Restore interrupts if we exited after disabling them. */
4760 if (uOldEFlags != ~(RTCCUINTREG)0)
4761 ASMSetFlags(uOldEFlags);
4762#endif
4763
4764 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit2, x);
4765 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
4766 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatEntry, x);
4767 Log2(("X"));
4768 return VBOXSTRICTRC_TODO(rc);
4769}
4770
4771
4772/**
4773 * Enters the VT-x session.
4774 *
4775 * @returns VBox status code.
4776 * @param pVM Pointer to the VM.
4777 * @param pVCpu Pointer to the VMCPU.
4778 * @param pCpu Pointer to the CPU info struct.
4779 */
4780VMMR0DECL(int) VMXR0Enter(PVM pVM, PVMCPU pVCpu, PHMGLOBLCPUINFO pCpu)
4781{
4782 Assert(pVM->hwaccm.s.vmx.fSupported);
4783 NOREF(pCpu);
4784
4785 unsigned cr4 = ASMGetCR4();
4786 if (!(cr4 & X86_CR4_VMXE))
4787 {
4788 AssertMsgFailed(("X86_CR4_VMXE should be set!\n"));
4789 return VERR_VMX_X86_CR4_VMXE_CLEARED;
4790 }
4791
4792 /* Activate the VMCS. */
4793 int rc = VMXActivateVMCS(pVCpu->hwaccm.s.vmx.HCPhysVMCS);
4794 if (RT_FAILURE(rc))
4795 return rc;
4796
4797 pVCpu->hwaccm.s.fResumeVM = false;
4798 return VINF_SUCCESS;
4799}
4800
4801
4802/**
4803 * Leaves the VT-x session.
4804 *
4805 * @returns VBox status code.
4806 * @param pVM Pointer to the VM.
4807 * @param pVCpu Pointer to the VMCPU.
4808 * @param pCtx Pointer to the guests CPU context.
4809 */
4810VMMR0DECL(int) VMXR0Leave(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4811{
4812 Assert(pVM->hwaccm.s.vmx.fSupported);
4813
4814#ifdef DEBUG
4815 if (CPUMIsHyperDebugStateActive(pVCpu))
4816 {
4817 CPUMR0LoadHostDebugState(pVM, pVCpu);
4818 Assert(pVCpu->hwaccm.s.vmx.proc_ctls & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT);
4819 }
4820 else
4821#endif
4822
4823 /*
4824 * Save the guest debug state if necessary.
4825 */
4826 if (CPUMIsGuestDebugStateActive(pVCpu))
4827 {
4828 CPUMR0SaveGuestDebugState(pVM, pVCpu, pCtx, true /* save DR6 */);
4829
4830 /* Enable DRx move intercepts again. */
4831 pVCpu->hwaccm.s.vmx.proc_ctls |= VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT;
4832 int rc = VMXWriteVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, pVCpu->hwaccm.s.vmx.proc_ctls);
4833 AssertRC(rc);
4834
4835 /* Resync the debug registers the next time. */
4836 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_DEBUG;
4837 }
4838 else
4839 Assert(pVCpu->hwaccm.s.vmx.proc_ctls & VMX_VMCS_CTRL_PROC_EXEC_CONTROLS_MOV_DR_EXIT);
4840
4841 /*
4842 * Clear VMCS, marking it inactive, clearing implementation-specific data and writing
4843 * VMCS data back to memory.
4844 */
4845 int rc = VMXClearVMCS(pVCpu->hwaccm.s.vmx.HCPhysVMCS);
4846 AssertRC(rc);
4847
4848 return VINF_SUCCESS;
4849}
4850
4851
4852/**
4853 * Flush the TLB using EPT.
4854 *
4855 * @returns VBox status code.
4856 * @param pVM Pointer to the VM.
4857 * @param pVCpu Pointer to the VMCPU.
4858 * @param enmFlush Type of flush.
4859 */
4860static void hmR0VmxFlushEPT(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_EPT enmFlush)
4861{
4862 uint64_t descriptor[2];
4863
4864 LogFlow(("hmR0VmxFlushEPT %d\n", enmFlush));
4865 Assert(pVM->hwaccm.s.fNestedPaging);
4866 descriptor[0] = pVCpu->hwaccm.s.vmx.GCPhysEPTP;
4867 descriptor[1] = 0; /* MBZ. Intel spec. 33.3 VMX Instructions */
4868 int rc = VMXR0InvEPT(enmFlush, &descriptor[0]);
4869 AssertMsg(rc == VINF_SUCCESS, ("VMXR0InvEPT %x %RGv failed with %d\n", enmFlush, pVCpu->hwaccm.s.vmx.GCPhysEPTP, rc));
4870}
4871
4872
4873/**
4874 * Flush the TLB using VPID.
4875 *
4876 * @returns VBox status code.
4877 * @param pVM Pointer to the VM.
4878 * @param pVCpu Pointer to the VMCPU (can be NULL depending on @a
4879 * enmFlush).
4880 * @param enmFlush Type of flush.
4881 * @param GCPtr Virtual address of the page to flush (can be 0 depending
4882 * on @a enmFlush).
4883 */
4884static void hmR0VmxFlushVPID(PVM pVM, PVMCPU pVCpu, VMX_FLUSH_VPID enmFlush, RTGCPTR GCPtr)
4885{
4886#if HC_ARCH_BITS == 32
4887 /*
4888 * If we get a flush in 64-bit guest mode, then force a full TLB flush. invvpid probably takes only 32-bit addresses.
4889 */
4890 if ( CPUMIsGuestInLongMode(pVCpu)
4891 && !VMX_IS_64BIT_HOST_MODE())
4892 {
4893 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
4894 }
4895 else
4896#endif
4897 {
4898 uint64_t descriptor[2];
4899
4900 Assert(pVM->hwaccm.s.vmx.fVPID);
4901 if (enmFlush == VMX_FLUSH_VPID_ALL_CONTEXTS)
4902 {
4903 descriptor[0] = 0;
4904 descriptor[1] = 0;
4905 }
4906 else
4907 {
4908 AssertPtr(pVCpu);
4909 Assert(pVCpu->hwaccm.s.uCurrentASID != 0);
4910 descriptor[0] = pVCpu->hwaccm.s.uCurrentASID;
4911 descriptor[1] = GCPtr;
4912 }
4913 int rc = VMXR0InvVPID(enmFlush, &descriptor[0]); NOREF(rc);
4914 AssertMsg(rc == VINF_SUCCESS,
4915 ("VMXR0InvVPID %x %x %RGv failed with %d\n", enmFlush, pVCpu ? pVCpu->hwaccm.s.uCurrentASID : 0, GCPtr, rc));
4916 }
4917}
4918
4919
4920/**
4921 * Invalidates a guest page by guest virtual address. Only relevant for
4922 * EPT/VPID, otherwise there is nothing really to invalidate.
4923 *
4924 * @returns VBox status code.
4925 * @param pVM Pointer to the VM.
4926 * @param pVCpu Pointer to the VMCPU.
4927 * @param GCVirt Guest virtual address of the page to invalidate.
4928 */
4929VMMR0DECL(int) VMXR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt)
4930{
4931 bool fFlushPending = VMCPU_FF_ISSET(pVCpu, VMCPU_FF_TLB_FLUSH);
4932
4933 Log2(("VMXR0InvalidatePage %RGv\n", GCVirt));
4934
4935 if (!fFlushPending)
4936 {
4937 /*
4938 * We must invalidate the guest TLB entry in either case, we cannot ignore it even for the EPT case
4939 * See @bugref{6043} and @bugref{6177}
4940 *
4941 * Set the VMCPU_FF_TLB_FLUSH force flag and flush before VMENTRY in hmR0VmxSetupTLB*() as this
4942 * function maybe called in a loop with individual addresses.
4943 */
4944 if (pVM->hwaccm.s.vmx.fVPID)
4945 {
4946 /* If we can flush just this page do it, otherwise flush as little as possible. */
4947 if (pVM->hwaccm.s.vmx.msr.vmx_eptcaps & MSR_IA32_VMX_EPT_CAPS_INVVPID_CAPS_INDIV_ADDR)
4948 hmR0VmxFlushVPID(pVM, pVCpu, VMX_FLUSH_VPID_INDIV_ADDR, GCVirt);
4949 else
4950 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
4951 }
4952 else if (pVM->hwaccm.s.fNestedPaging)
4953 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
4954 }
4955
4956 return VINF_SUCCESS;
4957}
4958
4959
4960/**
4961 * Invalidates a guest page by physical address. Only relevant for EPT/VPID,
4962 * otherwise there is nothing really to invalidate.
4963 *
4964 * NOTE: Assumes the current instruction references this physical page though a virtual address!!
4965 *
4966 * @returns VBox status code.
4967 * @param pVM Pointer to the VM.
4968 * @param pVCpu Pointer to the VMCPU.
4969 * @param GCPhys Guest physical address of the page to invalidate.
4970 */
4971VMMR0DECL(int) VMXR0InvalidatePhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
4972{
4973 LogFlow(("VMXR0InvalidatePhysPage %RGp\n", GCPhys));
4974
4975 /*
4976 * We cannot flush a page by guest-physical address. invvpid takes only a linear address
4977 * while invept only flushes by EPT not individual addresses. We update the force flag here
4978 * and flush before VMENTRY in hmR0VmxSetupTLB*(). This function might be called in a loop.
4979 */
4980 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
4981 return VINF_SUCCESS;
4982}
4983
4984
4985/**
4986 * Report world switch error and dump some useful debug info.
4987 *
4988 * @param pVM Pointer to the VM.
4989 * @param pVCpu Pointer to the VMCPU.
4990 * @param rc Return code.
4991 * @param pCtx Pointer to the current guest CPU context (not updated).
4992 */
4993static void hmR0VmxReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rc, PCPUMCTX pCtx)
4994{
4995 NOREF(pVM);
4996
4997 switch (VBOXSTRICTRC_VAL(rc))
4998 {
4999 case VERR_VMX_INVALID_VMXON_PTR:
5000 AssertFailed();
5001 break;
5002
5003 case VERR_VMX_UNABLE_TO_START_VM:
5004 case VERR_VMX_UNABLE_TO_RESUME_VM:
5005 {
5006 int rc2;
5007 RTCCUINTREG exitReason, instrError;
5008
5009 rc2 = VMXReadVMCS(VMX_VMCS32_RO_EXIT_REASON, &exitReason);
5010 rc2 |= VMXReadVMCS(VMX_VMCS32_RO_VM_INSTR_ERROR, &instrError);
5011 AssertRC(rc2);
5012 if (rc2 == VINF_SUCCESS)
5013 {
5014 Log(("Unable to start/resume VM for reason: %x. Instruction error %x\n", (uint32_t)exitReason,
5015 (uint32_t)instrError));
5016 Log(("Current stack %08x\n", &rc2));
5017
5018 pVCpu->hwaccm.s.vmx.lasterror.ulInstrError = instrError;
5019 pVCpu->hwaccm.s.vmx.lasterror.ulExitReason = exitReason;
5020
5021#ifdef VBOX_STRICT
5022 RTGDTR gdtr;
5023 PCX86DESCHC pDesc;
5024 RTCCUINTREG val;
5025
5026 ASMGetGDTR(&gdtr);
5027
5028 VMXReadVMCS(VMX_VMCS64_GUEST_RIP, &val);
5029 Log(("Old eip %RGv new %RGv\n", (RTGCPTR)pCtx->rip, (RTGCPTR)val));
5030 VMXReadVMCS(VMX_VMCS_CTRL_PIN_EXEC_CONTROLS, &val);
5031 Log(("VMX_VMCS_CTRL_PIN_EXEC_CONTROLS %08x\n", val));
5032 VMXReadVMCS(VMX_VMCS_CTRL_PROC_EXEC_CONTROLS, &val);
5033 Log(("VMX_VMCS_CTRL_PROC_EXEC_CONTROLS %08x\n", val));
5034 VMXReadVMCS(VMX_VMCS_CTRL_ENTRY_CONTROLS, &val);
5035 Log(("VMX_VMCS_CTRL_ENTRY_CONTROLS %08x\n", val));
5036 VMXReadVMCS(VMX_VMCS_CTRL_EXIT_CONTROLS, &val);
5037 Log(("VMX_VMCS_CTRL_EXIT_CONTROLS %08x\n", val));
5038
5039 VMXReadVMCS(VMX_VMCS_HOST_CR0, &val);
5040 Log(("VMX_VMCS_HOST_CR0 %08x\n", val));
5041 VMXReadVMCS(VMX_VMCS_HOST_CR3, &val);
5042 Log(("VMX_VMCS_HOST_CR3 %08x\n", val));
5043 VMXReadVMCS(VMX_VMCS_HOST_CR4, &val);
5044 Log(("VMX_VMCS_HOST_CR4 %08x\n", val));
5045
5046 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_CS, &val);
5047 Log(("VMX_VMCS_HOST_FIELD_CS %08x\n", val));
5048 VMXReadVMCS(VMX_VMCS_GUEST_RFLAGS, &val);
5049 Log(("VMX_VMCS_GUEST_RFLAGS %08x\n", val));
5050
5051 if (val < gdtr.cbGdt)
5052 {
5053 pDesc = (PCX86DESCHC)(gdtr.pGdt + (val & X86_SEL_MASK));
5054 HWACCMR0DumpDescriptor(pDesc, val, "CS: ");
5055 }
5056
5057 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_DS, &val);
5058 Log(("VMX_VMCS_HOST_FIELD_DS %08x\n", val));
5059 if (val < gdtr.cbGdt)
5060 {
5061 pDesc = (PCX86DESCHC)(gdtr.pGdt + (val & X86_SEL_MASK));
5062 HWACCMR0DumpDescriptor(pDesc, val, "DS: ");
5063 }
5064
5065 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_ES, &val);
5066 Log(("VMX_VMCS_HOST_FIELD_ES %08x\n", val));
5067 if (val < gdtr.cbGdt)
5068 {
5069 pDesc = (PCX86DESCHC)(gdtr.pGdt + (val & X86_SEL_MASK));
5070 HWACCMR0DumpDescriptor(pDesc, val, "ES: ");
5071 }
5072
5073 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_FS, &val);
5074 Log(("VMX_VMCS16_HOST_FIELD_FS %08x\n", val));
5075 if (val < gdtr.cbGdt)
5076 {
5077 pDesc = (PCX86DESCHC)(gdtr.pGdt + (val & X86_SEL_MASK));
5078 HWACCMR0DumpDescriptor(pDesc, val, "FS: ");
5079 }
5080
5081 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_GS, &val);
5082 Log(("VMX_VMCS16_HOST_FIELD_GS %08x\n", val));
5083 if (val < gdtr.cbGdt)
5084 {
5085 pDesc = (PCX86DESCHC)(gdtr.pGdt + (val & X86_SEL_MASK));
5086 HWACCMR0DumpDescriptor(pDesc, val, "GS: ");
5087 }
5088
5089 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_SS, &val);
5090 Log(("VMX_VMCS16_HOST_FIELD_SS %08x\n", val));
5091 if (val < gdtr.cbGdt)
5092 {
5093 pDesc = (PCX86DESCHC)(gdtr.pGdt + (val & X86_SEL_MASK));
5094 HWACCMR0DumpDescriptor(pDesc, val, "SS: ");
5095 }
5096
5097 VMXReadVMCS(VMX_VMCS16_HOST_FIELD_TR, &val);
5098 Log(("VMX_VMCS16_HOST_FIELD_TR %08x\n", val));
5099 if (val < gdtr.cbGdt)
5100 {
5101 pDesc = (PCX86DESCHC)(gdtr.pGdt + (val & X86_SEL_MASK));
5102 HWACCMR0DumpDescriptor(pDesc, val, "TR: ");
5103 }
5104
5105 VMXReadVMCS(VMX_VMCS_HOST_TR_BASE, &val);
5106 Log(("VMX_VMCS_HOST_TR_BASE %RHv\n", val));
5107 VMXReadVMCS(VMX_VMCS_HOST_GDTR_BASE, &val);
5108 Log(("VMX_VMCS_HOST_GDTR_BASE %RHv\n", val));
5109 VMXReadVMCS(VMX_VMCS_HOST_IDTR_BASE, &val);
5110 Log(("VMX_VMCS_HOST_IDTR_BASE %RHv\n", val));
5111 VMXReadVMCS(VMX_VMCS32_HOST_SYSENTER_CS, &val);
5112 Log(("VMX_VMCS_HOST_SYSENTER_CS %08x\n", val));
5113 VMXReadVMCS(VMX_VMCS_HOST_SYSENTER_EIP, &val);
5114 Log(("VMX_VMCS_HOST_SYSENTER_EIP %RHv\n", val));
5115 VMXReadVMCS(VMX_VMCS_HOST_SYSENTER_ESP, &val);
5116 Log(("VMX_VMCS_HOST_SYSENTER_ESP %RHv\n", val));
5117 VMXReadVMCS(VMX_VMCS_HOST_RSP, &val);
5118 Log(("VMX_VMCS_HOST_RSP %RHv\n", val));
5119 VMXReadVMCS(VMX_VMCS_HOST_RIP, &val);
5120 Log(("VMX_VMCS_HOST_RIP %RHv\n", val));
5121# if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
5122 if (VMX_IS_64BIT_HOST_MODE())
5123 {
5124 Log(("MSR_K6_EFER = %RX64\n", ASMRdMsr(MSR_K6_EFER)));
5125 Log(("MSR_K6_STAR = %RX64\n", ASMRdMsr(MSR_K6_STAR)));
5126 Log(("MSR_K8_LSTAR = %RX64\n", ASMRdMsr(MSR_K8_LSTAR)));
5127 Log(("MSR_K8_CSTAR = %RX64\n", ASMRdMsr(MSR_K8_CSTAR)));
5128 Log(("MSR_K8_SF_MASK = %RX64\n", ASMRdMsr(MSR_K8_SF_MASK)));
5129 }
5130# endif
5131#endif /* VBOX_STRICT */
5132 }
5133 break;
5134 }
5135
5136 default:
5137 /* impossible */
5138 AssertMsgFailed(("%Rrc (%#x)\n", VBOXSTRICTRC_VAL(rc), VBOXSTRICTRC_VAL(rc)));
5139 break;
5140 }
5141}
5142
5143
5144#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
5145/**
5146 * Prepares for and executes VMLAUNCH (64 bits guest mode).
5147 *
5148 * @returns VBox status code.
5149 * @param fResume Whether to vmlauch/vmresume.
5150 * @param pCtx Pointer to the guest CPU context.
5151 * @param pCache Pointer to the VMCS cache.
5152 * @param pVM Pointer to the VM.
5153 * @param pVCpu Pointer to the VMCPU.
5154 */
5155DECLASM(int) VMXR0SwitcherStartVM64(RTHCUINT fResume, PCPUMCTX pCtx, PVMCSCACHE pCache, PVM pVM, PVMCPU pVCpu)
5156{
5157 uint32_t aParam[6];
5158 PHMGLOBLCPUINFO pCpu;
5159 RTHCPHYS HCPhysCpuPage;
5160 int rc;
5161
5162 pCpu = HWACCMR0GetCurrentCpu();
5163 HCPhysCpuPage = RTR0MemObjGetPagePhysAddr(pCpu->hMemObj, 0);
5164
5165#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5166 pCache->uPos = 1;
5167 pCache->interPD = PGMGetInterPaeCR3(pVM);
5168 pCache->pSwitcher = (uint64_t)pVM->hwaccm.s.pfnHost32ToGuest64R0;
5169#endif
5170
5171#ifdef DEBUG
5172 pCache->TestIn.HCPhysCpuPage= 0;
5173 pCache->TestIn.HCPhysVMCS = 0;
5174 pCache->TestIn.pCache = 0;
5175 pCache->TestOut.HCPhysVMCS = 0;
5176 pCache->TestOut.pCache = 0;
5177 pCache->TestOut.pCtx = 0;
5178 pCache->TestOut.eflags = 0;
5179#endif
5180
5181 aParam[0] = (uint32_t)(HCPhysCpuPage); /* Param 1: VMXON physical address - Lo. */
5182 aParam[1] = (uint32_t)(HCPhysCpuPage >> 32); /* Param 1: VMXON physical address - Hi. */
5183 aParam[2] = (uint32_t)(pVCpu->hwaccm.s.vmx.HCPhysVMCS); /* Param 2: VMCS physical address - Lo. */
5184 aParam[3] = (uint32_t)(pVCpu->hwaccm.s.vmx.HCPhysVMCS >> 32); /* Param 2: VMCS physical address - Hi. */
5185 aParam[4] = VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hwaccm.s.vmx.VMCSCache);
5186 aParam[5] = 0;
5187
5188#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5189 pCtx->dr[4] = pVM->hwaccm.s.vmx.pScratchPhys + 16 + 8;
5190 *(uint32_t *)(pVM->hwaccm.s.vmx.pScratch + 16 + 8) = 1;
5191#endif
5192 rc = VMXR0Execute64BitsHandler(pVM, pVCpu, pCtx, pVM->hwaccm.s.pfnVMXGCStartVM64, 6, &aParam[0]);
5193
5194#ifdef VBOX_WITH_CRASHDUMP_MAGIC
5195 Assert(*(uint32_t *)(pVM->hwaccm.s.vmx.pScratch + 16 + 8) == 5);
5196 Assert(pCtx->dr[4] == 10);
5197 *(uint32_t *)(pVM->hwaccm.s.vmx.pScratch + 16 + 8) = 0xff;
5198#endif
5199
5200#ifdef DEBUG
5201 AssertMsg(pCache->TestIn.HCPhysCpuPage== HCPhysCpuPage, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysCpuPage, HCPhysCpuPage));
5202 AssertMsg(pCache->TestIn.HCPhysVMCS == pVCpu->hwaccm.s.vmx.HCPhysVMCS, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVMCS,
5203 pVCpu->hwaccm.s.vmx.HCPhysVMCS));
5204 AssertMsg(pCache->TestIn.HCPhysVMCS == pCache->TestOut.HCPhysVMCS, ("%RHp vs %RHp\n", pCache->TestIn.HCPhysVMCS,
5205 pCache->TestOut.HCPhysVMCS));
5206 AssertMsg(pCache->TestIn.pCache == pCache->TestOut.pCache, ("%RGv vs %RGv\n", pCache->TestIn.pCache,
5207 pCache->TestOut.pCache));
5208 AssertMsg(pCache->TestIn.pCache == VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hwaccm.s.vmx.VMCSCache),
5209 ("%RGv vs %RGv\n", pCache->TestIn.pCache, VM_RC_ADDR(pVM, &pVM->aCpus[pVCpu->idCpu].hwaccm.s.vmx.VMCSCache)));
5210 AssertMsg(pCache->TestIn.pCtx == pCache->TestOut.pCtx, ("%RGv vs %RGv\n", pCache->TestIn.pCtx,
5211 pCache->TestOut.pCtx));
5212 Assert(!(pCache->TestOut.eflags & X86_EFL_IF));
5213#endif
5214 return rc;
5215}
5216
5217
5218# ifdef VBOX_STRICT
5219static bool hmR0VmxIsValidReadField(uint32_t idxField)
5220{
5221 switch (idxField)
5222 {
5223 case VMX_VMCS64_GUEST_RIP:
5224 case VMX_VMCS64_GUEST_RSP:
5225 case VMX_VMCS_GUEST_RFLAGS:
5226 case VMX_VMCS32_GUEST_INTERRUPTIBILITY_STATE:
5227 case VMX_VMCS_CTRL_CR0_READ_SHADOW:
5228 case VMX_VMCS64_GUEST_CR0:
5229 case VMX_VMCS_CTRL_CR4_READ_SHADOW:
5230 case VMX_VMCS64_GUEST_CR4:
5231 case VMX_VMCS64_GUEST_DR7:
5232 case VMX_VMCS32_GUEST_SYSENTER_CS:
5233 case VMX_VMCS64_GUEST_SYSENTER_EIP:
5234 case VMX_VMCS64_GUEST_SYSENTER_ESP:
5235 case VMX_VMCS32_GUEST_GDTR_LIMIT:
5236 case VMX_VMCS64_GUEST_GDTR_BASE:
5237 case VMX_VMCS32_GUEST_IDTR_LIMIT:
5238 case VMX_VMCS64_GUEST_IDTR_BASE:
5239 case VMX_VMCS16_GUEST_FIELD_CS:
5240 case VMX_VMCS32_GUEST_CS_LIMIT:
5241 case VMX_VMCS64_GUEST_CS_BASE:
5242 case VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS:
5243 case VMX_VMCS16_GUEST_FIELD_DS:
5244 case VMX_VMCS32_GUEST_DS_LIMIT:
5245 case VMX_VMCS64_GUEST_DS_BASE:
5246 case VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS:
5247 case VMX_VMCS16_GUEST_FIELD_ES:
5248 case VMX_VMCS32_GUEST_ES_LIMIT:
5249 case VMX_VMCS64_GUEST_ES_BASE:
5250 case VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS:
5251 case VMX_VMCS16_GUEST_FIELD_FS:
5252 case VMX_VMCS32_GUEST_FS_LIMIT:
5253 case VMX_VMCS64_GUEST_FS_BASE:
5254 case VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS:
5255 case VMX_VMCS16_GUEST_FIELD_GS:
5256 case VMX_VMCS32_GUEST_GS_LIMIT:
5257 case VMX_VMCS64_GUEST_GS_BASE:
5258 case VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS:
5259 case VMX_VMCS16_GUEST_FIELD_SS:
5260 case VMX_VMCS32_GUEST_SS_LIMIT:
5261 case VMX_VMCS64_GUEST_SS_BASE:
5262 case VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS:
5263 case VMX_VMCS16_GUEST_FIELD_LDTR:
5264 case VMX_VMCS32_GUEST_LDTR_LIMIT:
5265 case VMX_VMCS64_GUEST_LDTR_BASE:
5266 case VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS:
5267 case VMX_VMCS16_GUEST_FIELD_TR:
5268 case VMX_VMCS32_GUEST_TR_LIMIT:
5269 case VMX_VMCS64_GUEST_TR_BASE:
5270 case VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS:
5271 case VMX_VMCS32_RO_EXIT_REASON:
5272 case VMX_VMCS32_RO_VM_INSTR_ERROR:
5273 case VMX_VMCS32_RO_EXIT_INSTR_LENGTH:
5274 case VMX_VMCS32_RO_EXIT_INTERRUPTION_ERRCODE:
5275 case VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO:
5276 case VMX_VMCS32_RO_EXIT_INSTR_INFO:
5277 case VMX_VMCS_RO_EXIT_QUALIFICATION:
5278 case VMX_VMCS32_RO_IDT_INFO:
5279 case VMX_VMCS32_RO_IDT_ERRCODE:
5280 case VMX_VMCS64_GUEST_CR3:
5281 case VMX_VMCS_EXIT_PHYS_ADDR_FULL:
5282 return true;
5283 }
5284 return false;
5285}
5286
5287
5288static bool hmR0VmxIsValidWriteField(uint32_t idxField)
5289{
5290 switch (idxField)
5291 {
5292 case VMX_VMCS64_GUEST_LDTR_BASE:
5293 case VMX_VMCS64_GUEST_TR_BASE:
5294 case VMX_VMCS64_GUEST_GDTR_BASE:
5295 case VMX_VMCS64_GUEST_IDTR_BASE:
5296 case VMX_VMCS64_GUEST_SYSENTER_EIP:
5297 case VMX_VMCS64_GUEST_SYSENTER_ESP:
5298 case VMX_VMCS64_GUEST_CR0:
5299 case VMX_VMCS64_GUEST_CR4:
5300 case VMX_VMCS64_GUEST_CR3:
5301 case VMX_VMCS64_GUEST_DR7:
5302 case VMX_VMCS64_GUEST_RIP:
5303 case VMX_VMCS64_GUEST_RSP:
5304 case VMX_VMCS64_GUEST_CS_BASE:
5305 case VMX_VMCS64_GUEST_DS_BASE:
5306 case VMX_VMCS64_GUEST_ES_BASE:
5307 case VMX_VMCS64_GUEST_FS_BASE:
5308 case VMX_VMCS64_GUEST_GS_BASE:
5309 case VMX_VMCS64_GUEST_SS_BASE:
5310 return true;
5311 }
5312 return false;
5313}
5314# endif /* VBOX_STRICT */
5315
5316
5317/**
5318 * Executes the specified handler in 64-bit mode.
5319 *
5320 * @returns VBox status code.
5321 * @param pVM Pointer to the VM.
5322 * @param pVCpu Pointer to the VMCPU.
5323 * @param pCtx Pointer to the guest CPU context.
5324 * @param pfnHandler Pointer to the RC handler function.
5325 * @param cbParam Number of parameters.
5326 * @param paParam Array of 32-bit parameters.
5327 */
5328VMMR0DECL(int) VMXR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTRCPTR pfnHandler, uint32_t cbParam,
5329 uint32_t *paParam)
5330{
5331 int rc, rc2;
5332 PHMGLOBLCPUINFO pCpu;
5333 RTHCPHYS HCPhysCpuPage;
5334 RTHCUINTREG uOldEFlags;
5335
5336 AssertReturn(pVM->hwaccm.s.pfnHost32ToGuest64R0, VERR_HM_NO_32_TO_64_SWITCHER);
5337 Assert(pfnHandler);
5338 Assert(pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries <= RT_ELEMENTS(pVCpu->hwaccm.s.vmx.VMCSCache.Write.aField));
5339 Assert(pVCpu->hwaccm.s.vmx.VMCSCache.Read.cValidEntries <= RT_ELEMENTS(pVCpu->hwaccm.s.vmx.VMCSCache.Read.aField));
5340
5341#ifdef VBOX_STRICT
5342 for (unsigned i=0;i<pVCpu->hwaccm.s.vmx.VMCSCache.Write.cValidEntries;i++)
5343 Assert(hmR0VmxIsValidWriteField(pVCpu->hwaccm.s.vmx.VMCSCache.Write.aField[i]));
5344
5345 for (unsigned i=0;i<pVCpu->hwaccm.s.vmx.VMCSCache.Read.cValidEntries;i++)
5346 Assert(hmR0VmxIsValidReadField(pVCpu->hwaccm.s.vmx.VMCSCache.Read.aField[i]));
5347#endif
5348
5349 /* Disable interrupts. */
5350 uOldEFlags = ASMIntDisableFlags();
5351
5352#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
5353 RTCPUID idHostCpu = RTMpCpuId();
5354 CPUMR0SetLApic(pVM, idHostCpu);
5355#endif
5356
5357 pCpu = HWACCMR0GetCurrentCpu();
5358 HCPhysCpuPage = RTR0MemObjGetPagePhysAddr(pCpu->hMemObj, 0);
5359
5360 /* Clear VMCS. Marking it inactive, clearing implementation-specific data and writing VMCS data back to memory. */
5361 VMXClearVMCS(pVCpu->hwaccm.s.vmx.HCPhysVMCS);
5362
5363 /* Leave VMX Root Mode. */
5364 VMXDisable();
5365
5366 ASMSetCR4(ASMGetCR4() & ~X86_CR4_VMXE);
5367
5368 CPUMSetHyperESP(pVCpu, VMMGetStackRC(pVCpu));
5369 CPUMSetHyperEIP(pVCpu, pfnHandler);
5370 for (int i=(int)cbParam-1;i>=0;i--)
5371 CPUMPushHyper(pVCpu, paParam[i]);
5372
5373 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatWorldSwitch3264, z);
5374
5375 /* Call switcher. */
5376 rc = pVM->hwaccm.s.pfnHost32ToGuest64R0(pVM, RT_OFFSETOF(VM, aCpus[pVCpu->idCpu].cpum) - RT_OFFSETOF(VM, cpum));
5377 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatWorldSwitch3264, z);
5378
5379 /* Make sure the VMX instructions don't cause #UD faults. */
5380 ASMSetCR4(ASMGetCR4() | X86_CR4_VMXE);
5381
5382 /* Enter VMX Root Mode */
5383 rc2 = VMXEnable(HCPhysCpuPage);
5384 if (RT_FAILURE(rc2))
5385 {
5386 ASMSetCR4(ASMGetCR4() & ~X86_CR4_VMXE);
5387 ASMSetFlags(uOldEFlags);
5388 return VERR_VMX_VMXON_FAILED;
5389 }
5390
5391 rc2 = VMXActivateVMCS(pVCpu->hwaccm.s.vmx.HCPhysVMCS);
5392 AssertRC(rc2);
5393 Assert(!(ASMGetFlags() & X86_EFL_IF));
5394 ASMSetFlags(uOldEFlags);
5395 return rc;
5396}
5397#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL) */
5398
5399
5400#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
5401/**
5402 * Executes VMWRITE.
5403 *
5404 * @returns VBox status code
5405 * @param pVCpu Pointer to the VMCPU.
5406 * @param idxField VMCS field index.
5407 * @param u64Val 16, 32 or 64 bits value.
5408 */
5409VMMR0DECL(int) VMXWriteVMCS64Ex(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5410{
5411 int rc;
5412 switch (idxField)
5413 {
5414 case VMX_VMCS_CTRL_TSC_OFFSET_FULL:
5415 case VMX_VMCS_CTRL_IO_BITMAP_A_FULL:
5416 case VMX_VMCS_CTRL_IO_BITMAP_B_FULL:
5417 case VMX_VMCS_CTRL_MSR_BITMAP_FULL:
5418 case VMX_VMCS_CTRL_VMEXIT_MSR_STORE_FULL:
5419 case VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_FULL:
5420 case VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_FULL:
5421 case VMX_VMCS_CTRL_VAPIC_PAGEADDR_FULL:
5422 case VMX_VMCS_CTRL_APIC_ACCESSADDR_FULL:
5423 case VMX_VMCS_GUEST_LINK_PTR_FULL:
5424 case VMX_VMCS_GUEST_PDPTR0_FULL:
5425 case VMX_VMCS_GUEST_PDPTR1_FULL:
5426 case VMX_VMCS_GUEST_PDPTR2_FULL:
5427 case VMX_VMCS_GUEST_PDPTR3_FULL:
5428 case VMX_VMCS_GUEST_DEBUGCTL_FULL:
5429 case VMX_VMCS_GUEST_EFER_FULL:
5430 case VMX_VMCS_CTRL_EPTP_FULL:
5431 /* These fields consist of two parts, which are both writable in 32 bits mode. */
5432 rc = VMXWriteVMCS32(idxField, u64Val);
5433 rc |= VMXWriteVMCS32(idxField + 1, (uint32_t)(u64Val >> 32ULL));
5434 AssertRC(rc);
5435 return rc;
5436
5437 case VMX_VMCS64_GUEST_LDTR_BASE:
5438 case VMX_VMCS64_GUEST_TR_BASE:
5439 case VMX_VMCS64_GUEST_GDTR_BASE:
5440 case VMX_VMCS64_GUEST_IDTR_BASE:
5441 case VMX_VMCS64_GUEST_SYSENTER_EIP:
5442 case VMX_VMCS64_GUEST_SYSENTER_ESP:
5443 case VMX_VMCS64_GUEST_CR0:
5444 case VMX_VMCS64_GUEST_CR4:
5445 case VMX_VMCS64_GUEST_CR3:
5446 case VMX_VMCS64_GUEST_DR7:
5447 case VMX_VMCS64_GUEST_RIP:
5448 case VMX_VMCS64_GUEST_RSP:
5449 case VMX_VMCS64_GUEST_CS_BASE:
5450 case VMX_VMCS64_GUEST_DS_BASE:
5451 case VMX_VMCS64_GUEST_ES_BASE:
5452 case VMX_VMCS64_GUEST_FS_BASE:
5453 case VMX_VMCS64_GUEST_GS_BASE:
5454 case VMX_VMCS64_GUEST_SS_BASE:
5455 /* Queue a 64 bits value as we can't set it in 32 bits host mode. */
5456 if (u64Val >> 32ULL)
5457 rc = VMXWriteCachedVMCSEx(pVCpu, idxField, u64Val);
5458 else
5459 rc = VMXWriteVMCS32(idxField, (uint32_t)u64Val);
5460
5461 return rc;
5462
5463 default:
5464 AssertMsgFailed(("Unexpected field %x\n", idxField));
5465 return VERR_INVALID_PARAMETER;
5466 }
5467}
5468
5469
5470/**
5471 * Cache VMCS writes for performance reasons (Darwin) and for running 64 bits guests on 32 bits hosts.
5472 *
5473 * @param pVCpu Pointer to the VMCPU.
5474 * @param idxField VMCS field index.
5475 * @param u64Val 16, 32 or 64 bits value.
5476 */
5477VMMR0DECL(int) VMXWriteCachedVMCSEx(PVMCPU pVCpu, uint32_t idxField, uint64_t u64Val)
5478{
5479 PVMCSCACHE pCache = &pVCpu->hwaccm.s.vmx.VMCSCache;
5480
5481 AssertMsgReturn(pCache->Write.cValidEntries < VMCSCACHE_MAX_ENTRY - 1,
5482 ("entries=%x\n", pCache->Write.cValidEntries), VERR_ACCESS_DENIED);
5483
5484 /* Make sure there are no duplicates. */
5485 for (unsigned i = 0; i < pCache->Write.cValidEntries; i++)
5486 {
5487 if (pCache->Write.aField[i] == idxField)
5488 {
5489 pCache->Write.aFieldVal[i] = u64Val;
5490 return VINF_SUCCESS;
5491 }
5492 }
5493
5494 pCache->Write.aField[pCache->Write.cValidEntries] = idxField;
5495 pCache->Write.aFieldVal[pCache->Write.cValidEntries] = u64Val;
5496 pCache->Write.cValidEntries++;
5497 return VINF_SUCCESS;
5498}
5499
5500#endif /* HC_ARCH_BITS == 32 && !VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
5501
Note: See TracBrowser for help on using the repository browser.

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