VirtualBox

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

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

Fully emulated lmsw.

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

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