VirtualBox

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

Last change on this file since 12756 was 12756, checked in by vboxsync, 17 years ago

Attempt to correct hidden selector attributes when switching from real to protected mode. (VT-x weirdness again)

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

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