VirtualBox

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

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

Logging change

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

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