VirtualBox

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

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

Added debugging code (inactive) for tracking the state of the 32/64 switcher in crash dumps

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