VirtualBox

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

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

Log additional VT-x flags

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

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