VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp@ 26718

Last change on this file since 26718 was 26152, checked in by vboxsync, 15 years ago

VMM: pdm.h and @copydoc cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 114.5 KB
Line 
1/* $Id: HWSVMR0.cpp 26152 2010-02-02 16:00:35Z vboxsync $ */
2/** @file
3 * HWACCM SVM - 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 <VBox/pgm.h>
29#include <VBox/selm.h>
30#include <VBox/iom.h>
31#include <VBox/dbgf.h>
32#include <VBox/tm.h>
33#include <VBox/pdmapi.h>
34#include "HWACCMInternal.h"
35#include <VBox/vm.h>
36#include <VBox/x86.h>
37#include <VBox/hwacc_svm.h>
38#include <VBox/err.h>
39#include <VBox/log.h>
40#include <VBox/dis.h>
41#include <VBox/disopcode.h>
42#include <iprt/param.h>
43#include <iprt/assert.h>
44#include <iprt/asm.h>
45#include <iprt/cpuset.h>
46#include <iprt/mp.h>
47#include <iprt/time.h>
48#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
49# include <iprt/thread.h>
50#endif
51#include "HWSVMR0.h"
52
53/*******************************************************************************
54* Internal Functions *
55*******************************************************************************/
56static int svmR0InterpretInvpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t uASID);
57static int svmR0EmulateTprVMMCall(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx);
58static void svmR0SetMSRPermission(PVMCPU pVCpu, unsigned ulMSR, bool fRead, bool fWrite);
59
60/*******************************************************************************
61* Global Variables *
62*******************************************************************************/
63
64/**
65 * Sets up and activates AMD-V on the current CPU
66 *
67 * @returns VBox status code.
68 * @param pCpu CPU info struct
69 * @param pVM The VM to operate on. (can be NULL after a resume!!)
70 * @param pvPageCpu Pointer to the global cpu page
71 * @param pPageCpuPhys Physical address of the global cpu page
72 */
73VMMR0DECL(int) SVMR0EnableCpu(PHWACCM_CPUINFO pCpu, PVM pVM, void *pvPageCpu, RTHCPHYS pPageCpuPhys)
74{
75 AssertReturn(pPageCpuPhys, VERR_INVALID_PARAMETER);
76 AssertReturn(pvPageCpu, VERR_INVALID_PARAMETER);
77
78 /* We must turn on AMD-V and setup the host state physical address, as those MSRs are per-cpu/core. */
79 uint64_t val = ASMRdMsr(MSR_K6_EFER);
80 if (val & MSR_K6_EFER_SVME)
81 {
82 /* If the VBOX_HWVIRTEX_IGNORE_SVM_IN_USE hack is active, then we blindly use AMD-V. */
83 if ( pVM
84 && pVM->hwaccm.s.svm.fIgnoreInUseError)
85 {
86 pCpu->fIgnoreAMDVInUseError = true;
87 }
88
89 if (!pCpu->fIgnoreAMDVInUseError)
90 return VERR_SVM_IN_USE;
91 }
92
93 /* Turn on AMD-V in the EFER MSR. */
94 ASMWrMsr(MSR_K6_EFER, val | MSR_K6_EFER_SVME);
95
96 /* Write the physical page address where the CPU will store the host state while executing the VM. */
97 ASMWrMsr(MSR_K8_VM_HSAVE_PA, pPageCpuPhys);
98
99 return VINF_SUCCESS;
100}
101
102/**
103 * Deactivates AMD-V on the current CPU
104 *
105 * @returns VBox status code.
106 * @param pCpu CPU info struct
107 * @param pvPageCpu Pointer to the global cpu page
108 * @param pPageCpuPhys Physical address of the global cpu page
109 */
110VMMR0DECL(int) SVMR0DisableCpu(PHWACCM_CPUINFO pCpu, void *pvPageCpu, RTHCPHYS pPageCpuPhys)
111{
112 AssertReturn(pPageCpuPhys, VERR_INVALID_PARAMETER);
113 AssertReturn(pvPageCpu, VERR_INVALID_PARAMETER);
114
115 /* Turn off AMD-V in the EFER MSR. */
116 uint64_t val = ASMRdMsr(MSR_K6_EFER);
117 ASMWrMsr(MSR_K6_EFER, val & ~MSR_K6_EFER_SVME);
118
119 /* Invalidate host state physical address. */
120 ASMWrMsr(MSR_K8_VM_HSAVE_PA, 0);
121
122 return VINF_SUCCESS;
123}
124
125/**
126 * Does Ring-0 per VM AMD-V init.
127 *
128 * @returns VBox status code.
129 * @param pVM The VM to operate on.
130 */
131VMMR0DECL(int) SVMR0InitVM(PVM pVM)
132{
133 int rc;
134
135 pVM->hwaccm.s.svm.pMemObjIOBitmap = NIL_RTR0MEMOBJ;
136
137 /* Allocate 12 KB for the IO bitmap (doesn't seem to be a way to convince SVM not to use it) */
138 rc = RTR0MemObjAllocCont(&pVM->hwaccm.s.svm.pMemObjIOBitmap, 3 << PAGE_SHIFT, true /* executable R0 mapping */);
139 if (RT_FAILURE(rc))
140 return rc;
141
142 pVM->hwaccm.s.svm.pIOBitmap = RTR0MemObjAddress(pVM->hwaccm.s.svm.pMemObjIOBitmap);
143 pVM->hwaccm.s.svm.pIOBitmapPhys = RTR0MemObjGetPagePhysAddr(pVM->hwaccm.s.svm.pMemObjIOBitmap, 0);
144 /* Set all bits to intercept all IO accesses. */
145 ASMMemFill32(pVM->hwaccm.s.svm.pIOBitmap, PAGE_SIZE*3, 0xffffffff);
146
147 /* Erratum 170 which requires a forced TLB flush for each world switch:
148 * See http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/33610.pdf
149 *
150 * All BH-G1/2 and DH-G1/2 models include a fix:
151 * Athlon X2: 0x6b 1/2
152 * 0x68 1/2
153 * Athlon 64: 0x7f 1
154 * 0x6f 2
155 * Sempron: 0x7f 1/2
156 * 0x6f 2
157 * 0x6c 2
158 * 0x7c 2
159 * Turion 64: 0x68 2
160 *
161 */
162 uint32_t u32Dummy;
163 uint32_t u32Version, u32Family, u32Model, u32Stepping, u32BaseFamily;
164 ASMCpuId(1, &u32Version, &u32Dummy, &u32Dummy, &u32Dummy);
165 u32BaseFamily= (u32Version >> 8) & 0xf;
166 u32Family = u32BaseFamily + (u32BaseFamily == 0xf ? ((u32Version >> 20) & 0x7f) : 0);
167 u32Model = ((u32Version >> 4) & 0xf);
168 u32Model = u32Model | ((u32BaseFamily == 0xf ? (u32Version >> 16) & 0x0f : 0) << 4);
169 u32Stepping = u32Version & 0xf;
170 if ( u32Family == 0xf
171 && !((u32Model == 0x68 || u32Model == 0x6b || u32Model == 0x7f) && u32Stepping >= 1)
172 && !((u32Model == 0x6f || u32Model == 0x6c || u32Model == 0x7c) && u32Stepping >= 2))
173 {
174 Log(("SVMR0InitVM: AMD cpu with erratum 170 family %x model %x stepping %x\n", u32Family, u32Model, u32Stepping));
175 pVM->hwaccm.s.svm.fAlwaysFlushTLB = true;
176 }
177
178 /* Allocate VMCBs for all guest CPUs. */
179 for (VMCPUID i = 0; i < pVM->cCpus; i++)
180 {
181 PVMCPU pVCpu = &pVM->aCpus[i];
182
183 pVCpu->hwaccm.s.svm.pMemObjVMCBHost = NIL_RTR0MEMOBJ;
184 pVCpu->hwaccm.s.svm.pMemObjVMCB = NIL_RTR0MEMOBJ;
185 pVCpu->hwaccm.s.svm.pMemObjMSRBitmap = NIL_RTR0MEMOBJ;
186
187 /* Allocate one page for the host context */
188 rc = RTR0MemObjAllocCont(&pVCpu->hwaccm.s.svm.pMemObjVMCBHost, 1 << PAGE_SHIFT, true /* executable R0 mapping */);
189 if (RT_FAILURE(rc))
190 return rc;
191
192 pVCpu->hwaccm.s.svm.pVMCBHost = RTR0MemObjAddress(pVCpu->hwaccm.s.svm.pMemObjVMCBHost);
193 pVCpu->hwaccm.s.svm.pVMCBHostPhys = RTR0MemObjGetPagePhysAddr(pVCpu->hwaccm.s.svm.pMemObjVMCBHost, 0);
194 Assert(pVCpu->hwaccm.s.svm.pVMCBHostPhys < _4G);
195 ASMMemZeroPage(pVCpu->hwaccm.s.svm.pVMCBHost);
196
197 /* Allocate one page for the VM control block (VMCB). */
198 rc = RTR0MemObjAllocCont(&pVCpu->hwaccm.s.svm.pMemObjVMCB, 1 << PAGE_SHIFT, true /* executable R0 mapping */);
199 if (RT_FAILURE(rc))
200 return rc;
201
202 pVCpu->hwaccm.s.svm.pVMCB = RTR0MemObjAddress(pVCpu->hwaccm.s.svm.pMemObjVMCB);
203 pVCpu->hwaccm.s.svm.pVMCBPhys = RTR0MemObjGetPagePhysAddr(pVCpu->hwaccm.s.svm.pMemObjVMCB, 0);
204 Assert(pVCpu->hwaccm.s.svm.pVMCBPhys < _4G);
205 ASMMemZeroPage(pVCpu->hwaccm.s.svm.pVMCB);
206
207 /* Allocate 8 KB for the MSR bitmap (doesn't seem to be a way to convince SVM not to use it) */
208 rc = RTR0MemObjAllocCont(&pVCpu->hwaccm.s.svm.pMemObjMSRBitmap, 2 << PAGE_SHIFT, true /* executable R0 mapping */);
209 if (RT_FAILURE(rc))
210 return rc;
211
212 pVCpu->hwaccm.s.svm.pMSRBitmap = RTR0MemObjAddress(pVCpu->hwaccm.s.svm.pMemObjMSRBitmap);
213 pVCpu->hwaccm.s.svm.pMSRBitmapPhys = RTR0MemObjGetPagePhysAddr(pVCpu->hwaccm.s.svm.pMemObjMSRBitmap, 0);
214 /* Set all bits to intercept all MSR accesses. */
215 ASMMemFill32(pVCpu->hwaccm.s.svm.pMSRBitmap, PAGE_SIZE*2, 0xffffffff);
216 }
217
218 return VINF_SUCCESS;
219}
220
221/**
222 * Does Ring-0 per VM AMD-V termination.
223 *
224 * @returns VBox status code.
225 * @param pVM The VM to operate on.
226 */
227VMMR0DECL(int) SVMR0TermVM(PVM pVM)
228{
229 for (VMCPUID i = 0; i < pVM->cCpus; i++)
230 {
231 PVMCPU pVCpu = &pVM->aCpus[i];
232
233 if (pVCpu->hwaccm.s.svm.pMemObjVMCBHost != NIL_RTR0MEMOBJ)
234 {
235 RTR0MemObjFree(pVCpu->hwaccm.s.svm.pMemObjVMCBHost, false);
236 pVCpu->hwaccm.s.svm.pVMCBHost = 0;
237 pVCpu->hwaccm.s.svm.pVMCBHostPhys = 0;
238 pVCpu->hwaccm.s.svm.pMemObjVMCBHost = NIL_RTR0MEMOBJ;
239 }
240
241 if (pVCpu->hwaccm.s.svm.pMemObjVMCB != NIL_RTR0MEMOBJ)
242 {
243 RTR0MemObjFree(pVCpu->hwaccm.s.svm.pMemObjVMCB, false);
244 pVCpu->hwaccm.s.svm.pVMCB = 0;
245 pVCpu->hwaccm.s.svm.pVMCBPhys = 0;
246 pVCpu->hwaccm.s.svm.pMemObjVMCB = NIL_RTR0MEMOBJ;
247 }
248 if (pVCpu->hwaccm.s.svm.pMemObjMSRBitmap != NIL_RTR0MEMOBJ)
249 {
250 RTR0MemObjFree(pVCpu->hwaccm.s.svm.pMemObjMSRBitmap, false);
251 pVCpu->hwaccm.s.svm.pMSRBitmap = 0;
252 pVCpu->hwaccm.s.svm.pMSRBitmapPhys = 0;
253 pVCpu->hwaccm.s.svm.pMemObjMSRBitmap = NIL_RTR0MEMOBJ;
254 }
255 }
256 if (pVM->hwaccm.s.svm.pMemObjIOBitmap != NIL_RTR0MEMOBJ)
257 {
258 RTR0MemObjFree(pVM->hwaccm.s.svm.pMemObjIOBitmap, false);
259 pVM->hwaccm.s.svm.pIOBitmap = 0;
260 pVM->hwaccm.s.svm.pIOBitmapPhys = 0;
261 pVM->hwaccm.s.svm.pMemObjIOBitmap = NIL_RTR0MEMOBJ;
262 }
263 return VINF_SUCCESS;
264}
265
266/**
267 * Sets up AMD-V for the specified VM
268 *
269 * @returns VBox status code.
270 * @param pVM The VM to operate on.
271 */
272VMMR0DECL(int) SVMR0SetupVM(PVM pVM)
273{
274 int rc = VINF_SUCCESS;
275
276 AssertReturn(pVM, VERR_INVALID_PARAMETER);
277
278 Assert(pVM->hwaccm.s.svm.fSupported);
279
280 for (VMCPUID i = 0; i < pVM->cCpus; i++)
281 {
282 PVMCPU pVCpu = &pVM->aCpus[i];
283 SVM_VMCB *pVMCB = (SVM_VMCB *)pVM->aCpus[i].hwaccm.s.svm.pVMCB;
284
285 AssertMsgReturn(pVMCB, ("Invalid pVMCB\n"), VERR_EM_INTERNAL_ERROR);
286
287 /* Program the control fields. Most of them never have to be changed again. */
288 /* CR0/3/4 reads must be intercepted, our shadow values are not necessarily the same as the guest's. */
289 /* Note: CR0 & CR4 can be safely read when guest and shadow copies are identical. */
290 if (!pVM->hwaccm.s.fNestedPaging)
291 pVMCB->ctrl.u16InterceptRdCRx = RT_BIT(0) | RT_BIT(3) | RT_BIT(4);
292 else
293 pVMCB->ctrl.u16InterceptRdCRx = RT_BIT(0) | RT_BIT(4);
294
295 /*
296 * CR0/3/4 writes must be intercepted for obvious reasons.
297 */
298 if (!pVM->hwaccm.s.fNestedPaging)
299 pVMCB->ctrl.u16InterceptWrCRx = RT_BIT(0) | RT_BIT(3) | RT_BIT(4);
300 else
301 pVMCB->ctrl.u16InterceptWrCRx = RT_BIT(0) | RT_BIT(4) | RT_BIT(8);
302
303 /* Intercept all DRx reads and writes by default. Changed later on. */
304 pVMCB->ctrl.u16InterceptRdDRx = 0xFFFF;
305 pVMCB->ctrl.u16InterceptWrDRx = 0xFFFF;
306
307 /* Currently we don't care about DRx reads or writes. DRx registers are trashed.
308 * All breakpoints are automatically cleared when the VM exits.
309 */
310
311 pVMCB->ctrl.u32InterceptException = HWACCM_SVM_TRAP_MASK;
312#ifndef DEBUG
313 if (pVM->hwaccm.s.fNestedPaging)
314 pVMCB->ctrl.u32InterceptException &= ~RT_BIT(X86_XCPT_PF); /* no longer need to intercept #PF. */
315#endif
316
317 pVMCB->ctrl.u32InterceptCtrl1 = SVM_CTRL1_INTERCEPT_INTR
318 | SVM_CTRL1_INTERCEPT_VINTR
319 | SVM_CTRL1_INTERCEPT_NMI
320 | SVM_CTRL1_INTERCEPT_SMI
321 | SVM_CTRL1_INTERCEPT_INIT
322 | SVM_CTRL1_INTERCEPT_RDPMC
323 | SVM_CTRL1_INTERCEPT_CPUID
324 | SVM_CTRL1_INTERCEPT_RSM
325 | SVM_CTRL1_INTERCEPT_HLT
326 | SVM_CTRL1_INTERCEPT_INOUT_BITMAP
327 | SVM_CTRL1_INTERCEPT_MSR_SHADOW
328 | SVM_CTRL1_INTERCEPT_INVLPG
329 | SVM_CTRL1_INTERCEPT_INVLPGA /* AMD only */
330 | SVM_CTRL1_INTERCEPT_TASK_SWITCH
331 | SVM_CTRL1_INTERCEPT_SHUTDOWN /* fatal */
332 | SVM_CTRL1_INTERCEPT_FERR_FREEZE; /* Legacy FPU FERR handling. */
333 ;
334 /* With nested paging we don't care about invlpg anymore. */
335 if (pVM->hwaccm.s.fNestedPaging)
336 pVMCB->ctrl.u32InterceptCtrl1 &= ~SVM_CTRL1_INTERCEPT_INVLPG;
337
338 pVMCB->ctrl.u32InterceptCtrl2 = SVM_CTRL2_INTERCEPT_VMRUN /* required */
339 | SVM_CTRL2_INTERCEPT_VMMCALL
340 | SVM_CTRL2_INTERCEPT_VMLOAD
341 | SVM_CTRL2_INTERCEPT_VMSAVE
342 | SVM_CTRL2_INTERCEPT_STGI
343 | SVM_CTRL2_INTERCEPT_CLGI
344 | SVM_CTRL2_INTERCEPT_SKINIT
345 | SVM_CTRL2_INTERCEPT_WBINVD
346 | SVM_CTRL2_INTERCEPT_MWAIT_UNCOND; /* don't execute mwait or else we'll idle inside the guest (host thinks the cpu load is high) */
347 ;
348 Log(("pVMCB->ctrl.u32InterceptException = %x\n", pVMCB->ctrl.u32InterceptException));
349 Log(("pVMCB->ctrl.u32InterceptCtrl1 = %x\n", pVMCB->ctrl.u32InterceptCtrl1));
350 Log(("pVMCB->ctrl.u32InterceptCtrl2 = %x\n", pVMCB->ctrl.u32InterceptCtrl2));
351
352 /* Virtualize masking of INTR interrupts. (reads/writes from/to CR8 go to the V_TPR register) */
353 pVMCB->ctrl.IntCtrl.n.u1VIrqMasking = 1;
354 /* Ignore the priority in the TPR; just deliver it when we tell it to. */
355 pVMCB->ctrl.IntCtrl.n.u1IgnoreTPR = 1;
356
357 /* Set IO and MSR bitmap addresses. */
358 pVMCB->ctrl.u64IOPMPhysAddr = pVM->hwaccm.s.svm.pIOBitmapPhys;
359 pVMCB->ctrl.u64MSRPMPhysAddr = pVCpu->hwaccm.s.svm.pMSRBitmapPhys;
360
361 /* No LBR virtualization. */
362 pVMCB->ctrl.u64LBRVirt = 0;
363
364 /** The ASID must start at 1; the host uses 0. */
365 pVMCB->ctrl.TLBCtrl.n.u32ASID = 1;
366
367 /** Setup the PAT msr (nested paging only) */
368 pVMCB->guest.u64GPAT = 0x0007040600070406ULL;
369
370 /* The following MSRs are saved automatically by vmload/vmsave, so we allow the guest
371 * to modify them directly.
372 */
373 svmR0SetMSRPermission(pVCpu, MSR_K8_LSTAR, true, true);
374 svmR0SetMSRPermission(pVCpu, MSR_K8_CSTAR, true, true);
375 svmR0SetMSRPermission(pVCpu, MSR_K6_STAR, true, true);
376 svmR0SetMSRPermission(pVCpu, MSR_K8_SF_MASK, true, true);
377 svmR0SetMSRPermission(pVCpu, MSR_K8_FS_BASE, true, true);
378 svmR0SetMSRPermission(pVCpu, MSR_K8_GS_BASE, true, true);
379 svmR0SetMSRPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, true, true);
380 svmR0SetMSRPermission(pVCpu, MSR_IA32_SYSENTER_CS, true, true);
381 svmR0SetMSRPermission(pVCpu, MSR_IA32_SYSENTER_ESP, true, true);
382 svmR0SetMSRPermission(pVCpu, MSR_IA32_SYSENTER_EIP, true, true);
383 }
384
385 return rc;
386}
387
388
389/**
390 * Sets the permission bits for the specified MSR
391 *
392 * @param pVCpu The VMCPU to operate on.
393 * @param ulMSR MSR value
394 * @param fRead Reading allowed/disallowed
395 * @param fWrite Writing allowed/disallowed
396 */
397static void svmR0SetMSRPermission(PVMCPU pVCpu, unsigned ulMSR, bool fRead, bool fWrite)
398{
399 unsigned ulBit;
400 uint8_t *pMSRBitmap = (uint8_t *)pVCpu->hwaccm.s.svm.pMSRBitmap;
401
402 if (ulMSR <= 0x00001FFF)
403 {
404 /* Pentium-compatible MSRs */
405 ulBit = ulMSR * 2;
406 }
407 else
408 if ( ulMSR >= 0xC0000000
409 && ulMSR <= 0xC0001FFF)
410 {
411 /* AMD Sixth Generation x86 Processor MSRs and SYSCALL */
412 ulBit = (ulMSR - 0xC0000000) * 2;
413 pMSRBitmap += 0x800;
414 }
415 else
416 if ( ulMSR >= 0xC0010000
417 && ulMSR <= 0xC0011FFF)
418 {
419 /* AMD Seventh and Eighth Generation Processor MSRs */
420 ulBit = (ulMSR - 0xC0001000) * 2;
421 pMSRBitmap += 0x1000;
422 }
423 else
424 {
425 AssertFailed();
426 return;
427 }
428 Assert(ulBit < 16 * 1024 - 1);
429 if (fRead)
430 ASMBitClear(pMSRBitmap, ulBit);
431 else
432 ASMBitSet(pMSRBitmap, ulBit);
433
434 if (fWrite)
435 ASMBitClear(pMSRBitmap, ulBit + 1);
436 else
437 ASMBitSet(pMSRBitmap, ulBit + 1);
438}
439
440/**
441 * Injects an event (trap or external interrupt)
442 *
443 * @param pVCpu The VMCPU to operate on.
444 * @param pVMCB SVM control block
445 * @param pCtx CPU Context
446 * @param pIntInfo SVM interrupt info
447 */
448inline void SVMR0InjectEvent(PVMCPU pVCpu, SVM_VMCB *pVMCB, CPUMCTX *pCtx, SVM_EVENT* pEvent)
449{
450#ifdef VBOX_WITH_STATISTICS
451 STAM_COUNTER_INC(&pVCpu->hwaccm.s.paStatInjectedIrqsR0[pEvent->n.u8Vector & MASK_INJECT_IRQ_STAT]);
452#endif
453
454#ifdef VBOX_STRICT
455 if (pEvent->n.u8Vector == 0xE)
456 Log(("SVM: Inject int %d at %RGv error code=%02x CR2=%RGv intInfo=%08x\n", pEvent->n.u8Vector, (RTGCPTR)pCtx->rip, pEvent->n.u32ErrorCode, (RTGCPTR)pCtx->cr2, pEvent->au64[0]));
457 else
458 if (pEvent->n.u8Vector < 0x20)
459 Log(("SVM: Inject int %d at %RGv error code=%08x\n", pEvent->n.u8Vector, (RTGCPTR)pCtx->rip, pEvent->n.u32ErrorCode));
460 else
461 {
462 Log(("INJ-EI: %x at %RGv\n", pEvent->n.u8Vector, (RTGCPTR)pCtx->rip));
463 Assert(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
464 Assert(pCtx->eflags.u32 & X86_EFL_IF);
465 }
466#endif
467
468 /* Set event injection state. */
469 pVMCB->ctrl.EventInject.au64[0] = pEvent->au64[0];
470}
471
472
473/**
474 * Checks for pending guest interrupts and injects them
475 *
476 * @returns VBox status code.
477 * @param pVM The VM to operate on.
478 * @param pVCpu The VM CPU to operate on.
479 * @param pVMCB SVM control block
480 * @param pCtx CPU Context
481 */
482static int SVMR0CheckPendingInterrupt(PVM pVM, PVMCPU pVCpu, SVM_VMCB *pVMCB, CPUMCTX *pCtx)
483{
484 int rc;
485
486 /* Dispatch any pending interrupts. (injected before, but a VM exit occurred prematurely) */
487 if (pVCpu->hwaccm.s.Event.fPending)
488 {
489 SVM_EVENT Event;
490
491 Log(("Reinjecting event %08x %08x at %RGv\n", pVCpu->hwaccm.s.Event.intInfo, pVCpu->hwaccm.s.Event.errCode, (RTGCPTR)pCtx->rip));
492 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatIntReinject);
493 Event.au64[0] = pVCpu->hwaccm.s.Event.intInfo;
494 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
495
496 pVCpu->hwaccm.s.Event.fPending = false;
497 return VINF_SUCCESS;
498 }
499
500 /* If an active trap is already pending, then we must forward it first! */
501 if (!TRPMHasTrap(pVCpu))
502 {
503 if (VMCPU_FF_TESTANDCLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI))
504 {
505 SVM_EVENT Event;
506
507 Log(("CPU%d: injecting #NMI\n", pVCpu->idCpu));
508 Event.n.u8Vector = X86_XCPT_NMI;
509 Event.n.u1Valid = 1;
510 Event.n.u32ErrorCode = 0;
511 Event.n.u3Type = SVM_EVENT_NMI;
512
513 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
514 return VINF_SUCCESS;
515 }
516
517 /* @todo SMI interrupts. */
518
519 /* When external interrupts are pending, we should exit the VM when IF is set. */
520 if (VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)))
521 {
522 if ( !(pCtx->eflags.u32 & X86_EFL_IF)
523 || VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
524 {
525 if (!pVMCB->ctrl.IntCtrl.n.u1VIrqValid)
526 {
527 if (!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
528 LogFlow(("Enable irq window exit!\n"));
529 else
530 Log(("Pending interrupt blocked at %RGv by VM_FF_INHIBIT_INTERRUPTS -> irq window exit\n", (RTGCPTR)pCtx->rip));
531
532 /** @todo use virtual interrupt method to inject a pending irq; dispatched as soon as guest.IF is set. */
533 pVMCB->ctrl.u32InterceptCtrl1 |= SVM_CTRL1_INTERCEPT_VINTR;
534 pVMCB->ctrl.IntCtrl.n.u1VIrqValid = 1;
535 pVMCB->ctrl.IntCtrl.n.u8VIrqVector = 0; /* don't care */
536 }
537 }
538 else
539 {
540 uint8_t u8Interrupt;
541
542 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
543 Log(("Dispatch interrupt: u8Interrupt=%x (%d) rc=%Rrc\n", u8Interrupt, u8Interrupt, rc));
544 if (RT_SUCCESS(rc))
545 {
546 rc = TRPMAssertTrap(pVCpu, u8Interrupt, TRPM_HARDWARE_INT);
547 AssertRC(rc);
548 }
549 else
550 {
551 /* Can only happen in rare cases where a pending interrupt is cleared behind our back */
552 Assert(!VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)));
553 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatSwitchGuestIrq);
554 /* Just continue */
555 }
556 }
557 }
558 }
559
560#ifdef VBOX_STRICT
561 if (TRPMHasTrap(pVCpu))
562 {
563 uint8_t u8Vector;
564 rc = TRPMQueryTrapAll(pVCpu, &u8Vector, 0, 0, 0);
565 AssertRC(rc);
566 }
567#endif
568
569 if ( (pCtx->eflags.u32 & X86_EFL_IF)
570 && (!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
571 && TRPMHasTrap(pVCpu)
572 )
573 {
574 uint8_t u8Vector;
575 TRPMEVENT enmType;
576 SVM_EVENT Event;
577 RTGCUINT u32ErrorCode;
578
579 Event.au64[0] = 0;
580
581 /* If a new event is pending, then dispatch it now. */
582 rc = TRPMQueryTrapAll(pVCpu, &u8Vector, &enmType, &u32ErrorCode, 0);
583 AssertRC(rc);
584 Assert(pCtx->eflags.Bits.u1IF == 1 || enmType == TRPM_TRAP);
585 Assert(enmType != TRPM_SOFTWARE_INT);
586
587 /* Clear the pending trap. */
588 rc = TRPMResetTrap(pVCpu);
589 AssertRC(rc);
590
591 Event.n.u8Vector = u8Vector;
592 Event.n.u1Valid = 1;
593 Event.n.u32ErrorCode = u32ErrorCode;
594
595 if (enmType == TRPM_TRAP)
596 {
597 switch (u8Vector) {
598 case 8:
599 case 10:
600 case 11:
601 case 12:
602 case 13:
603 case 14:
604 case 17:
605 /* Valid error codes. */
606 Event.n.u1ErrorCodeValid = 1;
607 break;
608 default:
609 break;
610 }
611 if (u8Vector == X86_XCPT_NMI)
612 Event.n.u3Type = SVM_EVENT_NMI;
613 else
614 Event.n.u3Type = SVM_EVENT_EXCEPTION;
615 }
616 else
617 Event.n.u3Type = SVM_EVENT_EXTERNAL_IRQ;
618
619 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatIntInject);
620 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
621 } /* if (interrupts can be dispatched) */
622
623 return VINF_SUCCESS;
624}
625
626/**
627 * Save the host state
628 *
629 * @returns VBox status code.
630 * @param pVM The VM to operate on.
631 * @param pVCpu The VM CPU to operate on.
632 */
633VMMR0DECL(int) SVMR0SaveHostState(PVM pVM, PVMCPU pVCpu)
634{
635 NOREF(pVM);
636 NOREF(pVCpu);
637 /* Nothing to do here. */
638 return VINF_SUCCESS;
639}
640
641/**
642 * Loads the guest state
643 *
644 * NOTE: Don't do anything here that can cause a jump back to ring 3!!!!!
645 *
646 * @returns VBox status code.
647 * @param pVM The VM to operate on.
648 * @param pVCpu The VM CPU to operate on.
649 * @param pCtx Guest context
650 */
651VMMR0DECL(int) SVMR0LoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
652{
653 RTGCUINTPTR val;
654 SVM_VMCB *pVMCB;
655
656 if (pVM == NULL)
657 return VERR_INVALID_PARAMETER;
658
659 /* Setup AMD SVM. */
660 Assert(pVM->hwaccm.s.svm.fSupported);
661
662 pVMCB = (SVM_VMCB *)pVCpu->hwaccm.s.svm.pVMCB;
663 AssertMsgReturn(pVMCB, ("Invalid pVMCB\n"), VERR_EM_INTERNAL_ERROR);
664
665 /* Guest CPU context: ES, CS, SS, DS, FS, GS. */
666 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_SEGMENT_REGS)
667 {
668 SVM_WRITE_SELREG(CS, cs);
669 SVM_WRITE_SELREG(SS, ss);
670 SVM_WRITE_SELREG(DS, ds);
671 SVM_WRITE_SELREG(ES, es);
672 SVM_WRITE_SELREG(FS, fs);
673 SVM_WRITE_SELREG(GS, gs);
674 }
675
676 /* Guest CPU context: LDTR. */
677 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_LDTR)
678 {
679 SVM_WRITE_SELREG(LDTR, ldtr);
680 }
681
682 /* Guest CPU context: TR. */
683 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_TR)
684 {
685 SVM_WRITE_SELREG(TR, tr);
686 }
687
688 /* Guest CPU context: GDTR. */
689 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_GDTR)
690 {
691 pVMCB->guest.GDTR.u32Limit = pCtx->gdtr.cbGdt;
692 pVMCB->guest.GDTR.u64Base = pCtx->gdtr.pGdt;
693 }
694
695 /* Guest CPU context: IDTR. */
696 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_IDTR)
697 {
698 pVMCB->guest.IDTR.u32Limit = pCtx->idtr.cbIdt;
699 pVMCB->guest.IDTR.u64Base = pCtx->idtr.pIdt;
700 }
701
702 /*
703 * Sysenter MSRs (unconditional)
704 */
705 pVMCB->guest.u64SysEnterCS = pCtx->SysEnter.cs;
706 pVMCB->guest.u64SysEnterEIP = pCtx->SysEnter.eip;
707 pVMCB->guest.u64SysEnterESP = pCtx->SysEnter.esp;
708
709 /* Control registers */
710 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR0)
711 {
712 val = pCtx->cr0;
713 if (!CPUMIsGuestFPUStateActive(pVCpu))
714 {
715 /* Always use #NM exceptions to load the FPU/XMM state on demand. */
716 val |= X86_CR0_TS | X86_CR0_ET | X86_CR0_NE | X86_CR0_MP;
717 }
718 else
719 {
720 /** @todo check if we support the old style mess correctly. */
721 if (!(val & X86_CR0_NE))
722 {
723 Log(("Forcing X86_CR0_NE!!!\n"));
724
725 /* Also catch floating point exceptions as we need to report them to the guest in a different way. */
726 if (!pVCpu->hwaccm.s.fFPUOldStyleOverride)
727 {
728 pVMCB->ctrl.u32InterceptException |= RT_BIT(X86_XCPT_MF);
729 pVCpu->hwaccm.s.fFPUOldStyleOverride = true;
730 }
731 }
732 val |= X86_CR0_NE; /* always turn on the native mechanism to report FPU errors (old style uses interrupts) */
733 }
734 /* Always enable caching. */
735 val &= ~(X86_CR0_CD|X86_CR0_NW);
736
737 /* Note: WP is not relevant in nested paging mode as we catch accesses on the (guest) physical level. */
738 /* Note: In nested paging mode the guest is allowed to run with paging disabled; the guest physical to host physical translation will remain active. */
739 if (!pVM->hwaccm.s.fNestedPaging)
740 {
741 val |= X86_CR0_PG; /* Paging is always enabled; even when the guest is running in real mode or PE without paging. */
742 val |= X86_CR0_WP; /* Must set this as we rely on protect various pages and supervisor writes must be caught. */
743 }
744 pVMCB->guest.u64CR0 = val;
745 }
746 /* CR2 as well */
747 pVMCB->guest.u64CR2 = pCtx->cr2;
748
749 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR3)
750 {
751 /* Save our shadow CR3 register. */
752 if (pVM->hwaccm.s.fNestedPaging)
753 {
754 PGMMODE enmShwPagingMode;
755
756#if HC_ARCH_BITS == 32
757 if (CPUMIsGuestInLongModeEx(pCtx))
758 enmShwPagingMode = PGMMODE_AMD64_NX;
759 else
760#endif
761 enmShwPagingMode = PGMGetHostMode(pVM);
762
763 pVMCB->ctrl.u64NestedPagingCR3 = PGMGetNestedCR3(pVCpu, enmShwPagingMode);
764 Assert(pVMCB->ctrl.u64NestedPagingCR3);
765 pVMCB->guest.u64CR3 = pCtx->cr3;
766 }
767 else
768 {
769 pVMCB->guest.u64CR3 = PGMGetHyperCR3(pVCpu);
770 Assert(pVMCB->guest.u64CR3 || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL));
771 }
772 }
773
774 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR4)
775 {
776 val = pCtx->cr4;
777 if (!pVM->hwaccm.s.fNestedPaging)
778 {
779 switch(pVCpu->hwaccm.s.enmShadowMode)
780 {
781 case PGMMODE_REAL:
782 case PGMMODE_PROTECTED: /* Protected mode, no paging. */
783 AssertFailed();
784 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
785
786 case PGMMODE_32_BIT: /* 32-bit paging. */
787 val &= ~X86_CR4_PAE;
788 break;
789
790 case PGMMODE_PAE: /* PAE paging. */
791 case PGMMODE_PAE_NX: /* PAE paging with NX enabled. */
792 /** @todo use normal 32 bits paging */
793 val |= X86_CR4_PAE;
794 break;
795
796 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
797 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
798#ifdef VBOX_ENABLE_64_BITS_GUESTS
799 break;
800#else
801 AssertFailed();
802 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
803#endif
804
805 default: /* shut up gcc */
806 AssertFailed();
807 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
808 }
809 }
810 pVMCB->guest.u64CR4 = val;
811 }
812
813 /* Debug registers. */
814 if (pVCpu->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_DEBUG)
815 {
816 pCtx->dr[6] |= X86_DR6_INIT_VAL; /* set all reserved bits to 1. */
817 pCtx->dr[6] &= ~RT_BIT(12); /* must be zero. */
818
819 pCtx->dr[7] &= 0xffffffff; /* upper 32 bits reserved */
820 pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
821 pCtx->dr[7] |= 0x400; /* must be one */
822
823 pVMCB->guest.u64DR7 = pCtx->dr[7];
824 pVMCB->guest.u64DR6 = pCtx->dr[6];
825
826#ifdef DEBUG
827 /* Sync the hypervisor debug state now if any breakpoint is armed. */
828 if ( CPUMGetHyperDR7(pVCpu) & (X86_DR7_ENABLED_MASK|X86_DR7_GD)
829 && !CPUMIsHyperDebugStateActive(pVCpu)
830 && !DBGFIsStepping(pVCpu))
831 {
832 /* Save the host and load the hypervisor debug state. */
833 int rc = CPUMR0LoadHyperDebugState(pVM, pVCpu, pCtx, false /* exclude DR6 */);
834 AssertRC(rc);
835
836 /* DRx intercepts remain enabled. */
837
838 /* Override dr6 & dr7 with the hypervisor values. */
839 pVMCB->guest.u64DR7 = CPUMGetHyperDR7(pVCpu);
840 pVMCB->guest.u64DR6 = CPUMGetHyperDR6(pVCpu);
841 }
842 else
843#endif
844 /* Sync the debug state now if any breakpoint is armed. */
845 if ( (pCtx->dr[7] & (X86_DR7_ENABLED_MASK|X86_DR7_GD))
846 && !CPUMIsGuestDebugStateActive(pVCpu)
847 && !DBGFIsStepping(pVCpu))
848 {
849 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxArmed);
850
851 /* Disable drx move intercepts. */
852 pVMCB->ctrl.u16InterceptRdDRx = 0;
853 pVMCB->ctrl.u16InterceptWrDRx = 0;
854
855 /* Save the host and load the guest debug state. */
856 int rc = CPUMR0LoadGuestDebugState(pVM, pVCpu, pCtx, false /* exclude DR6 */);
857 AssertRC(rc);
858 }
859 }
860
861 /* EIP, ESP and EFLAGS */
862 pVMCB->guest.u64RIP = pCtx->rip;
863 pVMCB->guest.u64RSP = pCtx->rsp;
864 pVMCB->guest.u64RFlags = pCtx->eflags.u32;
865
866 /* Set CPL */
867 pVMCB->guest.u8CPL = pCtx->csHid.Attr.n.u2Dpl;
868
869 /* RAX/EAX too, as VMRUN uses RAX as an implicit parameter. */
870 pVMCB->guest.u64RAX = pCtx->rax;
871
872 /* vmrun will fail without MSR_K6_EFER_SVME. */
873 pVMCB->guest.u64EFER = pCtx->msrEFER | MSR_K6_EFER_SVME;
874
875 /* 64 bits guest mode? */
876 if (CPUMIsGuestInLongModeEx(pCtx))
877 {
878#if !defined(VBOX_ENABLE_64_BITS_GUESTS)
879 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
880#elif HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
881 pVCpu->hwaccm.s.svm.pfnVMRun = SVMR0VMSwitcherRun64;
882#else
883# ifdef VBOX_WITH_HYBRID_32BIT_KERNEL
884 if (!pVM->hwaccm.s.fAllow64BitGuests)
885 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
886# endif
887 pVCpu->hwaccm.s.svm.pfnVMRun = SVMR0VMRun64;
888#endif
889 /* Unconditionally update these as wrmsr might have changed them. (HWACCM_CHANGED_GUEST_SEGMENT_REGS will not be set) */
890 pVMCB->guest.FS.u64Base = pCtx->fsHid.u64Base;
891 pVMCB->guest.GS.u64Base = pCtx->gsHid.u64Base;
892 }
893 else
894 {
895 /* Filter out the MSR_K6_LME bit or else AMD-V expects amd64 shadow paging. */
896 pVMCB->guest.u64EFER &= ~MSR_K6_EFER_LME;
897
898 pVCpu->hwaccm.s.svm.pfnVMRun = SVMR0VMRun;
899 }
900
901 /* TSC offset. */
902 if (TMCpuTickCanUseRealTSC(pVCpu, &pVMCB->ctrl.u64TSCOffset))
903 {
904 uint64_t u64CurTSC = ASMReadTSC();
905 if (u64CurTSC + pVMCB->ctrl.u64TSCOffset >= TMCpuTickGetLastSeen(pVCpu))
906 {
907 pVMCB->ctrl.u32InterceptCtrl1 &= ~SVM_CTRL1_INTERCEPT_RDTSC;
908 pVMCB->ctrl.u32InterceptCtrl2 &= ~SVM_CTRL2_INTERCEPT_RDTSCP;
909 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTSCOffset);
910 }
911 else
912 {
913 /* Fall back to rdtsc emulation as we would otherwise pass decreasing tsc values to the guest. */
914 LogFlow(("TSC %RX64 offset %RX64 time=%RX64 last=%RX64 (diff=%RX64, virt_tsc=%RX64)\n", u64CurTSC, pVMCB->ctrl.u64TSCOffset, u64CurTSC + pVMCB->ctrl.u64TSCOffset, TMCpuTickGetLastSeen(pVCpu), TMCpuTickGetLastSeen(pVCpu) - u64CurTSC - pVMCB->ctrl.u64TSCOffset, TMCpuTickGet(pVCpu)));
915 pVMCB->ctrl.u32InterceptCtrl1 |= SVM_CTRL1_INTERCEPT_RDTSC;
916 pVMCB->ctrl.u32InterceptCtrl2 |= SVM_CTRL2_INTERCEPT_RDTSCP;
917 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTSCInterceptOverFlow);
918 }
919 }
920 else
921 {
922 pVMCB->ctrl.u32InterceptCtrl1 |= SVM_CTRL1_INTERCEPT_RDTSC;
923 pVMCB->ctrl.u32InterceptCtrl2 |= SVM_CTRL2_INTERCEPT_RDTSCP;
924 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTSCIntercept);
925 }
926
927 /* Sync the various msrs for 64 bits mode. */
928 pVMCB->guest.u64STAR = pCtx->msrSTAR; /* legacy syscall eip, cs & ss */
929 pVMCB->guest.u64LSTAR = pCtx->msrLSTAR; /* 64 bits mode syscall rip */
930 pVMCB->guest.u64CSTAR = pCtx->msrCSTAR; /* compatibility mode syscall rip */
931 pVMCB->guest.u64SFMASK = pCtx->msrSFMASK; /* syscall flag mask */
932 pVMCB->guest.u64KernelGSBase = pCtx->msrKERNELGSBASE; /* swapgs exchange value */
933
934#ifdef DEBUG
935 /* Intercept X86_XCPT_DB if stepping is enabled */
936 if ( DBGFIsStepping(pVCpu)
937 || CPUMIsHyperDebugStateActive(pVCpu))
938 pVMCB->ctrl.u32InterceptException |= RT_BIT(X86_XCPT_DB);
939 else
940 pVMCB->ctrl.u32InterceptException &= ~RT_BIT(X86_XCPT_DB);
941#endif
942
943 /* Done. */
944 pVCpu->hwaccm.s.fContextUseFlags &= ~HWACCM_CHANGED_ALL_GUEST;
945
946 return VINF_SUCCESS;
947}
948
949
950/**
951 * Runs guest code in an AMD-V VM.
952 *
953 * @returns VBox status code.
954 * @param pVM The VM to operate on.
955 * @param pVCpu The VM CPU to operate on.
956 * @param pCtx Guest context
957 */
958VMMR0DECL(int) SVMR0RunGuestCode(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
959{
960 int rc = VINF_SUCCESS;
961 uint64_t exitCode = (uint64_t)SVM_EXIT_INVALID;
962 SVM_VMCB *pVMCB;
963 bool fSyncTPR = false;
964 unsigned cResume = 0;
965 uint8_t u8LastTPR;
966 PHWACCM_CPUINFO pCpu = 0;
967 RTCCUINTREG uOldEFlags = ~(RTCCUINTREG)0;
968#ifdef VBOX_STRICT
969 RTCPUID idCpuCheck;
970#endif
971#ifdef VBOX_HIGH_RES_TIMERS_HACK_IN_RING0
972 uint64_t u64LastTime = RTTimeMilliTS();
973#endif
974
975 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatEntry, x);
976
977 pVMCB = (SVM_VMCB *)pVCpu->hwaccm.s.svm.pVMCB;
978 AssertMsgReturn(pVMCB, ("Invalid pVMCB\n"), VERR_EM_INTERNAL_ERROR);
979
980 /* We can jump to this point to resume execution after determining that a VM-exit is innocent.
981 */
982ResumeExecution:
983 Assert(!HWACCMR0SuspendPending());
984
985 /* Safety precaution; looping for too long here can have a very bad effect on the host */
986 if (RT_UNLIKELY(++cResume > pVM->hwaccm.s.cMaxResumeLoops))
987 {
988 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitMaxResume);
989 rc = VINF_EM_RAW_INTERRUPT;
990 goto end;
991 }
992
993 /* Check for irq inhibition due to instruction fusing (sti, mov ss). */
994 if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
995 {
996 Log(("VM_FF_INHIBIT_INTERRUPTS at %RGv successor %RGv\n", (RTGCPTR)pCtx->rip, EMGetInhibitInterruptsPC(pVCpu)));
997 if (pCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
998 {
999 /* Note: we intentionally don't clear VM_FF_INHIBIT_INTERRUPTS here.
1000 * Before we are able to execute this instruction in raw mode (iret to guest code) an external interrupt might
1001 * force a world switch again. Possibly allowing a guest interrupt to be dispatched in the process. This could
1002 * break the guest. Sounds very unlikely, but such timing sensitive problems are not as rare as you might think.
1003 */
1004 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
1005 /* Irq inhibition is no longer active; clear the corresponding SVM state. */
1006 pVMCB->ctrl.u64IntShadow = 0;
1007 }
1008 }
1009 else
1010 {
1011 /* Irq inhibition is no longer active; clear the corresponding SVM state. */
1012 pVMCB->ctrl.u64IntShadow = 0;
1013 }
1014
1015#ifdef VBOX_HIGH_RES_TIMERS_HACK_IN_RING0
1016 if (RT_UNLIKELY(cResume & 0xf) == 0)
1017 {
1018 uint64_t u64CurTime = RTTimeMilliTS();
1019
1020 if (RT_UNLIKELY(u64CurTime > u64LastTime))
1021 {
1022 u64LastTime = u64CurTime;
1023 TMTimerPollVoid(pVM, pVCpu);
1024 }
1025 }
1026#endif
1027
1028 /* Check for pending actions that force us to go back to ring 3. */
1029 if ( VM_FF_ISPENDING(pVM, VM_FF_HWACCM_TO_R3_MASK | VM_FF_REQUEST | VM_FF_PGM_POOL_FLUSH_PENDING)
1030 || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_HWACCM_TO_R3_MASK | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_REQUEST))
1031 {
1032 /* Check if a sync operation is pending. */
1033 if (VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
1034 {
1035 rc = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
1036 AssertRC(rc);
1037 if (rc != VINF_SUCCESS)
1038 {
1039 Log(("Pending pool sync is forcing us back to ring 3; rc=%d\n", rc));
1040 goto end;
1041 }
1042 }
1043
1044#ifdef DEBUG
1045 /* Intercept X86_XCPT_DB if stepping is enabled */
1046 if (!DBGFIsStepping(pVCpu))
1047#endif
1048 {
1049 if ( VM_FF_ISPENDING(pVM, VM_FF_HWACCM_TO_R3_MASK)
1050 || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_HWACCM_TO_R3_MASK))
1051 {
1052 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
1053 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatSwitchToR3);
1054 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatEntry, x);
1055 rc = RT_UNLIKELY(VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
1056 goto end;
1057 }
1058 }
1059
1060 /* Pending request packets might contain actions that need immediate attention, such as pending hardware interrupts. */
1061 if ( VM_FF_ISPENDING(pVM, VM_FF_REQUEST)
1062 || VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_REQUEST))
1063 {
1064 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatEntry, x);
1065 rc = VINF_EM_PENDING_REQUEST;
1066 goto end;
1067 }
1068
1069 /* Check if a pgm pool flush is in progress. */
1070 if (VM_FF_ISPENDING(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
1071 {
1072 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatEntry, x);
1073 rc = VINF_PGM_POOL_FLUSH_PENDING;
1074 goto end;
1075 }
1076 }
1077
1078#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
1079 /*
1080 * Exit to ring-3 preemption/work is pending.
1081 *
1082 * Interrupts are disabled before the call to make sure we don't miss any interrupt
1083 * that would flag preemption (IPI, timer tick, ++). (Would've been nice to do this
1084 * further down, but SVMR0CheckPendingInterrupt makes that impossible.)
1085 *
1086 * Note! Interrupts must be disabled done *before* we check for TLB flushes; TLB
1087 * shootdowns rely on this.
1088 */
1089 uOldEFlags = ASMIntDisableFlags();
1090 if (RTThreadPreemptIsPending(NIL_RTTHREAD))
1091 {
1092 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitPreemptPending);
1093 rc = VINF_EM_RAW_INTERRUPT;
1094 goto end;
1095 }
1096 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
1097#endif
1098
1099 /* When external interrupts are pending, we should exit the VM when IF is set. */
1100 /* Note! *After* VM_FF_INHIBIT_INTERRUPTS check!!! */
1101 rc = SVMR0CheckPendingInterrupt(pVM, pVCpu, pVMCB, pCtx);
1102 if (RT_FAILURE(rc))
1103 {
1104 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatEntry, x);
1105 goto end;
1106 }
1107
1108 /* TPR caching using CR8 is only available in 64 bits mode or with 32 bits guests when X86_CPUID_AMD_FEATURE_ECX_CR8L is supported. */
1109 /* Note: we can't do this in LoadGuestState as PDMApicGetTPR can jump back to ring 3 (lock)!!!!!!!! (no longer true)
1110 * @todo query and update the TPR only when it could have been changed (mmio access)
1111 */
1112 if (pVM->hwaccm.s.fHasIoApic)
1113 {
1114 bool fPending;
1115
1116 /* TPR caching in CR8 */
1117 int rc2 = PDMApicGetTPR(pVCpu, &u8LastTPR, &fPending);
1118 AssertRC(rc2);
1119
1120 if (pVM->hwaccm.s.fTPRPatchingActive)
1121 {
1122 /* Our patch code uses LSTAR for TPR caching. */
1123 pCtx->msrLSTAR = u8LastTPR;
1124
1125 if (fPending)
1126 {
1127 /* A TPR change could activate a pending interrupt, so catch lstar writes. */
1128 svmR0SetMSRPermission(pVCpu, MSR_K8_LSTAR, true, false);
1129 }
1130 else
1131 /* No interrupts are pending, so we don't need to be explicitely notified.
1132 * There are enough world switches for detecting pending interrupts.
1133 */
1134 svmR0SetMSRPermission(pVCpu, MSR_K8_LSTAR, true, true);
1135 }
1136 else
1137 {
1138 pVMCB->ctrl.IntCtrl.n.u8VTPR = (u8LastTPR >> 4); /* cr8 bits 3-0 correspond to bits 7-4 of the task priority mmio register. */
1139
1140 if (fPending)
1141 {
1142 /* A TPR change could activate a pending interrupt, so catch cr8 writes. */
1143 pVMCB->ctrl.u16InterceptWrCRx |= RT_BIT(8);
1144 }
1145 else
1146 /* No interrupts are pending, so we don't need to be explicitely notified.
1147 * There are enough world switches for detecting pending interrupts.
1148 */
1149 pVMCB->ctrl.u16InterceptWrCRx &= ~RT_BIT(8);
1150 }
1151 fSyncTPR = !fPending;
1152 }
1153
1154 /* All done! Let's start VM execution. */
1155 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatInGC, x);
1156
1157 /* Enable nested paging if necessary (disabled each time after #VMEXIT). */
1158 pVMCB->ctrl.NestedPaging.n.u1NestedPaging = pVM->hwaccm.s.fNestedPaging;
1159
1160#ifdef LOG_ENABLED
1161 pCpu = HWACCMR0GetCurrentCpu();
1162 if ( pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu
1163 || pVCpu->hwaccm.s.cTLBFlushes != pCpu->cTLBFlushes)
1164 {
1165 if (pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu)
1166 LogFlow(("Force TLB flush due to rescheduling to a different cpu (%d vs %d)\n", pVCpu->hwaccm.s.idLastCpu, pCpu->idCpu));
1167 else
1168 LogFlow(("Force TLB flush due to changed TLB flush count (%x vs %x)\n", pVCpu->hwaccm.s.cTLBFlushes, pCpu->cTLBFlushes));
1169 }
1170 if (pCpu->fFlushTLB)
1171 LogFlow(("Force TLB flush: first time cpu %d is used -> flush\n", pCpu->idCpu));
1172#endif
1173
1174 /*
1175 * NOTE: DO NOT DO ANYTHING AFTER THIS POINT THAT MIGHT JUMP BACK TO RING 3!
1176 * (until the actual world switch)
1177 */
1178#ifdef VBOX_STRICT
1179 idCpuCheck = RTMpCpuId();
1180#endif
1181 VMMR0LogFlushDisable(pVCpu);
1182
1183 /* Load the guest state; *must* be here as it sets up the shadow cr0 for lazy fpu syncing! */
1184 rc = SVMR0LoadGuestState(pVM, pVCpu, pCtx);
1185 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1186 {
1187 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatEntry, x);
1188 VMMR0LogFlushEnable(pVCpu);
1189 goto end;
1190 }
1191
1192#ifndef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
1193 /* Disable interrupts to make sure a poke will interrupt execution.
1194 * This must be done *before* we check for TLB flushes; TLB shootdowns rely on this.
1195 */
1196 uOldEFlags = ASMIntDisableFlags();
1197 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
1198#endif
1199
1200 pCpu = HWACCMR0GetCurrentCpu();
1201 /* Force a TLB flush for the first world switch if the current cpu differs from the one we ran on last. */
1202 /* Note that this can happen both for start and resume due to long jumps back to ring 3. */
1203 if ( pVCpu->hwaccm.s.idLastCpu != pCpu->idCpu
1204 /* if the tlb flush count has changed, another VM has flushed the TLB of this cpu, so we can't use our current ASID anymore. */
1205 || pVCpu->hwaccm.s.cTLBFlushes != pCpu->cTLBFlushes)
1206 {
1207 /* Force a TLB flush on VM entry. */
1208 pVCpu->hwaccm.s.fForceTLBFlush = true;
1209 }
1210 else
1211 Assert(!pCpu->fFlushTLB || pVM->hwaccm.s.svm.fAlwaysFlushTLB);
1212
1213 pVCpu->hwaccm.s.idLastCpu = pCpu->idCpu;
1214
1215 /** Set TLB flush state as checked until we return from the world switch. */
1216 ASMAtomicWriteU8(&pVCpu->hwaccm.s.fCheckedTLBFlush, true);
1217
1218 /* Check for tlb shootdown flushes. */
1219 if (VMCPU_FF_TESTANDCLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
1220 pVCpu->hwaccm.s.fForceTLBFlush = true;
1221
1222 /* Make sure we flush the TLB when required. Switch ASID to achieve the same thing, but without actually flushing the whole TLB (which is expensive). */
1223 if ( pVCpu->hwaccm.s.fForceTLBFlush
1224 && !pVM->hwaccm.s.svm.fAlwaysFlushTLB)
1225 {
1226 if ( ++pCpu->uCurrentASID >= pVM->hwaccm.s.uMaxASID
1227 || pCpu->fFlushTLB)
1228 {
1229 pCpu->fFlushTLB = false;
1230 pCpu->uCurrentASID = 1; /* start at 1; host uses 0 */
1231 pVMCB->ctrl.TLBCtrl.n.u1TLBFlush = 1; /* wrap around; flush TLB */
1232 pCpu->cTLBFlushes++;
1233 }
1234 else
1235 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushASID);
1236
1237 pVCpu->hwaccm.s.cTLBFlushes = pCpu->cTLBFlushes;
1238 pVCpu->hwaccm.s.uCurrentASID = pCpu->uCurrentASID;
1239 }
1240 else
1241 {
1242 Assert(!pCpu->fFlushTLB || pVM->hwaccm.s.svm.fAlwaysFlushTLB);
1243
1244 /* We never increase uCurrentASID in the fAlwaysFlushTLB (erratum 170) case. */
1245 if (!pCpu->uCurrentASID || !pVCpu->hwaccm.s.uCurrentASID)
1246 pVCpu->hwaccm.s.uCurrentASID = pCpu->uCurrentASID = 1;
1247
1248 Assert(!pVM->hwaccm.s.svm.fAlwaysFlushTLB || pVCpu->hwaccm.s.fForceTLBFlush);
1249 pVMCB->ctrl.TLBCtrl.n.u1TLBFlush = pVCpu->hwaccm.s.fForceTLBFlush;
1250
1251 if ( !pVM->hwaccm.s.svm.fAlwaysFlushTLB
1252 && VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_TLB_SHOOTDOWN))
1253 {
1254 /* Deal with pending TLB shootdown actions which were queued when we were not executing code. */
1255 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdown);
1256 for (unsigned i=0;i<pVCpu->hwaccm.s.TlbShootdown.cPages;i++)
1257 SVMR0InvlpgA(pVCpu->hwaccm.s.TlbShootdown.aPages[i], pVMCB->ctrl.TLBCtrl.n.u32ASID);
1258 }
1259 }
1260 pVCpu->hwaccm.s.TlbShootdown.cPages = 0;
1261 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
1262
1263 AssertMsg(pVCpu->hwaccm.s.cTLBFlushes == pCpu->cTLBFlushes, ("Flush count mismatch for cpu %d (%x vs %x)\n", pCpu->idCpu, pVCpu->hwaccm.s.cTLBFlushes, pCpu->cTLBFlushes));
1264 AssertMsg(pCpu->uCurrentASID >= 1 && pCpu->uCurrentASID < pVM->hwaccm.s.uMaxASID, ("cpu%d uCurrentASID = %x\n", pCpu->idCpu, pCpu->uCurrentASID));
1265 AssertMsg(pVCpu->hwaccm.s.uCurrentASID >= 1 && pVCpu->hwaccm.s.uCurrentASID < pVM->hwaccm.s.uMaxASID, ("cpu%d VM uCurrentASID = %x\n", pCpu->idCpu, pVCpu->hwaccm.s.uCurrentASID));
1266 pVMCB->ctrl.TLBCtrl.n.u32ASID = pVCpu->hwaccm.s.uCurrentASID;
1267
1268#ifdef VBOX_WITH_STATISTICS
1269 if (pVMCB->ctrl.TLBCtrl.n.u1TLBFlush)
1270 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushTLBWorldSwitch);
1271 else
1272 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatNoFlushTLBWorldSwitch);
1273#endif
1274
1275 /* In case we execute a goto ResumeExecution later on. */
1276 pVCpu->hwaccm.s.fResumeVM = true;
1277 pVCpu->hwaccm.s.fForceTLBFlush = pVM->hwaccm.s.svm.fAlwaysFlushTLB;
1278
1279 Assert(sizeof(pVCpu->hwaccm.s.svm.pVMCBPhys) == 8);
1280 Assert(pVMCB->ctrl.IntCtrl.n.u1VIrqMasking);
1281 Assert(pVMCB->ctrl.u64IOPMPhysAddr == pVM->hwaccm.s.svm.pIOBitmapPhys);
1282 Assert(pVMCB->ctrl.u64MSRPMPhysAddr == pVCpu->hwaccm.s.svm.pMSRBitmapPhys);
1283 Assert(pVMCB->ctrl.u64LBRVirt == 0);
1284
1285#ifdef VBOX_STRICT
1286 Assert(idCpuCheck == RTMpCpuId());
1287#endif
1288 TMNotifyStartOfExecution(pVCpu);
1289#ifdef VBOX_WITH_KERNEL_USING_XMM
1290 hwaccmR0SVMRunWrapXMM(pVCpu->hwaccm.s.svm.pVMCBHostPhys, pVCpu->hwaccm.s.svm.pVMCBPhys, pCtx, pVM, pVCpu, pVCpu->hwaccm.s.svm.pfnVMRun);
1291#else
1292 pVCpu->hwaccm.s.svm.pfnVMRun(pVCpu->hwaccm.s.svm.pVMCBHostPhys, pVCpu->hwaccm.s.svm.pVMCBPhys, pCtx, pVM, pVCpu);
1293#endif
1294 ASMAtomicWriteU8(&pVCpu->hwaccm.s.fCheckedTLBFlush, false);
1295 ASMAtomicIncU32(&pVCpu->hwaccm.s.cWorldSwitchExit);
1296 /* Possibly the last TSC value seen by the guest (too high) (only when we're in tsc offset mode). */
1297 if (!(pVMCB->ctrl.u32InterceptCtrl1 & SVM_CTRL1_INTERCEPT_RDTSC))
1298 TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVMCB->ctrl.u64TSCOffset - 0x400 /* guestimate of world switch overhead in clock ticks */);
1299 TMNotifyEndOfExecution(pVCpu);
1300 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
1301 ASMSetFlags(uOldEFlags);
1302#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
1303 uOldEFlags = ~(RTCCUINTREG)0;
1304#endif
1305 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatInGC, x);
1306
1307 /*
1308 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1309 * 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
1310 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1311 */
1312
1313 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatExit1, x);
1314
1315 /* Reason for the VM exit */
1316 exitCode = pVMCB->ctrl.u64ExitCode;
1317
1318 if (RT_UNLIKELY(exitCode == (uint64_t)SVM_EXIT_INVALID)) /* Invalid guest state. */
1319 {
1320 HWACCMDumpRegs(pVM, pVCpu, pCtx);
1321#ifdef DEBUG
1322 Log(("ctrl.u16InterceptRdCRx %x\n", pVMCB->ctrl.u16InterceptRdCRx));
1323 Log(("ctrl.u16InterceptWrCRx %x\n", pVMCB->ctrl.u16InterceptWrCRx));
1324 Log(("ctrl.u16InterceptRdDRx %x\n", pVMCB->ctrl.u16InterceptRdDRx));
1325 Log(("ctrl.u16InterceptWrDRx %x\n", pVMCB->ctrl.u16InterceptWrDRx));
1326 Log(("ctrl.u32InterceptException %x\n", pVMCB->ctrl.u32InterceptException));
1327 Log(("ctrl.u32InterceptCtrl1 %x\n", pVMCB->ctrl.u32InterceptCtrl1));
1328 Log(("ctrl.u32InterceptCtrl2 %x\n", pVMCB->ctrl.u32InterceptCtrl2));
1329 Log(("ctrl.u64IOPMPhysAddr %RX64\n", pVMCB->ctrl.u64IOPMPhysAddr));
1330 Log(("ctrl.u64MSRPMPhysAddr %RX64\n", pVMCB->ctrl.u64MSRPMPhysAddr));
1331 Log(("ctrl.u64TSCOffset %RX64\n", pVMCB->ctrl.u64TSCOffset));
1332
1333 Log(("ctrl.TLBCtrl.u32ASID %x\n", pVMCB->ctrl.TLBCtrl.n.u32ASID));
1334 Log(("ctrl.TLBCtrl.u1TLBFlush %x\n", pVMCB->ctrl.TLBCtrl.n.u1TLBFlush));
1335 Log(("ctrl.TLBCtrl.u7Reserved %x\n", pVMCB->ctrl.TLBCtrl.n.u7Reserved));
1336 Log(("ctrl.TLBCtrl.u24Reserved %x\n", pVMCB->ctrl.TLBCtrl.n.u24Reserved));
1337
1338 Log(("ctrl.IntCtrl.u8VTPR %x\n", pVMCB->ctrl.IntCtrl.n.u8VTPR));
1339 Log(("ctrl.IntCtrl.u1VIrqValid %x\n", pVMCB->ctrl.IntCtrl.n.u1VIrqValid));
1340 Log(("ctrl.IntCtrl.u7Reserved %x\n", pVMCB->ctrl.IntCtrl.n.u7Reserved));
1341 Log(("ctrl.IntCtrl.u4VIrqPriority %x\n", pVMCB->ctrl.IntCtrl.n.u4VIrqPriority));
1342 Log(("ctrl.IntCtrl.u1IgnoreTPR %x\n", pVMCB->ctrl.IntCtrl.n.u1IgnoreTPR));
1343 Log(("ctrl.IntCtrl.u3Reserved %x\n", pVMCB->ctrl.IntCtrl.n.u3Reserved));
1344 Log(("ctrl.IntCtrl.u1VIrqMasking %x\n", pVMCB->ctrl.IntCtrl.n.u1VIrqMasking));
1345 Log(("ctrl.IntCtrl.u7Reserved2 %x\n", pVMCB->ctrl.IntCtrl.n.u7Reserved2));
1346 Log(("ctrl.IntCtrl.u8VIrqVector %x\n", pVMCB->ctrl.IntCtrl.n.u8VIrqVector));
1347 Log(("ctrl.IntCtrl.u24Reserved %x\n", pVMCB->ctrl.IntCtrl.n.u24Reserved));
1348
1349 Log(("ctrl.u64IntShadow %RX64\n", pVMCB->ctrl.u64IntShadow));
1350 Log(("ctrl.u64ExitCode %RX64\n", pVMCB->ctrl.u64ExitCode));
1351 Log(("ctrl.u64ExitInfo1 %RX64\n", pVMCB->ctrl.u64ExitInfo1));
1352 Log(("ctrl.u64ExitInfo2 %RX64\n", pVMCB->ctrl.u64ExitInfo2));
1353 Log(("ctrl.ExitIntInfo.u8Vector %x\n", pVMCB->ctrl.ExitIntInfo.n.u8Vector));
1354 Log(("ctrl.ExitIntInfo.u3Type %x\n", pVMCB->ctrl.ExitIntInfo.n.u3Type));
1355 Log(("ctrl.ExitIntInfo.u1ErrorCodeValid %x\n", pVMCB->ctrl.ExitIntInfo.n.u1ErrorCodeValid));
1356 Log(("ctrl.ExitIntInfo.u19Reserved %x\n", pVMCB->ctrl.ExitIntInfo.n.u19Reserved));
1357 Log(("ctrl.ExitIntInfo.u1Valid %x\n", pVMCB->ctrl.ExitIntInfo.n.u1Valid));
1358 Log(("ctrl.ExitIntInfo.u32ErrorCode %x\n", pVMCB->ctrl.ExitIntInfo.n.u32ErrorCode));
1359 Log(("ctrl.NestedPaging %RX64\n", pVMCB->ctrl.NestedPaging.au64));
1360 Log(("ctrl.EventInject.u8Vector %x\n", pVMCB->ctrl.EventInject.n.u8Vector));
1361 Log(("ctrl.EventInject.u3Type %x\n", pVMCB->ctrl.EventInject.n.u3Type));
1362 Log(("ctrl.EventInject.u1ErrorCodeValid %x\n", pVMCB->ctrl.EventInject.n.u1ErrorCodeValid));
1363 Log(("ctrl.EventInject.u19Reserved %x\n", pVMCB->ctrl.EventInject.n.u19Reserved));
1364 Log(("ctrl.EventInject.u1Valid %x\n", pVMCB->ctrl.EventInject.n.u1Valid));
1365 Log(("ctrl.EventInject.u32ErrorCode %x\n", pVMCB->ctrl.EventInject.n.u32ErrorCode));
1366
1367 Log(("ctrl.u64NestedPagingCR3 %RX64\n", pVMCB->ctrl.u64NestedPagingCR3));
1368 Log(("ctrl.u64LBRVirt %RX64\n", pVMCB->ctrl.u64LBRVirt));
1369
1370 Log(("guest.CS.u16Sel %04X\n", pVMCB->guest.CS.u16Sel));
1371 Log(("guest.CS.u16Attr %04X\n", pVMCB->guest.CS.u16Attr));
1372 Log(("guest.CS.u32Limit %X\n", pVMCB->guest.CS.u32Limit));
1373 Log(("guest.CS.u64Base %RX64\n", pVMCB->guest.CS.u64Base));
1374 Log(("guest.DS.u16Sel %04X\n", pVMCB->guest.DS.u16Sel));
1375 Log(("guest.DS.u16Attr %04X\n", pVMCB->guest.DS.u16Attr));
1376 Log(("guest.DS.u32Limit %X\n", pVMCB->guest.DS.u32Limit));
1377 Log(("guest.DS.u64Base %RX64\n", pVMCB->guest.DS.u64Base));
1378 Log(("guest.ES.u16Sel %04X\n", pVMCB->guest.ES.u16Sel));
1379 Log(("guest.ES.u16Attr %04X\n", pVMCB->guest.ES.u16Attr));
1380 Log(("guest.ES.u32Limit %X\n", pVMCB->guest.ES.u32Limit));
1381 Log(("guest.ES.u64Base %RX64\n", pVMCB->guest.ES.u64Base));
1382 Log(("guest.FS.u16Sel %04X\n", pVMCB->guest.FS.u16Sel));
1383 Log(("guest.FS.u16Attr %04X\n", pVMCB->guest.FS.u16Attr));
1384 Log(("guest.FS.u32Limit %X\n", pVMCB->guest.FS.u32Limit));
1385 Log(("guest.FS.u64Base %RX64\n", pVMCB->guest.FS.u64Base));
1386 Log(("guest.GS.u16Sel %04X\n", pVMCB->guest.GS.u16Sel));
1387 Log(("guest.GS.u16Attr %04X\n", pVMCB->guest.GS.u16Attr));
1388 Log(("guest.GS.u32Limit %X\n", pVMCB->guest.GS.u32Limit));
1389 Log(("guest.GS.u64Base %RX64\n", pVMCB->guest.GS.u64Base));
1390
1391 Log(("guest.GDTR.u32Limit %X\n", pVMCB->guest.GDTR.u32Limit));
1392 Log(("guest.GDTR.u64Base %RX64\n", pVMCB->guest.GDTR.u64Base));
1393
1394 Log(("guest.LDTR.u16Sel %04X\n", pVMCB->guest.LDTR.u16Sel));
1395 Log(("guest.LDTR.u16Attr %04X\n", pVMCB->guest.LDTR.u16Attr));
1396 Log(("guest.LDTR.u32Limit %X\n", pVMCB->guest.LDTR.u32Limit));
1397 Log(("guest.LDTR.u64Base %RX64\n", pVMCB->guest.LDTR.u64Base));
1398
1399 Log(("guest.IDTR.u32Limit %X\n", pVMCB->guest.IDTR.u32Limit));
1400 Log(("guest.IDTR.u64Base %RX64\n", pVMCB->guest.IDTR.u64Base));
1401
1402 Log(("guest.TR.u16Sel %04X\n", pVMCB->guest.TR.u16Sel));
1403 Log(("guest.TR.u16Attr %04X\n", pVMCB->guest.TR.u16Attr));
1404 Log(("guest.TR.u32Limit %X\n", pVMCB->guest.TR.u32Limit));
1405 Log(("guest.TR.u64Base %RX64\n", pVMCB->guest.TR.u64Base));
1406
1407 Log(("guest.u8CPL %X\n", pVMCB->guest.u8CPL));
1408 Log(("guest.u64CR0 %RX64\n", pVMCB->guest.u64CR0));
1409 Log(("guest.u64CR2 %RX64\n", pVMCB->guest.u64CR2));
1410 Log(("guest.u64CR3 %RX64\n", pVMCB->guest.u64CR3));
1411 Log(("guest.u64CR4 %RX64\n", pVMCB->guest.u64CR4));
1412 Log(("guest.u64DR6 %RX64\n", pVMCB->guest.u64DR6));
1413 Log(("guest.u64DR7 %RX64\n", pVMCB->guest.u64DR7));
1414
1415 Log(("guest.u64RIP %RX64\n", pVMCB->guest.u64RIP));
1416 Log(("guest.u64RSP %RX64\n", pVMCB->guest.u64RSP));
1417 Log(("guest.u64RAX %RX64\n", pVMCB->guest.u64RAX));
1418 Log(("guest.u64RFlags %RX64\n", pVMCB->guest.u64RFlags));
1419
1420 Log(("guest.u64SysEnterCS %RX64\n", pVMCB->guest.u64SysEnterCS));
1421 Log(("guest.u64SysEnterEIP %RX64\n", pVMCB->guest.u64SysEnterEIP));
1422 Log(("guest.u64SysEnterESP %RX64\n", pVMCB->guest.u64SysEnterESP));
1423
1424 Log(("guest.u64EFER %RX64\n", pVMCB->guest.u64EFER));
1425 Log(("guest.u64STAR %RX64\n", pVMCB->guest.u64STAR));
1426 Log(("guest.u64LSTAR %RX64\n", pVMCB->guest.u64LSTAR));
1427 Log(("guest.u64CSTAR %RX64\n", pVMCB->guest.u64CSTAR));
1428 Log(("guest.u64SFMASK %RX64\n", pVMCB->guest.u64SFMASK));
1429 Log(("guest.u64KernelGSBase %RX64\n", pVMCB->guest.u64KernelGSBase));
1430 Log(("guest.u64GPAT %RX64\n", pVMCB->guest.u64GPAT));
1431 Log(("guest.u64DBGCTL %RX64\n", pVMCB->guest.u64DBGCTL));
1432 Log(("guest.u64BR_FROM %RX64\n", pVMCB->guest.u64BR_FROM));
1433 Log(("guest.u64BR_TO %RX64\n", pVMCB->guest.u64BR_TO));
1434 Log(("guest.u64LASTEXCPFROM %RX64\n", pVMCB->guest.u64LASTEXCPFROM));
1435 Log(("guest.u64LASTEXCPTO %RX64\n", pVMCB->guest.u64LASTEXCPTO));
1436
1437#endif
1438 rc = VERR_SVM_UNABLE_TO_START_VM;
1439 VMMR0LogFlushEnable(pVCpu);
1440 goto end;
1441 }
1442
1443 /* Let's first sync back eip, esp, and eflags. */
1444 pCtx->rip = pVMCB->guest.u64RIP;
1445 pCtx->rsp = pVMCB->guest.u64RSP;
1446 pCtx->eflags.u32 = pVMCB->guest.u64RFlags;
1447 /* eax is saved/restore across the vmrun instruction */
1448 pCtx->rax = pVMCB->guest.u64RAX;
1449
1450 /* Save all the MSRs that can be changed by the guest without causing a world switch. (fs & gs base are saved with SVM_READ_SELREG) */
1451 pCtx->msrSTAR = pVMCB->guest.u64STAR; /* legacy syscall eip, cs & ss */
1452 pCtx->msrLSTAR = pVMCB->guest.u64LSTAR; /* 64 bits mode syscall rip */
1453 pCtx->msrCSTAR = pVMCB->guest.u64CSTAR; /* compatibility mode syscall rip */
1454 pCtx->msrSFMASK = pVMCB->guest.u64SFMASK; /* syscall flag mask */
1455 pCtx->msrKERNELGSBASE = pVMCB->guest.u64KernelGSBase; /* swapgs exchange value */
1456 pCtx->SysEnter.cs = pVMCB->guest.u64SysEnterCS;
1457 pCtx->SysEnter.eip = pVMCB->guest.u64SysEnterEIP;
1458 pCtx->SysEnter.esp = pVMCB->guest.u64SysEnterESP;
1459
1460 /* Can be updated behind our back in the nested paging case. */
1461 pCtx->cr2 = pVMCB->guest.u64CR2;
1462
1463 /* Guest CPU context: ES, CS, SS, DS, FS, GS. */
1464 SVM_READ_SELREG(SS, ss);
1465 SVM_READ_SELREG(CS, cs);
1466 SVM_READ_SELREG(DS, ds);
1467 SVM_READ_SELREG(ES, es);
1468 SVM_READ_SELREG(FS, fs);
1469 SVM_READ_SELREG(GS, gs);
1470
1471 /* Correct the hidden CS granularity flag. Haven't seen it being wrong in
1472 any other register (yet). */
1473 if ( !pCtx->csHid.Attr.n.u1Granularity
1474 && pCtx->csHid.Attr.n.u1Present
1475 && pCtx->csHid.u32Limit > UINT32_C(0xfffff))
1476 {
1477 Assert((pCtx->csHid.u32Limit & 0xfff) == 0xfff);
1478 pCtx->csHid.Attr.n.u1Granularity = 1;
1479 }
1480#define SVM_ASSERT_SEL_GRANULARITY(reg) \
1481 AssertMsg( !pCtx->reg##Hid.Attr.n.u1Present \
1482 || ( pCtx->reg##Hid.Attr.n.u1Granularity \
1483 ? (pCtx->reg##Hid.u32Limit & 0xfff) == 0xfff \
1484 : pCtx->reg##Hid.u32Limit <= 0xfffff), \
1485 ("%#x %#x %#llx\n", pCtx->reg##Hid.u32Limit, pCtx->reg##Hid.Attr.u, pCtx->reg##Hid.u64Base))
1486 SVM_ASSERT_SEL_GRANULARITY(ss);
1487 SVM_ASSERT_SEL_GRANULARITY(cs);
1488 SVM_ASSERT_SEL_GRANULARITY(ds);
1489 SVM_ASSERT_SEL_GRANULARITY(es);
1490 SVM_ASSERT_SEL_GRANULARITY(fs);
1491 SVM_ASSERT_SEL_GRANULARITY(gs);
1492#undef SVM_ASSERT_SEL_GRANULARITY
1493
1494 /* Remaining guest CPU context: TR, IDTR, GDTR, LDTR; must sync everything otherwise we can get out of sync when jumping to ring 3. */
1495 SVM_READ_SELREG(LDTR, ldtr);
1496 SVM_READ_SELREG(TR, tr);
1497
1498 pCtx->gdtr.cbGdt = pVMCB->guest.GDTR.u32Limit;
1499 pCtx->gdtr.pGdt = pVMCB->guest.GDTR.u64Base;
1500
1501 pCtx->idtr.cbIdt = pVMCB->guest.IDTR.u32Limit;
1502 pCtx->idtr.pIdt = pVMCB->guest.IDTR.u64Base;
1503
1504 /* Note: no reason to sync back the CRx and DRx registers. They can't be changed by the guest. */
1505 /* Note: only in the nested paging case can CR3 & CR4 be changed by the guest. */
1506 if ( pVM->hwaccm.s.fNestedPaging
1507 && pCtx->cr3 != pVMCB->guest.u64CR3)
1508 {
1509 CPUMSetGuestCR3(pVCpu, pVMCB->guest.u64CR3);
1510 PGMUpdateCR3(pVCpu, pVMCB->guest.u64CR3);
1511 }
1512
1513 /* Note! NOW IT'S SAFE FOR LOGGING! */
1514 VMMR0LogFlushEnable(pVCpu);
1515
1516 /* Take care of instruction fusing (sti, mov ss) (see 15.20.5 Interrupt Shadows) */
1517 if (pVMCB->ctrl.u64IntShadow & SVM_INTERRUPT_SHADOW_ACTIVE)
1518 {
1519 Log(("uInterruptState %x rip=%RGv\n", pVMCB->ctrl.u64IntShadow, (RTGCPTR)pCtx->rip));
1520 EMSetInhibitInterruptsPC(pVCpu, pCtx->rip);
1521 }
1522 else
1523 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
1524
1525 Log2(("exitCode = %x\n", exitCode));
1526
1527 /* Sync back DR6 as it could have been changed by hitting breakpoints. */
1528 pCtx->dr[6] = pVMCB->guest.u64DR6;
1529 /* DR7.GD can be cleared by debug exceptions, so sync it back as well. */
1530 pCtx->dr[7] = pVMCB->guest.u64DR7;
1531
1532 /* Check if an injected event was interrupted prematurely. */
1533 pVCpu->hwaccm.s.Event.intInfo = pVMCB->ctrl.ExitIntInfo.au64[0];
1534 if ( pVMCB->ctrl.ExitIntInfo.n.u1Valid
1535 && pVMCB->ctrl.ExitIntInfo.n.u3Type != SVM_EVENT_SOFTWARE_INT /* we don't care about 'int xx' as the instruction will be restarted. */)
1536 {
1537 Log(("Pending inject %RX64 at %RGv exit=%08x\n", pVCpu->hwaccm.s.Event.intInfo, (RTGCPTR)pCtx->rip, exitCode));
1538
1539#ifdef LOG_ENABLED
1540 SVM_EVENT Event;
1541 Event.au64[0] = pVCpu->hwaccm.s.Event.intInfo;
1542
1543 if ( exitCode == SVM_EXIT_EXCEPTION_E
1544 && Event.n.u8Vector == 0xE)
1545 {
1546 Log(("Double fault!\n"));
1547 }
1548#endif
1549
1550 pVCpu->hwaccm.s.Event.fPending = true;
1551 /* Error code present? (redundant) */
1552 if (pVMCB->ctrl.ExitIntInfo.n.u1ErrorCodeValid)
1553 pVCpu->hwaccm.s.Event.errCode = pVMCB->ctrl.ExitIntInfo.n.u32ErrorCode;
1554 else
1555 pVCpu->hwaccm.s.Event.errCode = 0;
1556 }
1557#ifdef VBOX_WITH_STATISTICS
1558 if (exitCode == SVM_EXIT_NPF)
1559 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitReasonNPF);
1560 else
1561 STAM_COUNTER_INC(&pVCpu->hwaccm.s.paStatExitReasonR0[exitCode & MASK_EXITREASON_STAT]);
1562#endif
1563
1564 /* Sync back the TPR if it was changed. */
1565 if (fSyncTPR)
1566 {
1567 if (pVM->hwaccm.s.fTPRPatchingActive)
1568 {
1569 if ((pCtx->msrLSTAR & 0xff) != u8LastTPR)
1570 {
1571 /* Our patch code uses LSTAR for TPR caching. */
1572 rc = PDMApicSetTPR(pVCpu, pCtx->msrLSTAR & 0xff);
1573 AssertRC(rc);
1574 }
1575 }
1576 else
1577 {
1578 if ((u8LastTPR >> 4) != pVMCB->ctrl.IntCtrl.n.u8VTPR)
1579 {
1580 rc = PDMApicSetTPR(pVCpu, pVMCB->ctrl.IntCtrl.n.u8VTPR << 4); /* cr8 bits 3-0 correspond to bits 7-4 of the task priority mmio register. */
1581 AssertRC(rc);
1582 }
1583 }
1584 }
1585
1586 /* Deal with the reason of the VM-exit. */
1587 switch (exitCode)
1588 {
1589 case SVM_EXIT_EXCEPTION_0: case SVM_EXIT_EXCEPTION_1: case SVM_EXIT_EXCEPTION_2: case SVM_EXIT_EXCEPTION_3:
1590 case SVM_EXIT_EXCEPTION_4: case SVM_EXIT_EXCEPTION_5: case SVM_EXIT_EXCEPTION_6: case SVM_EXIT_EXCEPTION_7:
1591 case SVM_EXIT_EXCEPTION_8: case SVM_EXIT_EXCEPTION_9: case SVM_EXIT_EXCEPTION_A: case SVM_EXIT_EXCEPTION_B:
1592 case SVM_EXIT_EXCEPTION_C: case SVM_EXIT_EXCEPTION_D: case SVM_EXIT_EXCEPTION_E: case SVM_EXIT_EXCEPTION_F:
1593 case SVM_EXIT_EXCEPTION_10: case SVM_EXIT_EXCEPTION_11: case SVM_EXIT_EXCEPTION_12: case SVM_EXIT_EXCEPTION_13:
1594 case SVM_EXIT_EXCEPTION_14: case SVM_EXIT_EXCEPTION_15: case SVM_EXIT_EXCEPTION_16: case SVM_EXIT_EXCEPTION_17:
1595 case SVM_EXIT_EXCEPTION_18: case SVM_EXIT_EXCEPTION_19: case SVM_EXIT_EXCEPTION_1A: case SVM_EXIT_EXCEPTION_1B:
1596 case SVM_EXIT_EXCEPTION_1C: case SVM_EXIT_EXCEPTION_1D: case SVM_EXIT_EXCEPTION_1E: case SVM_EXIT_EXCEPTION_1F:
1597 {
1598 /* Pending trap. */
1599 SVM_EVENT Event;
1600 uint32_t vector = exitCode - SVM_EXIT_EXCEPTION_0;
1601
1602 Log2(("Hardware/software interrupt %d\n", vector));
1603 switch (vector)
1604 {
1605 case X86_XCPT_DB:
1606 {
1607 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestDB);
1608
1609 /* Note that we don't support guest and host-initiated debugging at the same time. */
1610 Assert(DBGFIsStepping(pVCpu) || CPUMIsHyperDebugStateActive(pVCpu));
1611
1612 rc = DBGFRZTrap01Handler(pVM, pVCpu, CPUMCTX2CORE(pCtx), pCtx->dr[6]);
1613 if (rc == VINF_EM_RAW_GUEST_TRAP)
1614 {
1615 Log(("Trap %x (debug) at %016RX64\n", vector, pCtx->rip));
1616
1617 /* Reinject the exception. */
1618 Event.au64[0] = 0;
1619 Event.n.u3Type = SVM_EVENT_EXCEPTION; /* trap or fault */
1620 Event.n.u1Valid = 1;
1621 Event.n.u8Vector = X86_XCPT_DB;
1622
1623 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
1624
1625 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1626 goto ResumeExecution;
1627 }
1628 /* Return to ring 3 to deal with the debug exit code. */
1629 Log(("Debugger hardware BP at %04x:%RGv (rc=%Rrc)\n", pCtx->cs, pCtx->rip, rc));
1630 break;
1631 }
1632
1633 case X86_XCPT_NM:
1634 {
1635 Log(("#NM fault at %RGv\n", (RTGCPTR)pCtx->rip));
1636
1637 /** @todo don't intercept #NM exceptions anymore when we've activated the guest FPU state. */
1638 /* If we sync the FPU/XMM state on-demand, then we can continue execution as if nothing has happened. */
1639 rc = CPUMR0LoadGuestFPU(pVM, pVCpu, pCtx);
1640 if (rc == VINF_SUCCESS)
1641 {
1642 Assert(CPUMIsGuestFPUStateActive(pVCpu));
1643 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitShadowNM);
1644
1645 /* Continue execution. */
1646 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1647 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
1648
1649 goto ResumeExecution;
1650 }
1651
1652 Log(("Forward #NM fault to the guest\n"));
1653 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestNM);
1654
1655 Event.au64[0] = 0;
1656 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1657 Event.n.u1Valid = 1;
1658 Event.n.u8Vector = X86_XCPT_NM;
1659
1660 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
1661 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1662 goto ResumeExecution;
1663 }
1664
1665 case X86_XCPT_PF: /* Page fault */
1666 {
1667 uint32_t errCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1668 RTGCUINTPTR uFaultAddress = pVMCB->ctrl.u64ExitInfo2; /* EXITINFO2 = fault address */
1669
1670#ifdef DEBUG
1671 if (pVM->hwaccm.s.fNestedPaging)
1672 { /* A genuine pagefault.
1673 * Forward the trap to the guest by injecting the exception and resuming execution.
1674 */
1675 Log(("Guest page fault at %04X:%RGv cr2=%RGv error code %x rsp=%RGv\n", pCtx->cs, (RTGCPTR)pCtx->rip, uFaultAddress, errCode, (RTGCPTR)pCtx->rsp));
1676 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestPF);
1677
1678 /* Now we must update CR2. */
1679 pCtx->cr2 = uFaultAddress;
1680
1681 Event.au64[0] = 0;
1682 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1683 Event.n.u1Valid = 1;
1684 Event.n.u8Vector = X86_XCPT_PF;
1685 Event.n.u1ErrorCodeValid = 1;
1686 Event.n.u32ErrorCode = errCode;
1687
1688 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
1689
1690 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1691 goto ResumeExecution;
1692 }
1693#endif
1694 Assert(!pVM->hwaccm.s.fNestedPaging);
1695
1696#ifdef VBOX_HWACCM_WITH_GUEST_PATCHING
1697 /* Shortcut for APIC TPR reads and writes; 32 bits guests only */
1698 if ( pVM->hwaccm.s.fTRPPatchingAllowed
1699 && (uFaultAddress & 0xfff) == 0x080
1700 && !(errCode & X86_TRAP_PF_P) /* not present */
1701 && CPUMGetGuestCPL(pVCpu, CPUMCTX2CORE(pCtx)) == 0
1702 && !CPUMIsGuestInLongModeEx(pCtx)
1703 && pVM->hwaccm.s.cPatches < RT_ELEMENTS(pVM->hwaccm.s.aPatches))
1704 {
1705 RTGCPHYS GCPhysApicBase, GCPhys;
1706 PDMApicGetBase(pVM, &GCPhysApicBase); /* @todo cache this */
1707 GCPhysApicBase &= PAGE_BASE_GC_MASK;
1708
1709 rc = PGMGstGetPage(pVCpu, (RTGCPTR)uFaultAddress, NULL, &GCPhys);
1710 if ( rc == VINF_SUCCESS
1711 && GCPhys == GCPhysApicBase)
1712 {
1713 /* Only attempt to patch the instruction once. */
1714 PHWACCMTPRPATCH pPatch = (PHWACCMTPRPATCH)RTAvloU32Get(&pVM->hwaccm.s.PatchTree, (AVLOU32KEY)pCtx->eip);
1715 if (!pPatch)
1716 {
1717 rc = VINF_EM_HWACCM_PATCH_TPR_INSTR;
1718 break;
1719 }
1720 }
1721 }
1722#endif
1723
1724 Log2(("Page fault at %RGv cr2=%RGv error code %x\n", (RTGCPTR)pCtx->rip, uFaultAddress, errCode));
1725 /* Exit qualification contains the linear address of the page fault. */
1726 TRPMAssertTrap(pVCpu, X86_XCPT_PF, TRPM_TRAP);
1727 TRPMSetErrorCode(pVCpu, errCode);
1728 TRPMSetFaultAddress(pVCpu, uFaultAddress);
1729
1730 /* Forward it to our trap handler first, in case our shadow pages are out of sync. */
1731 rc = PGMTrap0eHandler(pVCpu, errCode, CPUMCTX2CORE(pCtx), (RTGCPTR)uFaultAddress);
1732 Log2(("PGMTrap0eHandler %RGv returned %Rrc\n", (RTGCPTR)pCtx->rip, rc));
1733 if (rc == VINF_SUCCESS)
1734 { /* We've successfully synced our shadow pages, so let's just continue execution. */
1735 Log2(("Shadow page fault at %RGv cr2=%RGv error code %x\n", (RTGCPTR)pCtx->rip, uFaultAddress, errCode));
1736 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitShadowPF);
1737
1738 TRPMResetTrap(pVCpu);
1739 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1740 goto ResumeExecution;
1741 }
1742 else
1743 if (rc == VINF_EM_RAW_GUEST_TRAP)
1744 { /* A genuine pagefault.
1745 * Forward the trap to the guest by injecting the exception and resuming execution.
1746 */
1747 Log2(("Forward page fault to the guest\n"));
1748 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestPF);
1749 /* The error code might have been changed. */
1750 errCode = TRPMGetErrorCode(pVCpu);
1751
1752 TRPMResetTrap(pVCpu);
1753
1754 /* Now we must update CR2. */
1755 pCtx->cr2 = uFaultAddress;
1756
1757 Event.au64[0] = 0;
1758 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1759 Event.n.u1Valid = 1;
1760 Event.n.u8Vector = X86_XCPT_PF;
1761 Event.n.u1ErrorCodeValid = 1;
1762 Event.n.u32ErrorCode = errCode;
1763
1764 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
1765
1766 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1767 goto ResumeExecution;
1768 }
1769#ifdef VBOX_STRICT
1770 if (rc != VINF_EM_RAW_EMULATE_INSTR && rc != VINF_EM_RAW_EMULATE_IO_BLOCK)
1771 LogFlow(("PGMTrap0eHandler failed with %d\n", rc));
1772#endif
1773 /* Need to go back to the recompiler to emulate the instruction. */
1774 TRPMResetTrap(pVCpu);
1775 break;
1776 }
1777
1778 case X86_XCPT_MF: /* Floating point exception. */
1779 {
1780 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestMF);
1781 if (!(pCtx->cr0 & X86_CR0_NE))
1782 {
1783 /* old style FPU error reporting needs some extra work. */
1784 /** @todo don't fall back to the recompiler, but do it manually. */
1785 rc = VINF_EM_RAW_EMULATE_INSTR;
1786 break;
1787 }
1788 Log(("Trap %x at %RGv\n", vector, (RTGCPTR)pCtx->rip));
1789
1790 Event.au64[0] = 0;
1791 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1792 Event.n.u1Valid = 1;
1793 Event.n.u8Vector = X86_XCPT_MF;
1794
1795 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
1796
1797 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1798 goto ResumeExecution;
1799 }
1800
1801#ifdef VBOX_STRICT
1802 case X86_XCPT_GP: /* General protection failure exception.*/
1803 case X86_XCPT_UD: /* Unknown opcode exception. */
1804 case X86_XCPT_DE: /* Divide error. */
1805 case X86_XCPT_SS: /* Stack segment exception. */
1806 case X86_XCPT_NP: /* Segment not present exception. */
1807 {
1808 Event.au64[0] = 0;
1809 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1810 Event.n.u1Valid = 1;
1811 Event.n.u8Vector = vector;
1812
1813 switch(vector)
1814 {
1815 case X86_XCPT_GP:
1816 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestGP);
1817 Event.n.u1ErrorCodeValid = 1;
1818 Event.n.u32ErrorCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1819 break;
1820 case X86_XCPT_DE:
1821 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestDE);
1822 break;
1823 case X86_XCPT_UD:
1824 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestUD);
1825 break;
1826 case X86_XCPT_SS:
1827 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestSS);
1828 Event.n.u1ErrorCodeValid = 1;
1829 Event.n.u32ErrorCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1830 break;
1831 case X86_XCPT_NP:
1832 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitGuestNP);
1833 Event.n.u1ErrorCodeValid = 1;
1834 Event.n.u32ErrorCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1835 break;
1836 }
1837 Log(("Trap %x at %04x:%RGv esi=%x\n", vector, pCtx->cs, (RTGCPTR)pCtx->rip, pCtx->esi));
1838 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
1839
1840 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1841 goto ResumeExecution;
1842 }
1843#endif
1844 default:
1845 AssertMsgFailed(("Unexpected vm-exit caused by exception %x\n", vector));
1846 rc = VERR_EM_INTERNAL_ERROR;
1847 break;
1848
1849 } /* switch (vector) */
1850 break;
1851 }
1852
1853 case SVM_EXIT_NPF:
1854 {
1855 /* EXITINFO1 contains fault errorcode; EXITINFO2 contains the guest physical address causing the fault. */
1856 uint32_t errCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1857 RTGCPHYS uFaultAddress = pVMCB->ctrl.u64ExitInfo2; /* EXITINFO2 = fault address */
1858 PGMMODE enmShwPagingMode;
1859
1860 Assert(pVM->hwaccm.s.fNestedPaging);
1861 LogFlow(("Nested page fault at %RGv cr2=%RGp error code %x\n", (RTGCPTR)pCtx->rip, uFaultAddress, errCode));
1862
1863#ifdef VBOX_HWACCM_WITH_GUEST_PATCHING
1864 /* Shortcut for APIC TPR reads and writes; 32 bits guests only */
1865 if ( pVM->hwaccm.s.fTRPPatchingAllowed
1866 && (uFaultAddress & 0xfff) == 0x080
1867 && !(errCode & X86_TRAP_PF_P) /* not present */
1868 && CPUMGetGuestCPL(pVCpu, CPUMCTX2CORE(pCtx)) == 0
1869 && !CPUMIsGuestInLongModeEx(pCtx)
1870 && pVM->hwaccm.s.cPatches < RT_ELEMENTS(pVM->hwaccm.s.aPatches))
1871 {
1872 RTGCPHYS GCPhysApicBase;
1873 PDMApicGetBase(pVM, &GCPhysApicBase); /* @todo cache this */
1874 GCPhysApicBase &= PAGE_BASE_GC_MASK;
1875
1876 if (uFaultAddress == GCPhysApicBase + 0x80)
1877 {
1878 /* Only attempt to patch the instruction once. */
1879 PHWACCMTPRPATCH pPatch = (PHWACCMTPRPATCH)RTAvloU32Get(&pVM->hwaccm.s.PatchTree, (AVLOU32KEY)pCtx->eip);
1880 if (!pPatch)
1881 {
1882 rc = VINF_EM_HWACCM_PATCH_TPR_INSTR;
1883 break;
1884 }
1885 }
1886 }
1887#endif
1888
1889 /* Exit qualification contains the linear address of the page fault. */
1890 TRPMAssertTrap(pVCpu, X86_XCPT_PF, TRPM_TRAP);
1891 TRPMSetErrorCode(pVCpu, errCode);
1892 TRPMSetFaultAddress(pVCpu, uFaultAddress);
1893
1894 /* Handle the pagefault trap for the nested shadow table. */
1895#if HC_ARCH_BITS == 32
1896 if (CPUMIsGuestInLongModeEx(pCtx))
1897 enmShwPagingMode = PGMMODE_AMD64_NX;
1898 else
1899#endif
1900 enmShwPagingMode = PGMGetHostMode(pVM);
1901
1902 rc = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, enmShwPagingMode, errCode, CPUMCTX2CORE(pCtx), uFaultAddress);
1903 Log2(("PGMR0Trap0eHandlerNestedPaging %RGv returned %Rrc\n", (RTGCPTR)pCtx->rip, rc));
1904 if (rc == VINF_SUCCESS)
1905 { /* We've successfully synced our shadow pages, so let's just continue execution. */
1906 Log2(("Shadow page fault at %RGv cr2=%RGp error code %x\n", (RTGCPTR)pCtx->rip, uFaultAddress, errCode));
1907 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitShadowPF);
1908
1909 TRPMResetTrap(pVCpu);
1910
1911 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1912 goto ResumeExecution;
1913 }
1914
1915#ifdef VBOX_STRICT
1916 if (rc != VINF_EM_RAW_EMULATE_INSTR)
1917 LogFlow(("PGMTrap0eHandlerNestedPaging failed with %d\n", rc));
1918#endif
1919 /* Need to go back to the recompiler to emulate the instruction. */
1920 TRPMResetTrap(pVCpu);
1921 break;
1922 }
1923
1924 case SVM_EXIT_VINTR:
1925 /* A virtual interrupt is about to be delivered, which means IF=1. */
1926 Log(("SVM_EXIT_VINTR IF=%d\n", pCtx->eflags.Bits.u1IF));
1927 pVMCB->ctrl.IntCtrl.n.u1VIrqValid = 0;
1928 pVMCB->ctrl.IntCtrl.n.u8VIrqVector = 0;
1929 goto ResumeExecution;
1930
1931 case SVM_EXIT_FERR_FREEZE:
1932 case SVM_EXIT_INTR:
1933 case SVM_EXIT_NMI:
1934 case SVM_EXIT_SMI:
1935 case SVM_EXIT_INIT:
1936 /* External interrupt; leave to allow it to be dispatched again. */
1937 rc = VINF_EM_RAW_INTERRUPT;
1938 break;
1939
1940 case SVM_EXIT_WBINVD:
1941 case SVM_EXIT_INVD: /* Guest software attempted to execute INVD. */
1942 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitInvd);
1943 /* Skip instruction and continue directly. */
1944 pCtx->rip += 2; /* Note! hardcoded opcode size! */
1945 /* Continue execution.*/
1946 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1947 goto ResumeExecution;
1948
1949 case SVM_EXIT_CPUID: /* Guest software attempted to execute CPUID. */
1950 {
1951 Log2(("SVM: Cpuid at %RGv for %x\n", (RTGCPTR)pCtx->rip, pCtx->eax));
1952 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCpuid);
1953 rc = EMInterpretCpuId(pVM, pVCpu, CPUMCTX2CORE(pCtx));
1954 if (rc == VINF_SUCCESS)
1955 {
1956 /* Update EIP and continue execution. */
1957 pCtx->rip += 2; /* Note! hardcoded opcode size! */
1958 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1959 goto ResumeExecution;
1960 }
1961 AssertMsgFailed(("EMU: cpuid failed with %Rrc\n", rc));
1962 rc = VINF_EM_RAW_EMULATE_INSTR;
1963 break;
1964 }
1965
1966 case SVM_EXIT_RDTSC: /* Guest software attempted to execute RDTSC. */
1967 {
1968 Log2(("SVM: Rdtsc\n"));
1969 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitRdtsc);
1970 rc = EMInterpretRdtsc(pVM, pVCpu, CPUMCTX2CORE(pCtx));
1971 if (rc == VINF_SUCCESS)
1972 {
1973 /* Update EIP and continue execution. */
1974 pCtx->rip += 2; /* Note! hardcoded opcode size! */
1975 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
1976 goto ResumeExecution;
1977 }
1978 rc = VINF_EM_RAW_EMULATE_INSTR;
1979 break;
1980 }
1981
1982 case SVM_EXIT_RDPMC: /* Guest software attempted to execute RDPMC. */
1983 {
1984 Log2(("SVM: Rdpmc %x\n", pCtx->ecx));
1985 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitRdpmc);
1986 rc = EMInterpretRdpmc(pVM, pVCpu, CPUMCTX2CORE(pCtx));
1987 if (rc == VINF_SUCCESS)
1988 {
1989 /* Update EIP and continue execution. */
1990 pCtx->rip += 2; /* Note! hardcoded opcode size! */
1991 goto ResumeExecution;
1992 }
1993 rc = VINF_EM_RAW_EMULATE_INSTR;
1994 break;
1995 }
1996
1997 case SVM_EXIT_RDTSCP: /* Guest software attempted to execute RDTSCP. */
1998 {
1999 Log2(("SVM: Rdtscp\n"));
2000 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitRdtsc);
2001 rc = EMInterpretRdtscp(pVM, pVCpu, pCtx);
2002 if (rc == VINF_SUCCESS)
2003 {
2004 /* Update EIP and continue execution. */
2005 pCtx->rip += 3; /* Note! hardcoded opcode size! */
2006 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2007 goto ResumeExecution;
2008 }
2009 AssertMsgFailed(("EMU: rdtscp failed with %Rrc\n", rc));
2010 rc = VINF_EM_RAW_EMULATE_INSTR;
2011 break;
2012 }
2013
2014 case SVM_EXIT_INVLPG: /* Guest software attempted to execute INVPG. */
2015 {
2016 Log2(("SVM: invlpg\n"));
2017 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitInvpg);
2018
2019 Assert(!pVM->hwaccm.s.fNestedPaging);
2020
2021 /* Truly a pita. Why can't SVM give the same information as VT-x? */
2022 rc = svmR0InterpretInvpg(pVM, pVCpu, CPUMCTX2CORE(pCtx), pVMCB->ctrl.TLBCtrl.n.u32ASID);
2023 if (rc == VINF_SUCCESS)
2024 {
2025 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushPageInvlpg);
2026 goto ResumeExecution; /* eip already updated */
2027 }
2028 break;
2029 }
2030
2031 case SVM_EXIT_WRITE_CR0: case SVM_EXIT_WRITE_CR1: case SVM_EXIT_WRITE_CR2: case SVM_EXIT_WRITE_CR3:
2032 case SVM_EXIT_WRITE_CR4: case SVM_EXIT_WRITE_CR5: case SVM_EXIT_WRITE_CR6: case SVM_EXIT_WRITE_CR7:
2033 case SVM_EXIT_WRITE_CR8: case SVM_EXIT_WRITE_CR9: case SVM_EXIT_WRITE_CR10: case SVM_EXIT_WRITE_CR11:
2034 case SVM_EXIT_WRITE_CR12: case SVM_EXIT_WRITE_CR13: case SVM_EXIT_WRITE_CR14: case SVM_EXIT_WRITE_CR15:
2035 {
2036 uint32_t cbSize;
2037
2038 Log2(("SVM: %RGv mov cr%d, \n", (RTGCPTR)pCtx->rip, exitCode - SVM_EXIT_WRITE_CR0));
2039 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCRxWrite[exitCode - SVM_EXIT_WRITE_CR0]);
2040 rc = EMInterpretInstruction(pVM, pVCpu, CPUMCTX2CORE(pCtx), 0, &cbSize);
2041
2042 switch (exitCode - SVM_EXIT_WRITE_CR0)
2043 {
2044 case 0:
2045 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
2046 break;
2047 case 2:
2048 break;
2049 case 3:
2050 Assert(!pVM->hwaccm.s.fNestedPaging);
2051 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR3;
2052 break;
2053 case 4:
2054 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR4;
2055 break;
2056 case 8:
2057 break;
2058 default:
2059 AssertFailed();
2060 }
2061 if (rc == VINF_SUCCESS)
2062 {
2063 /* EIP has been updated already. */
2064
2065 /* Only resume if successful. */
2066 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2067 goto ResumeExecution;
2068 }
2069 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
2070 break;
2071 }
2072
2073 case SVM_EXIT_READ_CR0: case SVM_EXIT_READ_CR1: case SVM_EXIT_READ_CR2: case SVM_EXIT_READ_CR3:
2074 case SVM_EXIT_READ_CR4: case SVM_EXIT_READ_CR5: case SVM_EXIT_READ_CR6: case SVM_EXIT_READ_CR7:
2075 case SVM_EXIT_READ_CR8: case SVM_EXIT_READ_CR9: case SVM_EXIT_READ_CR10: case SVM_EXIT_READ_CR11:
2076 case SVM_EXIT_READ_CR12: case SVM_EXIT_READ_CR13: case SVM_EXIT_READ_CR14: case SVM_EXIT_READ_CR15:
2077 {
2078 uint32_t cbSize;
2079
2080 Log2(("SVM: %RGv mov x, cr%d\n", (RTGCPTR)pCtx->rip, exitCode - SVM_EXIT_READ_CR0));
2081 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitCRxRead[exitCode - SVM_EXIT_READ_CR0]);
2082 rc = EMInterpretInstruction(pVM, pVCpu, CPUMCTX2CORE(pCtx), 0, &cbSize);
2083 if (rc == VINF_SUCCESS)
2084 {
2085 /* EIP has been updated already. */
2086
2087 /* Only resume if successful. */
2088 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2089 goto ResumeExecution;
2090 }
2091 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
2092 break;
2093 }
2094
2095 case SVM_EXIT_WRITE_DR0: case SVM_EXIT_WRITE_DR1: case SVM_EXIT_WRITE_DR2: case SVM_EXIT_WRITE_DR3:
2096 case SVM_EXIT_WRITE_DR4: case SVM_EXIT_WRITE_DR5: case SVM_EXIT_WRITE_DR6: case SVM_EXIT_WRITE_DR7:
2097 case SVM_EXIT_WRITE_DR8: case SVM_EXIT_WRITE_DR9: case SVM_EXIT_WRITE_DR10: case SVM_EXIT_WRITE_DR11:
2098 case SVM_EXIT_WRITE_DR12: case SVM_EXIT_WRITE_DR13: case SVM_EXIT_WRITE_DR14: case SVM_EXIT_WRITE_DR15:
2099 {
2100 uint32_t cbSize;
2101
2102 Log2(("SVM: %RGv mov dr%d, x\n", (RTGCPTR)pCtx->rip, exitCode - SVM_EXIT_WRITE_DR0));
2103 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxWrite);
2104
2105 if ( !DBGFIsStepping(pVCpu)
2106 && !CPUMIsHyperDebugStateActive(pVCpu))
2107 {
2108 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxContextSwitch);
2109
2110 /* Disable drx move intercepts. */
2111 pVMCB->ctrl.u16InterceptRdDRx = 0;
2112 pVMCB->ctrl.u16InterceptWrDRx = 0;
2113
2114 /* Save the host and load the guest debug state. */
2115 rc = CPUMR0LoadGuestDebugState(pVM, pVCpu, pCtx, false /* exclude DR6 */);
2116 AssertRC(rc);
2117
2118 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2119 goto ResumeExecution;
2120 }
2121
2122 rc = EMInterpretInstruction(pVM, pVCpu, CPUMCTX2CORE(pCtx), 0, &cbSize);
2123 if (rc == VINF_SUCCESS)
2124 {
2125 /* EIP has been updated already. */
2126 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_DEBUG;
2127
2128 /* Only resume if successful. */
2129 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2130 goto ResumeExecution;
2131 }
2132 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
2133 break;
2134 }
2135
2136 case SVM_EXIT_READ_DR0: case SVM_EXIT_READ_DR1: case SVM_EXIT_READ_DR2: case SVM_EXIT_READ_DR3:
2137 case SVM_EXIT_READ_DR4: case SVM_EXIT_READ_DR5: case SVM_EXIT_READ_DR6: case SVM_EXIT_READ_DR7:
2138 case SVM_EXIT_READ_DR8: case SVM_EXIT_READ_DR9: case SVM_EXIT_READ_DR10: case SVM_EXIT_READ_DR11:
2139 case SVM_EXIT_READ_DR12: case SVM_EXIT_READ_DR13: case SVM_EXIT_READ_DR14: case SVM_EXIT_READ_DR15:
2140 {
2141 uint32_t cbSize;
2142
2143 Log2(("SVM: %RGv mov x, dr%d\n", (RTGCPTR)pCtx->rip, exitCode - SVM_EXIT_READ_DR0));
2144 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitDRxRead);
2145
2146 if (!DBGFIsStepping(pVCpu))
2147 {
2148 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxContextSwitch);
2149
2150 /* Disable drx move intercepts. */
2151 pVMCB->ctrl.u16InterceptRdDRx = 0;
2152 pVMCB->ctrl.u16InterceptWrDRx = 0;
2153
2154 /* Save the host and load the guest debug state. */
2155 rc = CPUMR0LoadGuestDebugState(pVM, pVCpu, pCtx, false /* exclude DR6 */);
2156 AssertRC(rc);
2157
2158 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2159 goto ResumeExecution;
2160 }
2161
2162 rc = EMInterpretInstruction(pVM, pVCpu, CPUMCTX2CORE(pCtx), 0, &cbSize);
2163 if (rc == VINF_SUCCESS)
2164 {
2165 /* EIP has been updated already. */
2166
2167 /* Only resume if successful. */
2168 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2169 goto ResumeExecution;
2170 }
2171 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
2172 break;
2173 }
2174
2175 /* Note: We'll get a #GP if the IO instruction isn't allowed (IOPL or TSS bitmap); no need to double check. */
2176 case SVM_EXIT_IOIO: /* I/O instruction. */
2177 {
2178 SVM_IOIO_EXIT IoExitInfo;
2179 uint32_t uIOSize, uAndVal;
2180
2181 IoExitInfo.au32[0] = pVMCB->ctrl.u64ExitInfo1;
2182
2183 /** @todo could use a lookup table here */
2184 if (IoExitInfo.n.u1OP8)
2185 {
2186 uIOSize = 1;
2187 uAndVal = 0xff;
2188 }
2189 else
2190 if (IoExitInfo.n.u1OP16)
2191 {
2192 uIOSize = 2;
2193 uAndVal = 0xffff;
2194 }
2195 else
2196 if (IoExitInfo.n.u1OP32)
2197 {
2198 uIOSize = 4;
2199 uAndVal = 0xffffffff;
2200 }
2201 else
2202 {
2203 AssertFailed(); /* should be fatal. */
2204 rc = VINF_EM_RAW_EMULATE_INSTR;
2205 break;
2206 }
2207
2208 if (IoExitInfo.n.u1STR)
2209 {
2210 /* ins/outs */
2211 PDISCPUSTATE pDis = &pVCpu->hwaccm.s.DisState;
2212
2213 /* Disassemble manually to deal with segment prefixes. */
2214 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), pDis, NULL);
2215 if (rc == VINF_SUCCESS)
2216 {
2217 if (IoExitInfo.n.u1Type == 0)
2218 {
2219 Log2(("IOMInterpretOUTSEx %RGv %x size=%d\n", (RTGCPTR)pCtx->rip, IoExitInfo.n.u16Port, uIOSize));
2220 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIOStringWrite);
2221 rc = VBOXSTRICTRC_TODO(IOMInterpretOUTSEx(pVM, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, pDis->prefix, uIOSize));
2222 }
2223 else
2224 {
2225 Log2(("IOMInterpretINSEx %RGv %x size=%d\n", (RTGCPTR)pCtx->rip, IoExitInfo.n.u16Port, uIOSize));
2226 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIOStringRead);
2227 rc = VBOXSTRICTRC_TODO(IOMInterpretINSEx(pVM, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, pDis->prefix, uIOSize));
2228 }
2229 }
2230 else
2231 rc = VINF_EM_RAW_EMULATE_INSTR;
2232 }
2233 else
2234 {
2235 /* normal in/out */
2236 Assert(!IoExitInfo.n.u1REP);
2237
2238 if (IoExitInfo.n.u1Type == 0)
2239 {
2240 Log2(("IOMIOPortWrite %RGv %x %x size=%d\n", (RTGCPTR)pCtx->rip, IoExitInfo.n.u16Port, pCtx->eax & uAndVal, uIOSize));
2241 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIOWrite);
2242 rc = VBOXSTRICTRC_TODO(IOMIOPortWrite(pVM, IoExitInfo.n.u16Port, pCtx->eax & uAndVal, uIOSize));
2243 if (rc == VINF_IOM_HC_IOPORT_WRITE)
2244 HWACCMR0SavePendingIOPortWrite(pVCpu, pCtx->rip, pVMCB->ctrl.u64ExitInfo2, IoExitInfo.n.u16Port, uAndVal, uIOSize);
2245 }
2246 else
2247 {
2248 uint32_t u32Val = 0;
2249
2250 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitIORead);
2251 rc = VBOXSTRICTRC_TODO(IOMIOPortRead(pVM, IoExitInfo.n.u16Port, &u32Val, uIOSize));
2252 if (IOM_SUCCESS(rc))
2253 {
2254 /* Write back to the EAX register. */
2255 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Val & uAndVal);
2256 Log2(("IOMIOPortRead %RGv %x %x size=%d\n", (RTGCPTR)pCtx->rip, IoExitInfo.n.u16Port, u32Val & uAndVal, uIOSize));
2257 }
2258 else
2259 if (rc == VINF_IOM_HC_IOPORT_READ)
2260 HWACCMR0SavePendingIOPortRead(pVCpu, pCtx->rip, pVMCB->ctrl.u64ExitInfo2, IoExitInfo.n.u16Port, uAndVal, uIOSize);
2261 }
2262 }
2263 /*
2264 * Handled the I/O return codes.
2265 * (The unhandled cases end up with rc == VINF_EM_RAW_EMULATE_INSTR.)
2266 */
2267 if (IOM_SUCCESS(rc))
2268 {
2269 /* Update EIP and continue execution. */
2270 pCtx->rip = pVMCB->ctrl.u64ExitInfo2; /* RIP/EIP of the next instruction is saved in EXITINFO2. */
2271 if (RT_LIKELY(rc == VINF_SUCCESS))
2272 {
2273 /* If any IO breakpoints are armed, then we should check if a debug trap needs to be generated. */
2274 if (pCtx->dr[7] & X86_DR7_ENABLED_MASK)
2275 {
2276 /* IO operation lookup arrays. */
2277 static uint32_t const aIOSize[4] = {1, 2, 0, 4};
2278
2279 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatDRxIOCheck);
2280 for (unsigned i=0;i<4;i++)
2281 {
2282 unsigned uBPLen = aIOSize[X86_DR7_GET_LEN(pCtx->dr[7], i)];
2283
2284 if ( (IoExitInfo.n.u16Port >= pCtx->dr[i] && IoExitInfo.n.u16Port < pCtx->dr[i] + uBPLen)
2285 && (pCtx->dr[7] & (X86_DR7_L(i) | X86_DR7_G(i)))
2286 && (pCtx->dr[7] & X86_DR7_RW(i, X86_DR7_RW_IO)) == X86_DR7_RW(i, X86_DR7_RW_IO))
2287 {
2288 SVM_EVENT Event;
2289
2290 Assert(CPUMIsGuestDebugStateActive(pVCpu));
2291
2292 /* Clear all breakpoint status flags and set the one we just hit. */
2293 pCtx->dr[6] &= ~(X86_DR6_B0|X86_DR6_B1|X86_DR6_B2|X86_DR6_B3);
2294 pCtx->dr[6] |= (uint64_t)RT_BIT(i);
2295
2296 /* Note: AMD64 Architecture Programmer's Manual 13.1:
2297 * Bits 15:13 of the DR6 register is never cleared by the processor and must be cleared by software after
2298 * the contents have been read.
2299 */
2300 pVMCB->guest.u64DR6 = pCtx->dr[6];
2301
2302 /* X86_DR7_GD will be cleared if drx accesses should be trapped inside the guest. */
2303 pCtx->dr[7] &= ~X86_DR7_GD;
2304
2305 /* Paranoia. */
2306 pCtx->dr[7] &= 0xffffffff; /* upper 32 bits reserved */
2307 pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
2308 pCtx->dr[7] |= 0x400; /* must be one */
2309
2310 pVMCB->guest.u64DR7 = pCtx->dr[7];
2311
2312 /* Inject the exception. */
2313 Log(("Inject IO debug trap at %RGv\n", (RTGCPTR)pCtx->rip));
2314
2315 Event.au64[0] = 0;
2316 Event.n.u3Type = SVM_EVENT_EXCEPTION; /* trap or fault */
2317 Event.n.u1Valid = 1;
2318 Event.n.u8Vector = X86_XCPT_DB;
2319
2320 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
2321
2322 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2323 goto ResumeExecution;
2324 }
2325 }
2326 }
2327
2328 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2329 goto ResumeExecution;
2330 }
2331 Log2(("EM status from IO at %RGv %x size %d: %Rrc\n", (RTGCPTR)pCtx->rip, IoExitInfo.n.u16Port, uIOSize, rc));
2332 break;
2333 }
2334
2335#ifdef VBOX_STRICT
2336 if (rc == VINF_IOM_HC_IOPORT_READ)
2337 Assert(IoExitInfo.n.u1Type != 0);
2338 else if (rc == VINF_IOM_HC_IOPORT_WRITE)
2339 Assert(IoExitInfo.n.u1Type == 0);
2340 else
2341 AssertMsg(RT_FAILURE(rc) || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", rc));
2342#endif
2343 Log2(("Failed IO at %RGv %x size %d\n", (RTGCPTR)pCtx->rip, IoExitInfo.n.u16Port, uIOSize));
2344 break;
2345 }
2346
2347 case SVM_EXIT_HLT:
2348 /** Check if external interrupts are pending; if so, don't switch back. */
2349 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitHlt);
2350 pCtx->rip++; /* skip hlt */
2351 if ( pCtx->eflags.Bits.u1IF
2352 && VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)))
2353 goto ResumeExecution;
2354
2355 rc = VINF_EM_HALT;
2356 break;
2357
2358 case SVM_EXIT_MWAIT_UNCOND:
2359 Log2(("SVM: mwait\n"));
2360 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatExitMwait);
2361 rc = EMInterpretMWait(pVM, pVCpu, CPUMCTX2CORE(pCtx));
2362 if ( rc == VINF_EM_HALT
2363 || rc == VINF_SUCCESS)
2364 {
2365 /* Update EIP and continue execution. */
2366 pCtx->rip += 3; /* Note: hardcoded opcode size assumption! */
2367
2368 /** Check if external interrupts are pending; if so, don't switch back. */
2369 if ( rc == VINF_SUCCESS
2370 || ( rc == VINF_EM_HALT
2371 && pCtx->eflags.Bits.u1IF
2372 && VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC)))
2373 )
2374 goto ResumeExecution;
2375 }
2376 AssertMsg(rc == VERR_EM_INTERPRETER || rc == VINF_EM_HALT, ("EMU: mwait failed with %Rrc\n", rc));
2377 break;
2378
2379 case SVM_EXIT_VMMCALL:
2380 rc = svmR0EmulateTprVMMCall(pVM, pVCpu, pCtx);
2381 if (rc == VINF_SUCCESS)
2382 {
2383 goto ResumeExecution; /* rip already updated. */
2384 }
2385 /* no break */
2386
2387 case SVM_EXIT_RSM:
2388 case SVM_EXIT_INVLPGA:
2389 case SVM_EXIT_VMRUN:
2390 case SVM_EXIT_VMLOAD:
2391 case SVM_EXIT_VMSAVE:
2392 case SVM_EXIT_STGI:
2393 case SVM_EXIT_CLGI:
2394 case SVM_EXIT_SKINIT:
2395 {
2396 /* Unsupported instructions. */
2397 SVM_EVENT Event;
2398
2399 Event.au64[0] = 0;
2400 Event.n.u3Type = SVM_EVENT_EXCEPTION;
2401 Event.n.u1Valid = 1;
2402 Event.n.u8Vector = X86_XCPT_UD;
2403
2404 Log(("Forced #UD trap at %RGv\n", (RTGCPTR)pCtx->rip));
2405 SVMR0InjectEvent(pVCpu, pVMCB, pCtx, &Event);
2406
2407 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2408 goto ResumeExecution;
2409 }
2410
2411 /* Emulate in ring 3. */
2412 case SVM_EXIT_MSR:
2413 {
2414 uint32_t cbSize;
2415
2416 /* When an interrupt is pending, we'll let MSR_K8_LSTAR writes fault in our TPR patch code. */
2417 if ( pVM->hwaccm.s.fTPRPatchingActive
2418 && pCtx->ecx == MSR_K8_LSTAR
2419 && pVMCB->ctrl.u64ExitInfo1 == 1 /* wrmsr */)
2420 {
2421 if ((pCtx->eax & 0xff) != u8LastTPR)
2422 {
2423 Log(("SVM: Faulting MSR_K8_LSTAR write with new TPR value %x\n", pCtx->eax & 0xff));
2424
2425 /* Our patch code uses LSTAR for TPR caching. */
2426 rc = PDMApicSetTPR(pVCpu, pCtx->eax & 0xff);
2427 AssertRC(rc);
2428 }
2429
2430 /* Skip the instruction and continue. */
2431 pCtx->rip += 2; /* wrmsr = [0F 30] */
2432
2433 /* Only resume if successful. */
2434 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2435 goto ResumeExecution;
2436 }
2437
2438 /* 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. */
2439 STAM_COUNTER_INC((pVMCB->ctrl.u64ExitInfo1 == 0) ? &pVCpu->hwaccm.s.StatExitRdmsr : &pVCpu->hwaccm.s.StatExitWrmsr);
2440 Log(("SVM: %s\n", (pVMCB->ctrl.u64ExitInfo1 == 0) ? "rdmsr" : "wrmsr"));
2441 rc = EMInterpretInstruction(pVM, pVCpu, CPUMCTX2CORE(pCtx), 0, &cbSize);
2442 if (rc == VINF_SUCCESS)
2443 {
2444 /* EIP has been updated already. */
2445
2446 /* Only resume if successful. */
2447 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2448 goto ResumeExecution;
2449 }
2450 AssertMsg(rc == VERR_EM_INTERPRETER, ("EMU: %s failed with %Rrc\n", (pVMCB->ctrl.u64ExitInfo1 == 0) ? "rdmsr" : "wrmsr", rc));
2451 break;
2452 }
2453
2454 case SVM_EXIT_TASK_SWITCH: /* too complicated to emulate, so fall back to the recompiler*/
2455 Log(("SVM_EXIT_TASK_SWITCH: exit2=%RX64\n", pVMCB->ctrl.u64ExitInfo2));
2456 if ( !(pVMCB->ctrl.u64ExitInfo2 & (SVM_EXIT2_TASK_SWITCH_IRET | SVM_EXIT2_TASK_SWITCH_JMP))
2457 && pVCpu->hwaccm.s.Event.fPending)
2458 {
2459 SVM_EVENT Event;
2460
2461 Event.au64[0] = pVCpu->hwaccm.s.Event.intInfo;
2462
2463 /* Caused by an injected interrupt. */
2464 pVCpu->hwaccm.s.Event.fPending = false;
2465
2466 switch (Event.n.u3Type)
2467 {
2468 case SVM_EVENT_EXTERNAL_IRQ:
2469 case SVM_EVENT_NMI:
2470 Log(("SVM_EXIT_TASK_SWITCH: reassert trap %d\n", Event.n.u8Vector));
2471 Assert(!Event.n.u1ErrorCodeValid);
2472 rc = TRPMAssertTrap(pVCpu, Event.n.u8Vector, TRPM_HARDWARE_INT);
2473 AssertRC(rc);
2474 break;
2475
2476 default:
2477 /* Exceptions and software interrupts can just be restarted. */
2478 break;
2479 }
2480 }
2481 rc = VERR_EM_INTERPRETER;
2482 break;
2483
2484 case SVM_EXIT_MONITOR:
2485 case SVM_EXIT_PAUSE:
2486 case SVM_EXIT_MWAIT_ARMED:
2487 rc = VERR_EM_INTERPRETER;
2488 break;
2489
2490 case SVM_EXIT_SHUTDOWN:
2491 rc = VINF_EM_RESET; /* Triple fault equals a reset. */
2492 break;
2493
2494 case SVM_EXIT_IDTR_READ:
2495 case SVM_EXIT_GDTR_READ:
2496 case SVM_EXIT_LDTR_READ:
2497 case SVM_EXIT_TR_READ:
2498 case SVM_EXIT_IDTR_WRITE:
2499 case SVM_EXIT_GDTR_WRITE:
2500 case SVM_EXIT_LDTR_WRITE:
2501 case SVM_EXIT_TR_WRITE:
2502 case SVM_EXIT_CR0_SEL_WRITE:
2503 default:
2504 /* Unexpected exit codes. */
2505 rc = VERR_EM_INTERNAL_ERROR;
2506 AssertMsgFailed(("Unexpected exit code %x\n", exitCode)); /* Can't happen. */
2507 break;
2508 }
2509
2510end:
2511
2512 /* Signal changes for the recompiler. */
2513 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR | CPUM_CHANGED_LDTR | CPUM_CHANGED_GDTR | CPUM_CHANGED_IDTR | CPUM_CHANGED_TR | CPUM_CHANGED_HIDDEN_SEL_REGS);
2514
2515 /* If we executed vmrun and an external irq was pending, then we don't have to do a full sync the next time. */
2516 if (exitCode == SVM_EXIT_INTR)
2517 {
2518 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatPendingHostIrq);
2519 /* On the next entry we'll only sync the host context. */
2520 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_HOST_CONTEXT;
2521 }
2522 else
2523 {
2524 /* On the next entry we'll sync everything. */
2525 /** @todo we can do better than this */
2526 /* Not in the VINF_PGM_CHANGE_MODE though! */
2527 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_ALL;
2528 }
2529
2530 /* translate into a less severe return code */
2531 if (rc == VERR_EM_INTERPRETER)
2532 rc = VINF_EM_RAW_EMULATE_INSTR;
2533
2534 /* Just set the correct state here instead of trying to catch every goto above. */
2535 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC);
2536
2537#ifdef VBOX_WITH_VMMR0_DISABLE_PREEMPTION
2538 /* Restore interrupts if we exitted after disabling them. */
2539 if (uOldEFlags != ~(RTCCUINTREG)0)
2540 ASMSetFlags(uOldEFlags);
2541#endif
2542
2543 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x);
2544 return rc;
2545}
2546
2547/**
2548 * Emulate simple mov tpr instruction
2549 *
2550 * @returns VBox status code.
2551 * @param pVM The VM to operate on.
2552 * @param pVCpu The VM CPU to operate on.
2553 * @param pCtx CPU context
2554 */
2555static int svmR0EmulateTprVMMCall(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
2556{
2557 int rc;
2558
2559 LogFlow(("Emulated VMMCall TPR access replacement at %RGv\n", pCtx->rip));
2560
2561 while (true)
2562 {
2563 bool fPending;
2564 uint8_t u8Tpr;
2565
2566 PHWACCMTPRPATCH pPatch = (PHWACCMTPRPATCH)RTAvloU32Get(&pVM->hwaccm.s.PatchTree, (AVLOU32KEY)pCtx->eip);
2567 if (!pPatch)
2568 break;
2569
2570 switch(pPatch->enmType)
2571 {
2572 case HWACCMTPRINSTR_READ:
2573 /* TPR caching in CR8 */
2574 rc = PDMApicGetTPR(pVCpu, &u8Tpr, &fPending);
2575 AssertRC(rc);
2576
2577 rc = DISWriteReg32(CPUMCTX2CORE(pCtx), pPatch->uDstOperand, u8Tpr);
2578 AssertRC(rc);
2579
2580 LogFlow(("Emulated read successfully\n"));
2581 pCtx->rip += pPatch->cbOp;
2582 break;
2583
2584 case HWACCMTPRINSTR_WRITE_REG:
2585 case HWACCMTPRINSTR_WRITE_IMM:
2586 /* Fetch the new TPR value */
2587 if (pPatch->enmType == HWACCMTPRINSTR_WRITE_REG)
2588 {
2589 uint32_t val;
2590
2591 rc = DISFetchReg32(CPUMCTX2CORE(pCtx), pPatch->uSrcOperand, &val);
2592 AssertRC(rc);
2593 u8Tpr = val;
2594 }
2595 else
2596 u8Tpr = (uint8_t)pPatch->uSrcOperand;
2597
2598 rc = PDMApicSetTPR(pVCpu, u8Tpr);
2599 AssertRC(rc);
2600 LogFlow(("Emulated write successfully\n"));
2601 pCtx->rip += pPatch->cbOp;
2602 break;
2603 default:
2604 AssertMsgFailedReturn(("Unexpected type %d\n", pPatch->enmType), VERR_INTERNAL_ERROR);
2605 }
2606 }
2607 return VINF_SUCCESS;
2608}
2609
2610
2611/**
2612 * Enters the AMD-V session
2613 *
2614 * @returns VBox status code.
2615 * @param pVM The VM to operate on.
2616 * @param pVCpu The VM CPU to operate on.
2617 * @param pCpu CPU info struct
2618 */
2619VMMR0DECL(int) SVMR0Enter(PVM pVM, PVMCPU pVCpu, PHWACCM_CPUINFO pCpu)
2620{
2621 Assert(pVM->hwaccm.s.svm.fSupported);
2622
2623 LogFlow(("SVMR0Enter cpu%d last=%d asid=%d\n", pCpu->idCpu, pVCpu->hwaccm.s.idLastCpu, pVCpu->hwaccm.s.uCurrentASID));
2624 pVCpu->hwaccm.s.fResumeVM = false;
2625
2626 /* Force to reload LDTR, so we'll execute VMLoad to load additional guest state. */
2627 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_LDTR;
2628
2629 return VINF_SUCCESS;
2630}
2631
2632
2633/**
2634 * Leaves the AMD-V session
2635 *
2636 * @returns VBox status code.
2637 * @param pVM The VM to operate on.
2638 * @param pVCpu The VM CPU to operate on.
2639 * @param pCtx CPU context
2640 */
2641VMMR0DECL(int) SVMR0Leave(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
2642{
2643 SVM_VMCB *pVMCB = (SVM_VMCB *)pVCpu->hwaccm.s.svm.pVMCB;
2644
2645 Assert(pVM->hwaccm.s.svm.fSupported);
2646
2647#ifdef DEBUG
2648 if (CPUMIsHyperDebugStateActive(pVCpu))
2649 {
2650 CPUMR0LoadHostDebugState(pVM, pVCpu);
2651 }
2652 else
2653#endif
2654 /* Save the guest debug state if necessary. */
2655 if (CPUMIsGuestDebugStateActive(pVCpu))
2656 {
2657 CPUMR0SaveGuestDebugState(pVM, pVCpu, pCtx, false /* skip DR6 */);
2658
2659 /* Intercept all DRx reads and writes again. Changed later on. */
2660 pVMCB->ctrl.u16InterceptRdDRx = 0xFFFF;
2661 pVMCB->ctrl.u16InterceptWrDRx = 0xFFFF;
2662
2663 /* Resync the debug registers the next time. */
2664 pVCpu->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_DEBUG;
2665 }
2666 else
2667 Assert(pVMCB->ctrl.u16InterceptRdDRx == 0xFFFF && pVMCB->ctrl.u16InterceptWrDRx == 0xFFFF);
2668
2669 return VINF_SUCCESS;
2670}
2671
2672
2673static int svmR0InterpretInvlPg(PVMCPU pVCpu, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, uint32_t uASID)
2674{
2675 OP_PARAMVAL param1;
2676 RTGCPTR addr;
2677
2678 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
2679 if(RT_FAILURE(rc))
2680 return VERR_EM_INTERPRETER;
2681
2682 switch(param1.type)
2683 {
2684 case PARMTYPE_IMMEDIATE:
2685 case PARMTYPE_ADDRESS:
2686 if(!(param1.flags & (PARAM_VAL32|PARAM_VAL64)))
2687 return VERR_EM_INTERPRETER;
2688 addr = param1.val.val64;
2689 break;
2690
2691 default:
2692 return VERR_EM_INTERPRETER;
2693 }
2694
2695 /** @todo is addr always a flat linear address or ds based
2696 * (in absence of segment override prefixes)????
2697 */
2698 rc = PGMInvalidatePage(pVCpu, addr);
2699 if (RT_SUCCESS(rc))
2700 return VINF_SUCCESS;
2701
2702 AssertRC(rc);
2703 return rc;
2704}
2705
2706/**
2707 * Interprets INVLPG
2708 *
2709 * @returns VBox status code.
2710 * @retval VINF_* Scheduling instructions.
2711 * @retval VERR_EM_INTERPRETER Something we can't cope with.
2712 * @retval VERR_* Fatal errors.
2713 *
2714 * @param pVM The VM handle.
2715 * @param pRegFrame The register frame.
2716 * @param ASID Tagged TLB id for the guest
2717 *
2718 * Updates the EIP if an instruction was executed successfully.
2719 */
2720static int svmR0InterpretInvpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t uASID)
2721{
2722 /*
2723 * Only allow 32 & 64 bits code.
2724 */
2725 DISCPUMODE enmMode = SELMGetCpuModeFromSelector(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid);
2726 if (enmMode != CPUMODE_16BIT)
2727 {
2728 RTGCPTR pbCode;
2729 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->rip, &pbCode);
2730 if (RT_SUCCESS(rc))
2731 {
2732 uint32_t cbOp;
2733 PDISCPUSTATE pDis = &pVCpu->hwaccm.s.DisState;
2734
2735 pDis->mode = enmMode;
2736 rc = EMInterpretDisasOneEx(pVM, pVCpu, pbCode, pRegFrame, pDis, &cbOp);
2737 Assert(RT_FAILURE(rc) || pDis->pCurInstr->opcode == OP_INVLPG);
2738 if (RT_SUCCESS(rc) && pDis->pCurInstr->opcode == OP_INVLPG)
2739 {
2740 Assert(cbOp == pDis->opsize);
2741 rc = svmR0InterpretInvlPg(pVCpu, pDis, pRegFrame, uASID);
2742 if (RT_SUCCESS(rc))
2743 pRegFrame->rip += cbOp; /* Move on to the next instruction. */
2744
2745 return rc;
2746 }
2747 }
2748 }
2749 return VERR_EM_INTERPRETER;
2750}
2751
2752
2753/**
2754 * Invalidates a guest page
2755 *
2756 * @returns VBox status code.
2757 * @param pVM The VM to operate on.
2758 * @param pVCpu The VM CPU to operate on.
2759 * @param GCVirt Page to invalidate
2760 */
2761VMMR0DECL(int) SVMR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt)
2762{
2763 bool fFlushPending = pVM->hwaccm.s.svm.fAlwaysFlushTLB | VMCPU_FF_ISSET(pVCpu, VMCPU_FF_TLB_FLUSH);
2764
2765 /* Skip it if a TLB flush is already pending. */
2766 if (!fFlushPending)
2767 {
2768 SVM_VMCB *pVMCB;
2769
2770 Log2(("SVMR0InvalidatePage %RGv\n", GCVirt));
2771 AssertReturn(pVM, VERR_INVALID_PARAMETER);
2772 Assert(pVM->hwaccm.s.svm.fSupported);
2773
2774 pVMCB = (SVM_VMCB *)pVCpu->hwaccm.s.svm.pVMCB;
2775 AssertMsgReturn(pVMCB, ("Invalid pVMCB\n"), VERR_EM_INTERNAL_ERROR);
2776
2777#if HC_ARCH_BITS == 32
2778 /* If we get a flush in 64 bits guest mode, then force a full TLB flush. Invlpga takes only 32 bits addresses. */
2779 if (CPUMIsGuestInLongMode(pVCpu))
2780 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2781 else
2782#endif
2783 SVMR0InvlpgA(GCVirt, pVMCB->ctrl.TLBCtrl.n.u32ASID);
2784 }
2785 return VINF_SUCCESS;
2786}
2787
2788
2789#if 0 /* obsolete, but left here for clarification. */
2790/**
2791 * Invalidates a guest page by physical address
2792 *
2793 * @returns VBox status code.
2794 * @param pVM The VM to operate on.
2795 * @param pVCpu The VM CPU to operate on.
2796 * @param GCPhys Page to invalidate
2797 */
2798VMMR0DECL(int) SVMR0InvalidatePhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
2799{
2800 Assert(pVM->hwaccm.s.fNestedPaging);
2801 /* invlpga only invalidates TLB entries for guest virtual addresses; we have no choice but to force a TLB flush here. */
2802 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
2803 STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushTLBInvlpga);
2804 return VINF_SUCCESS;
2805}
2806#endif
2807
2808#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
2809/**
2810 * Prepares for and executes VMRUN (64 bits guests from a 32 bits hosts).
2811 *
2812 * @returns VBox status code.
2813 * @param pVMCBHostPhys Physical address of host VMCB.
2814 * @param pVMCBPhys Physical address of the VMCB.
2815 * @param pCtx Guest context.
2816 * @param pVM The VM to operate on.
2817 * @param pVCpu The VMCPU to operate on.
2818 */
2819DECLASM(int) SVMR0VMSwitcherRun64(RTHCPHYS pVMCBHostPhys, RTHCPHYS pVMCBPhys, PCPUMCTX pCtx, PVM pVM, PVMCPU pVCpu)
2820{
2821 uint32_t aParam[4];
2822
2823 aParam[0] = (uint32_t)(pVMCBHostPhys); /* Param 1: pVMCBHostPhys - Lo. */
2824 aParam[1] = (uint32_t)(pVMCBHostPhys >> 32); /* Param 1: pVMCBHostPhys - Hi. */
2825 aParam[2] = (uint32_t)(pVMCBPhys); /* Param 2: pVMCBPhys - Lo. */
2826 aParam[3] = (uint32_t)(pVMCBPhys >> 32); /* Param 2: pVMCBPhys - Hi. */
2827
2828 return SVMR0Execute64BitsHandler(pVM, pVCpu, pCtx, pVM->hwaccm.s.pfnSVMGCVMRun64, 4, &aParam[0]);
2829}
2830
2831/**
2832 * Executes the specified handler in 64 mode
2833 *
2834 * @returns VBox status code.
2835 * @param pVM The VM to operate on.
2836 * @param pVCpu The VMCPU to operate on.
2837 * @param pCtx Guest context
2838 * @param pfnHandler RC handler
2839 * @param cbParam Number of parameters
2840 * @param paParam Array of 32 bits parameters
2841 */
2842VMMR0DECL(int) SVMR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTRCPTR pfnHandler, uint32_t cbParam, uint32_t *paParam)
2843{
2844 int rc;
2845 RTHCUINTREG uOldEFlags;
2846
2847 /* @todo This code is not guest SMP safe (hyper stack and switchers) */
2848 AssertReturn(pVM->cCpus == 1, VERR_TOO_MANY_CPUS);
2849 Assert(pfnHandler);
2850
2851 /* Disable interrupts. */
2852 uOldEFlags = ASMIntDisableFlags();
2853
2854 CPUMSetHyperESP(pVCpu, VMMGetStackRC(pVM));
2855 CPUMSetHyperEIP(pVCpu, pfnHandler);
2856 for (int i=(int)cbParam-1;i>=0;i--)
2857 CPUMPushHyper(pVCpu, paParam[i]);
2858
2859 STAM_PROFILE_ADV_START(&pVCpu->hwaccm.s.StatWorldSwitch3264, z);
2860 /* Call switcher. */
2861 rc = pVM->hwaccm.s.pfnHost32ToGuest64R0(pVM);
2862 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatWorldSwitch3264, z);
2863
2864 ASMSetFlags(uOldEFlags);
2865 return rc;
2866}
2867
2868#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) */
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