VirtualBox

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

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

Fixed regression introduced by TPR caching. (never execute code that can jump back to ring 3 in *LoadGuestState)

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

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