VirtualBox

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

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

Nested paging updates. Extra paging mode added to prevent illegal changes to the shadow page table.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 74.1 KB
Line 
1/* $Id: HWSVMR0.cpp 9021 2008-05-21 14:38:13Z 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 "HWACCMInternal.h"
29#include <VBox/vm.h>
30#include <VBox/x86.h>
31#include <VBox/hwacc_svm.h>
32#include <VBox/pgm.h>
33#include <VBox/pdm.h>
34#include <VBox/err.h>
35#include <VBox/log.h>
36#include <VBox/selm.h>
37#include <VBox/iom.h>
38#include <VBox/dis.h>
39#include <VBox/dbgf.h>
40#include <VBox/disopcode.h>
41#include <iprt/param.h>
42#include <iprt/assert.h>
43#include <iprt/asm.h>
44#include <iprt/cpuset.h>
45#include <iprt/mp.h>
46#include "HWSVMR0.h"
47
48static int SVMR0InterpretInvpg(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uASID);
49
50/**
51 * Sets up and activates AMD-V on the current CPU
52 *
53 * @returns VBox status code.
54 * @param pCpu CPU info struct
55 * @param pVM The VM to operate on.
56 * @param pvPageCpu Pointer to the global cpu page
57 * @param pPageCpuPhys Physical address of the global cpu page
58 */
59HWACCMR0DECL(int) SVMR0EnableCpu(PHWACCM_CPUINFO pCpu, PVM pVM, void *pvPageCpu, RTHCPHYS pPageCpuPhys)
60{
61 AssertReturn(pPageCpuPhys, VERR_INVALID_PARAMETER);
62 AssertReturn(pVM, VERR_INVALID_PARAMETER);
63 AssertReturn(pvPageCpu, VERR_INVALID_PARAMETER);
64
65 /* We must turn on AMD-V and setup the host state physical address, as those MSRs are per-cpu/core. */
66
67#ifdef LOG_ENABLED
68 SUPR0Printf("SVMR0EnableCpu cpu %d page (%x) %x\n", pCpu->idCpu, pvPageCpu, (uint32_t)pPageCpuPhys);
69#endif
70
71 /* Turn on AMD-V in the EFER MSR. */
72 uint64_t val = ASMRdMsr(MSR_K6_EFER);
73 if (!(val & MSR_K6_EFER_SVME))
74 ASMWrMsr(MSR_K6_EFER, val | MSR_K6_EFER_SVME);
75
76 /* Write the physical page address where the CPU will store the host state while executing the VM. */
77 ASMWrMsr(MSR_K8_VM_HSAVE_PA, pPageCpuPhys);
78
79 pCpu->uCurrentASID = 0; /* we'll aways increment this the first time (host uses ASID 0) */
80 pCpu->cTLBFlushes = 0;
81 return VINF_SUCCESS;
82}
83
84/**
85 * Deactivates AMD-V on the current CPU
86 *
87 * @returns VBox status code.
88 * @param pCpu CPU info struct
89 * @param pvPageCpu Pointer to the global cpu page
90 * @param pPageCpuPhys Physical address of the global cpu page
91 */
92HWACCMR0DECL(int) SVMR0DisableCpu(PHWACCM_CPUINFO pCpu, void *pvPageCpu, RTHCPHYS pPageCpuPhys)
93{
94 AssertReturn(pPageCpuPhys, VERR_INVALID_PARAMETER);
95 AssertReturn(pvPageCpu, VERR_INVALID_PARAMETER);
96
97#ifdef LOG_ENABLED
98 SUPR0Printf("SVMR0DisableCpu cpu %d\n", pCpu->idCpu);
99#endif
100
101 /* Turn off AMD-V in the EFER MSR. */
102 uint64_t val = ASMRdMsr(MSR_K6_EFER);
103 ASMWrMsr(MSR_K6_EFER, val & ~MSR_K6_EFER_SVME);
104
105 /* Invalidate host state physical address. */
106 ASMWrMsr(MSR_K8_VM_HSAVE_PA, 0);
107 pCpu->uCurrentASID = 0;
108
109 return VINF_SUCCESS;
110}
111
112/**
113 * Does Ring-0 per VM AMD-V init.
114 *
115 * @returns VBox status code.
116 * @param pVM The VM to operate on.
117 */
118HWACCMR0DECL(int) SVMR0InitVM(PVM pVM)
119{
120 int rc;
121
122 /* Allocate one page for the VM control block (VMCB). */
123 rc = RTR0MemObjAllocCont(&pVM->hwaccm.s.svm.pMemObjVMCB, 1 << PAGE_SHIFT, true /* executable R0 mapping */);
124 if (RT_FAILURE(rc))
125 return rc;
126
127 pVM->hwaccm.s.svm.pVMCB = RTR0MemObjAddress(pVM->hwaccm.s.svm.pMemObjVMCB);
128 pVM->hwaccm.s.svm.pVMCBPhys = RTR0MemObjGetPagePhysAddr(pVM->hwaccm.s.svm.pMemObjVMCB, 0);
129 ASMMemZero32(pVM->hwaccm.s.svm.pVMCB, PAGE_SIZE);
130
131 /* Allocate one page for the host context */
132 rc = RTR0MemObjAllocCont(&pVM->hwaccm.s.svm.pMemObjVMCBHost, 1 << PAGE_SHIFT, true /* executable R0 mapping */);
133 if (RT_FAILURE(rc))
134 return rc;
135
136 pVM->hwaccm.s.svm.pVMCBHost = RTR0MemObjAddress(pVM->hwaccm.s.svm.pMemObjVMCBHost);
137 pVM->hwaccm.s.svm.pVMCBHostPhys = RTR0MemObjGetPagePhysAddr(pVM->hwaccm.s.svm.pMemObjVMCBHost, 0);
138 ASMMemZero32(pVM->hwaccm.s.svm.pVMCBHost, PAGE_SIZE);
139
140 /* Allocate 12 KB for the IO bitmap (doesn't seem to be a way to convince SVM not to use it) */
141 rc = RTR0MemObjAllocCont(&pVM->hwaccm.s.svm.pMemObjIOBitmap, 3 << PAGE_SHIFT, true /* executable R0 mapping */);
142 if (RT_FAILURE(rc))
143 return rc;
144
145 pVM->hwaccm.s.svm.pIOBitmap = RTR0MemObjAddress(pVM->hwaccm.s.svm.pMemObjIOBitmap);
146 pVM->hwaccm.s.svm.pIOBitmapPhys = RTR0MemObjGetPagePhysAddr(pVM->hwaccm.s.svm.pMemObjIOBitmap, 0);
147 /* Set all bits to intercept all IO accesses. */
148 ASMMemFill32(pVM->hwaccm.s.svm.pIOBitmap, PAGE_SIZE*3, 0xffffffff);
149
150 /* Allocate 8 KB for the MSR bitmap (doesn't seem to be a way to convince SVM not to use it) */
151 rc = RTR0MemObjAllocCont(&pVM->hwaccm.s.svm.pMemObjMSRBitmap, 2 << PAGE_SHIFT, true /* executable R0 mapping */);
152 if (RT_FAILURE(rc))
153 return rc;
154
155 pVM->hwaccm.s.svm.pMSRBitmap = RTR0MemObjAddress(pVM->hwaccm.s.svm.pMemObjMSRBitmap);
156 pVM->hwaccm.s.svm.pMSRBitmapPhys = RTR0MemObjGetPagePhysAddr(pVM->hwaccm.s.svm.pMemObjMSRBitmap, 0);
157 /* Set all bits to intercept all MSR accesses. */
158 ASMMemFill32(pVM->hwaccm.s.svm.pMSRBitmap, PAGE_SIZE*2, 0xffffffff);
159
160 /* Erratum 170 which requires a forced TLB flush for each world switch:
161 * See http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/33610.pdf
162 *
163 * All BH-G1/2 and DH-G1/2 models include a fix:
164 * Athlon X2: 0x6b 1/2
165 * 0x68 1/2
166 * Athlon 64: 0x7f 1
167 * 0x6f 2
168 * Sempron: 0x7f 1/2
169 * 0x6f 2
170 * 0x6c 2
171 * 0x7c 2
172 * Turion 64: 0x68 2
173 *
174 */
175 uint32_t u32Dummy;
176 uint32_t u32Version, u32Family, u32Model, u32Stepping, u32BaseFamily;
177 ASMCpuId(1, &u32Version, &u32Dummy, &u32Dummy, &u32Dummy);
178 u32BaseFamily= (u32Version >> 8) & 0xf;
179 u32Family = u32BaseFamily + (u32BaseFamily == 0xf ? ((u32Version >> 20) & 0x7f) : 0);
180 u32Model = ((u32Version >> 4) & 0xf);
181 u32Model = u32Model | ((u32BaseFamily == 0xf ? (u32Version >> 16) & 0x0f : 0) << 4);
182 u32Stepping = u32Version & 0xf;
183 if ( u32Family == 0xf
184 && !((u32Model == 0x68 || u32Model == 0x6b || u32Model == 0x7f) && u32Stepping >= 1)
185 && !((u32Model == 0x6f || u32Model == 0x6c || u32Model == 0x7c) && u32Stepping >= 2))
186 {
187 Log(("SVMR0InitVM: AMD cpu with erratum 170 family %x model %x stepping %x\n", u32Family, u32Model, u32Stepping));
188 pVM->hwaccm.s.svm.fAlwaysFlushTLB = true;
189 }
190
191 /* Invalidate the last cpu we were running on. */
192 pVM->hwaccm.s.svm.idLastCpu = NIL_RTCPUID;
193 return VINF_SUCCESS;
194}
195
196/**
197 * Does Ring-0 per VM AMD-V termination.
198 *
199 * @returns VBox status code.
200 * @param pVM The VM to operate on.
201 */
202HWACCMR0DECL(int) SVMR0TermVM(PVM pVM)
203{
204 if (pVM->hwaccm.s.svm.pMemObjVMCB)
205 {
206 RTR0MemObjFree(pVM->hwaccm.s.svm.pMemObjVMCB, false);
207 pVM->hwaccm.s.svm.pVMCB = 0;
208 pVM->hwaccm.s.svm.pVMCBPhys = 0;
209 pVM->hwaccm.s.svm.pMemObjVMCB = 0;
210 }
211 if (pVM->hwaccm.s.svm.pMemObjVMCBHost)
212 {
213 RTR0MemObjFree(pVM->hwaccm.s.svm.pMemObjVMCBHost, false);
214 pVM->hwaccm.s.svm.pVMCBHost = 0;
215 pVM->hwaccm.s.svm.pVMCBHostPhys = 0;
216 pVM->hwaccm.s.svm.pMemObjVMCBHost = 0;
217 }
218 if (pVM->hwaccm.s.svm.pMemObjIOBitmap)
219 {
220 RTR0MemObjFree(pVM->hwaccm.s.svm.pMemObjIOBitmap, false);
221 pVM->hwaccm.s.svm.pIOBitmap = 0;
222 pVM->hwaccm.s.svm.pIOBitmapPhys = 0;
223 pVM->hwaccm.s.svm.pMemObjIOBitmap = 0;
224 }
225 if (pVM->hwaccm.s.svm.pMemObjMSRBitmap)
226 {
227 RTR0MemObjFree(pVM->hwaccm.s.svm.pMemObjMSRBitmap, false);
228 pVM->hwaccm.s.svm.pMSRBitmap = 0;
229 pVM->hwaccm.s.svm.pMSRBitmapPhys = 0;
230 pVM->hwaccm.s.svm.pMemObjMSRBitmap = 0;
231 }
232 return VINF_SUCCESS;
233}
234
235/**
236 * Sets up AMD-V for the specified VM
237 *
238 * @returns VBox status code.
239 * @param pVM The VM to operate on.
240 */
241HWACCMR0DECL(int) SVMR0SetupVM(PVM pVM)
242{
243 int rc = VINF_SUCCESS;
244 SVM_VMCB *pVMCB;
245
246 AssertReturn(pVM, VERR_INVALID_PARAMETER);
247
248 Assert(pVM->hwaccm.s.svm.fSupported);
249
250 pVMCB = (SVM_VMCB *)pVM->hwaccm.s.svm.pVMCB;
251 AssertMsgReturn(pVMCB, ("Invalid pVMCB\n"), VERR_EM_INTERNAL_ERROR);
252
253 /* Program the control fields. Most of them never have to be changed again. */
254 /* CR0/3/4 reads must be intercepted, our shadow values are not necessarily the same as the guest's. */
255 /* Note: CR8 reads will refer to V_TPR, so no need to catch them. */
256 /** @note CR0 & CR4 can be safely read when guest and shadow copies are identical. */
257 if (!pVM->hwaccm.s.fNestedPaging)
258 pVMCB->ctrl.u16InterceptRdCRx = RT_BIT(0) | RT_BIT(3) | RT_BIT(4);
259 else
260 pVMCB->ctrl.u16InterceptRdCRx = RT_BIT(0);
261
262 /*
263 * CR0/3/4 writes must be intercepted for obvious reasons.
264 */
265 if (!pVM->hwaccm.s.fNestedPaging)
266 pVMCB->ctrl.u16InterceptWrCRx = RT_BIT(0) | RT_BIT(3) | RT_BIT(4) | RT_BIT(8);
267 else
268 pVMCB->ctrl.u16InterceptWrCRx = RT_BIT(0) | RT_BIT(8);
269
270 /* Intercept all DRx reads and writes. */
271 pVMCB->ctrl.u16InterceptRdDRx = RT_BIT(0) | RT_BIT(1) | RT_BIT(2) | RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(6) | RT_BIT(7);
272 pVMCB->ctrl.u16InterceptWrDRx = RT_BIT(0) | RT_BIT(1) | RT_BIT(2) | RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(6) | RT_BIT(7);
273
274 /* Currently we don't care about DRx reads or writes. DRx registers are trashed.
275 * All breakpoints are automatically cleared when the VM exits.
276 */
277
278 pVMCB->ctrl.u32InterceptException = HWACCM_SVM_TRAP_MASK;
279 if (pVM->hwaccm.s.fNestedPaging)
280 pVMCB->ctrl.u32InterceptException &= ~RT_BIT(14); /* no longer need to intercept #PF. */
281
282 pVMCB->ctrl.u32InterceptCtrl1 = SVM_CTRL1_INTERCEPT_INTR
283 | SVM_CTRL1_INTERCEPT_VINTR
284 | SVM_CTRL1_INTERCEPT_NMI
285 | SVM_CTRL1_INTERCEPT_SMI
286 | SVM_CTRL1_INTERCEPT_INIT
287 | SVM_CTRL1_INTERCEPT_RDPMC
288 | SVM_CTRL1_INTERCEPT_CPUID
289 | SVM_CTRL1_INTERCEPT_RSM
290 | SVM_CTRL1_INTERCEPT_HLT
291 | SVM_CTRL1_INTERCEPT_INOUT_BITMAP
292 | SVM_CTRL1_INTERCEPT_MSR_SHADOW
293 | SVM_CTRL1_INTERCEPT_INVLPG
294 | SVM_CTRL1_INTERCEPT_INVLPGA /* AMD only */
295 | SVM_CTRL1_INTERCEPT_TASK_SWITCH
296 | SVM_CTRL1_INTERCEPT_SHUTDOWN /* fatal */
297 | SVM_CTRL1_INTERCEPT_FERR_FREEZE; /* Legacy FPU FERR handling. */
298 ;
299 /* With nested paging we don't care about invlpg anymore. */
300 if (pVM->hwaccm.s.fNestedPaging)
301 pVMCB->ctrl.u32InterceptCtrl1 &= ~SVM_CTRL1_INTERCEPT_INVLPG;
302
303 pVMCB->ctrl.u32InterceptCtrl2 = SVM_CTRL2_INTERCEPT_VMRUN /* required */
304 | SVM_CTRL2_INTERCEPT_VMMCALL
305 | SVM_CTRL2_INTERCEPT_VMLOAD
306 | SVM_CTRL2_INTERCEPT_VMSAVE
307 | SVM_CTRL2_INTERCEPT_STGI
308 | SVM_CTRL2_INTERCEPT_CLGI
309 | SVM_CTRL2_INTERCEPT_SKINIT
310 | SVM_CTRL2_INTERCEPT_RDTSCP /* AMD only; we don't support this one */
311 | SVM_CTRL2_INTERCEPT_WBINVD
312 | SVM_CTRL2_INTERCEPT_MWAIT_UNCOND; /* don't execute mwait or else we'll idle inside the guest (host thinks the cpu load is high) */
313 ;
314 Log(("pVMCB->ctrl.u32InterceptException = %x\n", pVMCB->ctrl.u32InterceptException));
315 Log(("pVMCB->ctrl.u32InterceptCtrl1 = %x\n", pVMCB->ctrl.u32InterceptCtrl1));
316 Log(("pVMCB->ctrl.u32InterceptCtrl2 = %x\n", pVMCB->ctrl.u32InterceptCtrl2));
317
318 /* Virtualize masking of INTR interrupts. (reads/writes from/to CR8 go to the V_TPR register) */
319 pVMCB->ctrl.IntCtrl.n.u1VIrqMasking = 1;
320
321 /* Set IO and MSR bitmap addresses. */
322 pVMCB->ctrl.u64IOPMPhysAddr = pVM->hwaccm.s.svm.pIOBitmapPhys;
323 pVMCB->ctrl.u64MSRPMPhysAddr = pVM->hwaccm.s.svm.pMSRBitmapPhys;
324
325 /* No LBR virtualization. */
326 pVMCB->ctrl.u64LBRVirt = 0;
327
328 /** The ASID must start at 1; the host uses 0. */
329 pVMCB->ctrl.TLBCtrl.n.u32ASID = 1;
330
331 return rc;
332}
333
334
335/**
336 * Injects an event (trap or external interrupt)
337 *
338 * @param pVM The VM to operate on.
339 * @param pVMCB SVM control block
340 * @param pCtx CPU Context
341 * @param pIntInfo SVM interrupt info
342 */
343inline void SVMR0InjectEvent(PVM pVM, SVM_VMCB *pVMCB, CPUMCTX *pCtx, SVM_EVENT* pEvent)
344{
345#ifdef VBOX_STRICT
346 if (pEvent->n.u8Vector == 0xE)
347 Log(("SVM: Inject int %d at %VGv error code=%08x CR2=%08x intInfo=%08x\n", pEvent->n.u8Vector, pCtx->eip, pEvent->n.u32ErrorCode, pCtx->cr2, pEvent->au64[0]));
348 else
349 if (pEvent->n.u8Vector < 0x20)
350 Log(("SVM: Inject int %d at %VGv error code=%08x\n", pEvent->n.u8Vector, pCtx->eip, pEvent->n.u32ErrorCode));
351 else
352 {
353 Log(("INJ-EI: %x at %VGv\n", pEvent->n.u8Vector, pCtx->eip));
354 Assert(!VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS));
355 Assert(pCtx->eflags.u32 & X86_EFL_IF);
356 }
357#endif
358
359 /* Set event injection state. */
360 pVMCB->ctrl.EventInject.au64[0] = pEvent->au64[0];
361}
362
363
364/**
365 * Checks for pending guest interrupts and injects them
366 *
367 * @returns VBox status code.
368 * @param pVM The VM to operate on.
369 * @param pVMCB SVM control block
370 * @param pCtx CPU Context
371 */
372static int SVMR0CheckPendingInterrupt(PVM pVM, SVM_VMCB *pVMCB, CPUMCTX *pCtx)
373{
374 int rc;
375
376 /* Dispatch any pending interrupts. (injected before, but a VM exit occurred prematurely) */
377 if (pVM->hwaccm.s.Event.fPending)
378 {
379 SVM_EVENT Event;
380
381 Log(("Reinjecting event %08x %08x at %VGv\n", pVM->hwaccm.s.Event.intInfo, pVM->hwaccm.s.Event.errCode, pCtx->eip));
382 STAM_COUNTER_INC(&pVM->hwaccm.s.StatIntReinject);
383 Event.au64[0] = pVM->hwaccm.s.Event.intInfo;
384 SVMR0InjectEvent(pVM, pVMCB, pCtx, &Event);
385
386 pVM->hwaccm.s.Event.fPending = false;
387 return VINF_SUCCESS;
388 }
389
390 /* When external interrupts are pending, we should exit the VM when IF is set. */
391 if ( !TRPMHasTrap(pVM)
392 && VM_FF_ISPENDING(pVM, (VM_FF_INTERRUPT_APIC|VM_FF_INTERRUPT_PIC)))
393 {
394 if (!(pCtx->eflags.u32 & X86_EFL_IF))
395 {
396 if (!pVMCB->ctrl.IntCtrl.n.u1VIrqValid)
397 {
398 Log(("Enable irq window exit!\n"));
399 /** @todo use virtual interrupt method to inject a pending irq; dispatched as soon as guest.IF is set. */
400 pVMCB->ctrl.u32InterceptCtrl1 |= SVM_CTRL1_INTERCEPT_VINTR;
401 pVMCB->ctrl.IntCtrl.n.u1VIrqValid = 1;
402 pVMCB->ctrl.IntCtrl.n.u1IgnoreTPR = 1; /* ignore the priority in the TPR; just deliver it */
403 pVMCB->ctrl.IntCtrl.n.u8VIrqVector = 0; /* don't care */
404 }
405 }
406 else
407 if (!VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS))
408 {
409 uint8_t u8Interrupt;
410
411 rc = PDMGetInterrupt(pVM, &u8Interrupt);
412 Log(("Dispatch interrupt: u8Interrupt=%x (%d) rc=%Vrc\n", u8Interrupt, u8Interrupt, rc));
413 if (VBOX_SUCCESS(rc))
414 {
415 rc = TRPMAssertTrap(pVM, u8Interrupt, TRPM_HARDWARE_INT);
416 AssertRC(rc);
417 }
418 else
419 {
420 /* Can only happen in rare cases where a pending interrupt is cleared behind our back */
421 Assert(!VM_FF_ISPENDING(pVM, (VM_FF_INTERRUPT_APIC|VM_FF_INTERRUPT_PIC)));
422 STAM_COUNTER_INC(&pVM->hwaccm.s.StatSwitchGuestIrq);
423 /* Just continue */
424 }
425 }
426 else
427 Log(("Pending interrupt blocked at %VGv by VM_FF_INHIBIT_INTERRUPTS!!\n", pCtx->eip));
428 }
429
430#ifdef VBOX_STRICT
431 if (TRPMHasTrap(pVM))
432 {
433 uint8_t u8Vector;
434 rc = TRPMQueryTrapAll(pVM, &u8Vector, 0, 0, 0);
435 AssertRC(rc);
436 }
437#endif
438
439 if ( pCtx->eflags.u32 & X86_EFL_IF
440 && (!VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS))
441 && TRPMHasTrap(pVM)
442 )
443 {
444 uint8_t u8Vector;
445 int rc;
446 TRPMEVENT enmType;
447 SVM_EVENT Event;
448 uint32_t u32ErrorCode;
449
450 Event.au64[0] = 0;
451
452 /* If a new event is pending, then dispatch it now. */
453 rc = TRPMQueryTrapAll(pVM, &u8Vector, &enmType, &u32ErrorCode, 0);
454 AssertRC(rc);
455 Assert(pCtx->eflags.Bits.u1IF == 1 || enmType == TRPM_TRAP);
456 Assert(enmType != TRPM_SOFTWARE_INT);
457
458 /* Clear the pending trap. */
459 rc = TRPMResetTrap(pVM);
460 AssertRC(rc);
461
462 Event.n.u8Vector = u8Vector;
463 Event.n.u1Valid = 1;
464 Event.n.u32ErrorCode = u32ErrorCode;
465
466 if (enmType == TRPM_TRAP)
467 {
468 switch (u8Vector) {
469 case 8:
470 case 10:
471 case 11:
472 case 12:
473 case 13:
474 case 14:
475 case 17:
476 /* Valid error codes. */
477 Event.n.u1ErrorCodeValid = 1;
478 break;
479 default:
480 break;
481 }
482 if (u8Vector == X86_XCPT_NMI)
483 Event.n.u3Type = SVM_EVENT_NMI;
484 else
485 Event.n.u3Type = SVM_EVENT_EXCEPTION;
486 }
487 else
488 Event.n.u3Type = SVM_EVENT_EXTERNAL_IRQ;
489
490 STAM_COUNTER_INC(&pVM->hwaccm.s.StatIntInject);
491 SVMR0InjectEvent(pVM, pVMCB, pCtx, &Event);
492 } /* if (interrupts can be dispatched) */
493
494 return VINF_SUCCESS;
495}
496
497
498/**
499 * Loads the guest state
500 *
501 * @returns VBox status code.
502 * @param pVM The VM to operate on.
503 * @param pCtx Guest context
504 */
505HWACCMR0DECL(int) SVMR0LoadGuestState(PVM pVM, CPUMCTX *pCtx)
506{
507 RTGCUINTPTR val;
508 SVM_VMCB *pVMCB;
509
510 if (pVM == NULL)
511 return VERR_INVALID_PARAMETER;
512
513 /* Setup AMD SVM. */
514 Assert(pVM->hwaccm.s.svm.fSupported);
515
516 pVMCB = (SVM_VMCB *)pVM->hwaccm.s.svm.pVMCB;
517 AssertMsgReturn(pVMCB, ("Invalid pVMCB\n"), VERR_EM_INTERNAL_ERROR);
518
519 /* Guest CPU context: ES, CS, SS, DS, FS, GS. */
520 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_SEGMENT_REGS)
521 {
522 SVM_WRITE_SELREG(CS, cs);
523 SVM_WRITE_SELREG(SS, ss);
524 SVM_WRITE_SELREG(DS, ds);
525 SVM_WRITE_SELREG(ES, es);
526 SVM_WRITE_SELREG(FS, fs);
527 SVM_WRITE_SELREG(GS, gs);
528 }
529
530 /* Guest CPU context: LDTR. */
531 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_LDTR)
532 {
533 SVM_WRITE_SELREG(LDTR, ldtr);
534 }
535
536 /* Guest CPU context: TR. */
537 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_TR)
538 {
539 SVM_WRITE_SELREG(TR, tr);
540 }
541
542 /* Guest CPU context: GDTR. */
543 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_GDTR)
544 {
545 pVMCB->guest.GDTR.u32Limit = pCtx->gdtr.cbGdt;
546 pVMCB->guest.GDTR.u64Base = pCtx->gdtr.pGdt;
547 }
548
549 /* Guest CPU context: IDTR. */
550 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_IDTR)
551 {
552 pVMCB->guest.IDTR.u32Limit = pCtx->idtr.cbIdt;
553 pVMCB->guest.IDTR.u64Base = pCtx->idtr.pIdt;
554 }
555
556 /*
557 * Sysenter MSRs
558 */
559 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_SYSENTER_MSR)
560 {
561 pVMCB->guest.u64SysEnterCS = pCtx->SysEnter.cs;
562 pVMCB->guest.u64SysEnterEIP = pCtx->SysEnter.eip;
563 pVMCB->guest.u64SysEnterESP = pCtx->SysEnter.esp;
564 }
565
566 /* Control registers */
567 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR0)
568 {
569 val = pCtx->cr0;
570 if (CPUMIsGuestFPUStateActive(pVM) == false)
571 {
572 /* Always use #NM exceptions to load the FPU/XMM state on demand. */
573 val |= X86_CR0_TS | X86_CR0_ET | X86_CR0_NE | X86_CR0_MP;
574 }
575 else
576 {
577 Assert(pVM->hwaccm.s.svm.fResumeVM == true);
578 /** @todo check if we support the old style mess correctly. */
579 if (!(val & X86_CR0_NE))
580 {
581 Log(("Forcing X86_CR0_NE!!!\n"));
582
583 /* Also catch floating point exceptions as we need to report them to the guest in a different way. */
584 if (!pVM->hwaccm.s.fFPUOldStyleOverride)
585 {
586 pVMCB->ctrl.u32InterceptException |= RT_BIT(16);
587 pVM->hwaccm.s.fFPUOldStyleOverride = true;
588 }
589 }
590 val |= X86_CR0_NE; /* always turn on the native mechanism to report FPU errors (old style uses interrupts) */
591 }
592 /* Always enable caching. */
593 val &= ~(X86_CR0_CD|X86_CR0_NW);
594
595 /* Note: WP is not relevant in nested paging mode as we catch accesses on the (host) physical level. */
596 /* Note: In nested paging mode the guest is allowed to run with paging disabled; the guest physical to host physical translation will remain active. */
597 if (!pVM->hwaccm.s.fNestedPaging)
598 {
599 val |= X86_CR0_PG; /* Paging is always enabled; even when the guest is running in real mode or PE without paging. */
600 val |= X86_CR0_WP; /* Must set this as we rely on protect various pages and supervisor writes must be caught. */
601 }
602 pVMCB->guest.u64CR0 = val;
603 }
604 /* CR2 as well */
605 pVMCB->guest.u64CR2 = pCtx->cr2;
606
607 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR3)
608 {
609 /* Save our shadow CR3 register. */
610 if (pVM->hwaccm.s.fNestedPaging)
611 {
612 pVMCB->ctrl.u64NestedPagingCR3 = PGMGetHyperCR3(pVM);
613 pVMCB->guest.u64CR3 = pCtx->cr3;
614 }
615 else
616 pVMCB->guest.u64CR3 = PGMGetHyperCR3(pVM);
617 }
618
619 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_CR4)
620 {
621 val = pCtx->cr4;
622 if (!pVM->hwaccm.s.fNestedPaging)
623 {
624 switch(pVM->hwaccm.s.enmShadowMode)
625 {
626 case PGMMODE_REAL:
627 case PGMMODE_PROTECTED: /* Protected mode, no paging. */
628 AssertFailed();
629 return VERR_PGM_UNSUPPORTED_HOST_PAGING_MODE;
630
631 case PGMMODE_32_BIT: /* 32-bit paging. */
632 break;
633
634 case PGMMODE_PAE: /* PAE paging. */
635 case PGMMODE_PAE_NX: /* PAE paging with NX enabled. */
636 /** @todo use normal 32 bits paging */
637 val |= X86_CR4_PAE;
638 break;
639
640 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
641 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
642 AssertFailed();
643 return VERR_PGM_UNSUPPORTED_HOST_PAGING_MODE;
644
645 default: /* shut up gcc */
646 AssertFailed();
647 return VERR_PGM_UNSUPPORTED_HOST_PAGING_MODE;
648 }
649 }
650 pVMCB->guest.u64CR4 = val;
651 }
652
653 /* Debug registers. */
654 if (pVM->hwaccm.s.fContextUseFlags & HWACCM_CHANGED_GUEST_DEBUG)
655 {
656 /** @todo DR0-6 */
657 val = pCtx->dr7;
658 val &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* must be zero */
659 val |= 0x400; /* must be one */
660#ifdef VBOX_STRICT
661 val = 0x400;
662#endif
663 pVMCB->guest.u64DR7 = val;
664
665 pVMCB->guest.u64DR6 = pCtx->dr6;
666 }
667
668 /* EIP, ESP and EFLAGS */
669 pVMCB->guest.u64RIP = pCtx->eip;
670 pVMCB->guest.u64RSP = pCtx->esp;
671 pVMCB->guest.u64RFlags = pCtx->eflags.u32;
672
673 /* Set CPL */
674 pVMCB->guest.u8CPL = pCtx->ssHid.Attr.n.u2Dpl;
675
676 /* RAX/EAX too, as VMRUN uses RAX as an implicit parameter. */
677 pVMCB->guest.u64RAX = pCtx->eax;
678
679 /* vmrun will fail otherwise. */
680 pVMCB->guest.u64EFER = MSR_K6_EFER_SVME;
681
682 /** TSC offset. */
683 if (TMCpuTickCanUseRealTSC(pVM, &pVMCB->ctrl.u64TSCOffset))
684 pVMCB->ctrl.u32InterceptCtrl1 &= ~SVM_CTRL1_INTERCEPT_RDTSC;
685 else
686 pVMCB->ctrl.u32InterceptCtrl1 |= SVM_CTRL1_INTERCEPT_RDTSC;
687
688 /** @todo 64 bits stuff (?):
689 * - STAR
690 * - LSTAR
691 * - CSTAR
692 * - SFMASK
693 * - KernelGSBase
694 */
695
696#ifdef DEBUG
697 /* Intercept X86_XCPT_DB if stepping is enabled */
698 if (DBGFIsStepping(pVM))
699 pVMCB->ctrl.u32InterceptException |= RT_BIT(1);
700 else
701 pVMCB->ctrl.u32InterceptException &= ~RT_BIT(1);
702#endif
703
704 /* Done. */
705 pVM->hwaccm.s.fContextUseFlags &= ~HWACCM_CHANGED_ALL_GUEST;
706
707 return VINF_SUCCESS;
708}
709
710
711/**
712 * Runs guest code in an SVM VM.
713 *
714 * @todo This can be much more efficient, when we only sync that which has actually changed. (this is the first attempt only)
715 *
716 * @returns VBox status code.
717 * @param pVM The VM to operate on.
718 * @param pCtx Guest context
719 * @param pCpu CPU info struct
720 */
721HWACCMR0DECL(int) SVMR0RunGuestCode(PVM pVM, CPUMCTX *pCtx, PHWACCM_CPUINFO pCpu)
722{
723 int rc = VINF_SUCCESS;
724 uint64_t exitCode = (uint64_t)SVM_EXIT_INVALID;
725 SVM_VMCB *pVMCB;
726 bool fGuestStateSynced = false;
727 unsigned cResume = 0;
728
729 STAM_PROFILE_ADV_START(&pVM->hwaccm.s.StatEntry, x);
730
731 Assert(!pVM->hwaccm.s.fNestedPaging);
732 AssertReturn(pCpu->fSVMConfigured, VERR_EM_INTERNAL_ERROR);
733
734 pVMCB = (SVM_VMCB *)pVM->hwaccm.s.svm.pVMCB;
735 AssertMsgReturn(pVMCB, ("Invalid pVMCB\n"), VERR_EM_INTERNAL_ERROR);
736
737 /* We can jump to this point to resume execution after determining that a VM-exit is innocent.
738 */
739ResumeExecution:
740 /* Safety precaution; looping for too long here can have a very bad effect on the host */
741 if (++cResume > HWACCM_MAX_RESUME_LOOPS)
742 {
743 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitMaxResume);
744 rc = VINF_EM_RAW_INTERRUPT;
745 goto end;
746 }
747
748 /* Check for irq inhibition due to instruction fusing (sti, mov ss). */
749 if (VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS))
750 {
751 Log(("VM_FF_INHIBIT_INTERRUPTS at %VGv successor %VGv\n", pCtx->eip, EMGetInhibitInterruptsPC(pVM)));
752 if (pCtx->eip != EMGetInhibitInterruptsPC(pVM))
753 {
754 /** @note we intentionally don't clear VM_FF_INHIBIT_INTERRUPTS here.
755 * Before we are able to execute this instruction in raw mode (iret to guest code) an external interrupt might
756 * force a world switch again. Possibly allowing a guest interrupt to be dispatched in the process. This could
757 * break the guest. Sounds very unlikely, but such timing sensitive problem are not as rare as you might think.
758 */
759 VM_FF_CLEAR(pVM, VM_FF_INHIBIT_INTERRUPTS);
760 /* Irq inhibition is no longer active; clear the corresponding SVM state. */
761 pVMCB->ctrl.u64IntShadow = 0;
762 }
763 }
764 else
765 {
766 /* Irq inhibition is no longer active; clear the corresponding SVM state. */
767 pVMCB->ctrl.u64IntShadow = 0;
768 }
769
770 /* Check for pending actions that force us to go back to ring 3. */
771#ifdef DEBUG
772 /* Intercept X86_XCPT_DB if stepping is enabled */
773 if (!DBGFIsStepping(pVM))
774#endif
775 {
776 if (VM_FF_ISPENDING(pVM, VM_FF_TO_R3 | VM_FF_TIMER))
777 {
778 VM_FF_CLEAR(pVM, VM_FF_TO_R3);
779 STAM_COUNTER_INC(&pVM->hwaccm.s.StatSwitchToR3);
780 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatEntry, x);
781 rc = VINF_EM_RAW_TO_R3;
782 goto end;
783 }
784 }
785
786 /* Pending request packets might contain actions that need immediate attention, such as pending hardware interrupts. */
787 if (VM_FF_ISPENDING(pVM, VM_FF_REQUEST))
788 {
789 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatEntry, x);
790 rc = VINF_EM_PENDING_REQUEST;
791 goto end;
792 }
793
794 /* When external interrupts are pending, we should exit the VM when IF is set. */
795 /** @note *after* VM_FF_INHIBIT_INTERRUPTS check!!! */
796 rc = SVMR0CheckPendingInterrupt(pVM, pVMCB, pCtx);
797 if (VBOX_FAILURE(rc))
798 {
799 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatEntry, x);
800 goto end;
801 }
802
803 /* Load the guest state */
804 rc = SVMR0LoadGuestState(pVM, pCtx);
805 if (rc != VINF_SUCCESS)
806 {
807 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatEntry, x);
808 goto end;
809 }
810 fGuestStateSynced = true;
811
812 /* All done! Let's start VM execution. */
813 STAM_PROFILE_ADV_START(&pVM->hwaccm.s.StatInGC, x);
814
815 /* Enable nested paging if necessary (disabled each time after #VMEXIT). */
816 pVMCB->ctrl.NestedPaging.n.u1NestedPaging = pVM->hwaccm.s.fNestedPaging;
817
818 /* Force a TLB flush for the first world switch if the current cpu differs from the one we ran on last. */
819 if (!pVM->hwaccm.s.svm.fResumeVM)
820 {
821 if ( pVM->hwaccm.s.svm.idLastCpu != pCpu->idCpu
822 /* 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. */
823 || pVM->hwaccm.s.svm.cTLBFlushes != pCpu->cTLBFlushes)
824 {
825 /* Force a TLB flush on VM entry. */
826 pVM->hwaccm.s.svm.fForceTLBFlush = true;
827 }
828 pVM->hwaccm.s.svm.idLastCpu = pCpu->idCpu;
829 }
830
831 /* 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). */
832 if ( pVM->hwaccm.s.svm.fForceTLBFlush
833 && !pVM->hwaccm.s.svm.fAlwaysFlushTLB)
834 {
835 if (++pCpu->uCurrentASID >= pVM->hwaccm.s.svm.u32MaxASID)
836 {
837 pCpu->uCurrentASID = 1; /* start at 1; host uses 0 */
838 pVMCB->ctrl.TLBCtrl.n.u1TLBFlush = 1; /* wrap around; flush TLB */
839 pCpu->cTLBFlushes++;
840 }
841 else
842 STAM_COUNTER_INC(&pVM->hwaccm.s.StatFlushASID);
843
844 pVM->hwaccm.s.svm.cTLBFlushes = pCpu->cTLBFlushes;
845 }
846 else
847 {
848 /* We never increase uCurrentASID in the fAlwaysFlushTLB (erratum 170) case. */
849 if (!pCpu->uCurrentASID)
850 pCpu->uCurrentASID = 1;
851
852 pVMCB->ctrl.TLBCtrl.n.u1TLBFlush = pVM->hwaccm.s.svm.fForceTLBFlush;
853 }
854
855 AssertMsg(pCpu->uCurrentASID >= 1 && pCpu->uCurrentASID < pVM->hwaccm.s.svm.u32MaxASID, ("cpu%d uCurrentASID = %x\n", pCpu->idCpu, pCpu->uCurrentASID));
856 pVMCB->ctrl.TLBCtrl.n.u32ASID = pCpu->uCurrentASID;
857
858#ifdef VBOX_WITH_STATISTICS
859 if (pVMCB->ctrl.TLBCtrl.n.u1TLBFlush)
860 STAM_COUNTER_INC(&pVM->hwaccm.s.StatFlushTLBWorldSwitch);
861 else
862 STAM_COUNTER_INC(&pVM->hwaccm.s.StatNoFlushTLBWorldSwitch);
863#endif
864
865 /* In case we execute a goto ResumeExecution later on. */
866 pVM->hwaccm.s.svm.fResumeVM = true;
867 pVM->hwaccm.s.svm.fForceTLBFlush = pVM->hwaccm.s.svm.fAlwaysFlushTLB;
868
869 Assert(sizeof(pVM->hwaccm.s.svm.pVMCBPhys) == 8);
870 Assert(pVMCB->ctrl.u32InterceptCtrl2 == ( SVM_CTRL2_INTERCEPT_VMRUN /* required */
871 | SVM_CTRL2_INTERCEPT_VMMCALL
872 | SVM_CTRL2_INTERCEPT_VMLOAD
873 | SVM_CTRL2_INTERCEPT_VMSAVE
874 | SVM_CTRL2_INTERCEPT_STGI
875 | SVM_CTRL2_INTERCEPT_CLGI
876 | SVM_CTRL2_INTERCEPT_SKINIT
877 | SVM_CTRL2_INTERCEPT_RDTSCP /* AMD only; we don't support this one */
878 | SVM_CTRL2_INTERCEPT_WBINVD
879 | SVM_CTRL2_INTERCEPT_MWAIT_UNCOND /* don't execute mwait or else we'll idle inside the guest (host thinks the cpu load is high) */
880 ));
881 Assert(pVMCB->ctrl.IntCtrl.n.u1VIrqMasking);
882 Assert(pVMCB->ctrl.u64IOPMPhysAddr == pVM->hwaccm.s.svm.pIOBitmapPhys);
883 Assert(pVMCB->ctrl.u64MSRPMPhysAddr == pVM->hwaccm.s.svm.pMSRBitmapPhys);
884 Assert(pVMCB->ctrl.u64LBRVirt == 0);
885
886 SVMVMRun(pVM->hwaccm.s.svm.pVMCBHostPhys, pVM->hwaccm.s.svm.pVMCBPhys, pCtx);
887 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatInGC, x);
888
889 /**
890 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
891 * 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
892 * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
893 */
894
895 STAM_PROFILE_ADV_START(&pVM->hwaccm.s.StatExit, x);
896
897 /* Reason for the VM exit */
898 exitCode = pVMCB->ctrl.u64ExitCode;
899
900 if (exitCode == (uint64_t)SVM_EXIT_INVALID) /* Invalid guest state. */
901 {
902 HWACCMDumpRegs(pCtx);
903#ifdef DEBUG
904 Log(("ctrl.u16InterceptRdCRx %x\n", pVMCB->ctrl.u16InterceptRdCRx));
905 Log(("ctrl.u16InterceptWrCRx %x\n", pVMCB->ctrl.u16InterceptWrCRx));
906 Log(("ctrl.u16InterceptRdDRx %x\n", pVMCB->ctrl.u16InterceptRdDRx));
907 Log(("ctrl.u16InterceptWrDRx %x\n", pVMCB->ctrl.u16InterceptWrDRx));
908 Log(("ctrl.u32InterceptException %x\n", pVMCB->ctrl.u32InterceptException));
909 Log(("ctrl.u32InterceptCtrl1 %x\n", pVMCB->ctrl.u32InterceptCtrl1));
910 Log(("ctrl.u32InterceptCtrl2 %x\n", pVMCB->ctrl.u32InterceptCtrl2));
911 Log(("ctrl.u64IOPMPhysAddr %VX64\n", pVMCB->ctrl.u64IOPMPhysAddr));
912 Log(("ctrl.u64MSRPMPhysAddr %VX64\n", pVMCB->ctrl.u64MSRPMPhysAddr));
913 Log(("ctrl.u64TSCOffset %VX64\n", pVMCB->ctrl.u64TSCOffset));
914
915 Log(("ctrl.TLBCtrl.u32ASID %x\n", pVMCB->ctrl.TLBCtrl.n.u32ASID));
916 Log(("ctrl.TLBCtrl.u1TLBFlush %x\n", pVMCB->ctrl.TLBCtrl.n.u1TLBFlush));
917 Log(("ctrl.TLBCtrl.u7Reserved %x\n", pVMCB->ctrl.TLBCtrl.n.u7Reserved));
918 Log(("ctrl.TLBCtrl.u24Reserved %x\n", pVMCB->ctrl.TLBCtrl.n.u24Reserved));
919
920 Log(("ctrl.IntCtrl.u8VTPR %x\n", pVMCB->ctrl.IntCtrl.n.u8VTPR));
921 Log(("ctrl.IntCtrl.u1VIrqValid %x\n", pVMCB->ctrl.IntCtrl.n.u1VIrqValid));
922 Log(("ctrl.IntCtrl.u7Reserved %x\n", pVMCB->ctrl.IntCtrl.n.u7Reserved));
923 Log(("ctrl.IntCtrl.u4VIrqPriority %x\n", pVMCB->ctrl.IntCtrl.n.u4VIrqPriority));
924 Log(("ctrl.IntCtrl.u1IgnoreTPR %x\n", pVMCB->ctrl.IntCtrl.n.u1IgnoreTPR));
925 Log(("ctrl.IntCtrl.u3Reserved %x\n", pVMCB->ctrl.IntCtrl.n.u3Reserved));
926 Log(("ctrl.IntCtrl.u1VIrqMasking %x\n", pVMCB->ctrl.IntCtrl.n.u1VIrqMasking));
927 Log(("ctrl.IntCtrl.u7Reserved2 %x\n", pVMCB->ctrl.IntCtrl.n.u7Reserved2));
928 Log(("ctrl.IntCtrl.u8VIrqVector %x\n", pVMCB->ctrl.IntCtrl.n.u8VIrqVector));
929 Log(("ctrl.IntCtrl.u24Reserved %x\n", pVMCB->ctrl.IntCtrl.n.u24Reserved));
930
931 Log(("ctrl.u64IntShadow %VX64\n", pVMCB->ctrl.u64IntShadow));
932 Log(("ctrl.u64ExitCode %VX64\n", pVMCB->ctrl.u64ExitCode));
933 Log(("ctrl.u64ExitInfo1 %VX64\n", pVMCB->ctrl.u64ExitInfo1));
934 Log(("ctrl.u64ExitInfo2 %VX64\n", pVMCB->ctrl.u64ExitInfo2));
935 Log(("ctrl.ExitIntInfo.u8Vector %x\n", pVMCB->ctrl.ExitIntInfo.n.u8Vector));
936 Log(("ctrl.ExitIntInfo.u3Type %x\n", pVMCB->ctrl.ExitIntInfo.n.u3Type));
937 Log(("ctrl.ExitIntInfo.u1ErrorCodeValid %x\n", pVMCB->ctrl.ExitIntInfo.n.u1ErrorCodeValid));
938 Log(("ctrl.ExitIntInfo.u19Reserved %x\n", pVMCB->ctrl.ExitIntInfo.n.u19Reserved));
939 Log(("ctrl.ExitIntInfo.u1Valid %x\n", pVMCB->ctrl.ExitIntInfo.n.u1Valid));
940 Log(("ctrl.ExitIntInfo.u32ErrorCode %x\n", pVMCB->ctrl.ExitIntInfo.n.u32ErrorCode));
941 Log(("ctrl.NestedPaging %VX64\n", pVMCB->ctrl.NestedPaging.au64));
942 Log(("ctrl.EventInject.u8Vector %x\n", pVMCB->ctrl.EventInject.n.u8Vector));
943 Log(("ctrl.EventInject.u3Type %x\n", pVMCB->ctrl.EventInject.n.u3Type));
944 Log(("ctrl.EventInject.u1ErrorCodeValid %x\n", pVMCB->ctrl.EventInject.n.u1ErrorCodeValid));
945 Log(("ctrl.EventInject.u19Reserved %x\n", pVMCB->ctrl.EventInject.n.u19Reserved));
946 Log(("ctrl.EventInject.u1Valid %x\n", pVMCB->ctrl.EventInject.n.u1Valid));
947 Log(("ctrl.EventInject.u32ErrorCode %x\n", pVMCB->ctrl.EventInject.n.u32ErrorCode));
948
949 Log(("ctrl.u64NestedPagingCR3 %VX64\n", pVMCB->ctrl.u64NestedPagingCR3));
950 Log(("ctrl.u64LBRVirt %VX64\n", pVMCB->ctrl.u64LBRVirt));
951
952 Log(("guest.CS.u16Sel %04X\n", pVMCB->guest.CS.u16Sel));
953 Log(("guest.CS.u16Attr %04X\n", pVMCB->guest.CS.u16Attr));
954 Log(("guest.CS.u32Limit %X\n", pVMCB->guest.CS.u32Limit));
955 Log(("guest.CS.u64Base %VX64\n", pVMCB->guest.CS.u64Base));
956 Log(("guest.DS.u16Sel %04X\n", pVMCB->guest.DS.u16Sel));
957 Log(("guest.DS.u16Attr %04X\n", pVMCB->guest.DS.u16Attr));
958 Log(("guest.DS.u32Limit %X\n", pVMCB->guest.DS.u32Limit));
959 Log(("guest.DS.u64Base %VX64\n", pVMCB->guest.DS.u64Base));
960 Log(("guest.ES.u16Sel %04X\n", pVMCB->guest.ES.u16Sel));
961 Log(("guest.ES.u16Attr %04X\n", pVMCB->guest.ES.u16Attr));
962 Log(("guest.ES.u32Limit %X\n", pVMCB->guest.ES.u32Limit));
963 Log(("guest.ES.u64Base %VX64\n", pVMCB->guest.ES.u64Base));
964 Log(("guest.FS.u16Sel %04X\n", pVMCB->guest.FS.u16Sel));
965 Log(("guest.FS.u16Attr %04X\n", pVMCB->guest.FS.u16Attr));
966 Log(("guest.FS.u32Limit %X\n", pVMCB->guest.FS.u32Limit));
967 Log(("guest.FS.u64Base %VX64\n", pVMCB->guest.FS.u64Base));
968 Log(("guest.GS.u16Sel %04X\n", pVMCB->guest.GS.u16Sel));
969 Log(("guest.GS.u16Attr %04X\n", pVMCB->guest.GS.u16Attr));
970 Log(("guest.GS.u32Limit %X\n", pVMCB->guest.GS.u32Limit));
971 Log(("guest.GS.u64Base %VX64\n", pVMCB->guest.GS.u64Base));
972
973 Log(("guest.GDTR.u32Limit %X\n", pVMCB->guest.GDTR.u32Limit));
974 Log(("guest.GDTR.u64Base %VX64\n", pVMCB->guest.GDTR.u64Base));
975
976 Log(("guest.LDTR.u16Sel %04X\n", pVMCB->guest.LDTR.u16Sel));
977 Log(("guest.LDTR.u16Attr %04X\n", pVMCB->guest.LDTR.u16Attr));
978 Log(("guest.LDTR.u32Limit %X\n", pVMCB->guest.LDTR.u32Limit));
979 Log(("guest.LDTR.u64Base %VX64\n", pVMCB->guest.LDTR.u64Base));
980
981 Log(("guest.IDTR.u32Limit %X\n", pVMCB->guest.IDTR.u32Limit));
982 Log(("guest.IDTR.u64Base %VX64\n", pVMCB->guest.IDTR.u64Base));
983
984 Log(("guest.TR.u16Sel %04X\n", pVMCB->guest.TR.u16Sel));
985 Log(("guest.TR.u16Attr %04X\n", pVMCB->guest.TR.u16Attr));
986 Log(("guest.TR.u32Limit %X\n", pVMCB->guest.TR.u32Limit));
987 Log(("guest.TR.u64Base %VX64\n", pVMCB->guest.TR.u64Base));
988
989 Log(("guest.u8CPL %X\n", pVMCB->guest.u8CPL));
990 Log(("guest.u64CR0 %VX64\n", pVMCB->guest.u64CR0));
991 Log(("guest.u64CR2 %VX64\n", pVMCB->guest.u64CR2));
992 Log(("guest.u64CR3 %VX64\n", pVMCB->guest.u64CR3));
993 Log(("guest.u64CR4 %VX64\n", pVMCB->guest.u64CR4));
994 Log(("guest.u64DR6 %VX64\n", pVMCB->guest.u64DR6));
995 Log(("guest.u64DR7 %VX64\n", pVMCB->guest.u64DR7));
996
997 Log(("guest.u64RIP %VX64\n", pVMCB->guest.u64RIP));
998 Log(("guest.u64RSP %VX64\n", pVMCB->guest.u64RSP));
999 Log(("guest.u64RAX %VX64\n", pVMCB->guest.u64RAX));
1000 Log(("guest.u64RFlags %VX64\n", pVMCB->guest.u64RFlags));
1001
1002 Log(("guest.u64SysEnterCS %VX64\n", pVMCB->guest.u64SysEnterCS));
1003 Log(("guest.u64SysEnterEIP %VX64\n", pVMCB->guest.u64SysEnterEIP));
1004 Log(("guest.u64SysEnterESP %VX64\n", pVMCB->guest.u64SysEnterESP));
1005
1006 Log(("guest.u64EFER %VX64\n", pVMCB->guest.u64EFER));
1007 Log(("guest.u64STAR %VX64\n", pVMCB->guest.u64STAR));
1008 Log(("guest.u64LSTAR %VX64\n", pVMCB->guest.u64LSTAR));
1009 Log(("guest.u64CSTAR %VX64\n", pVMCB->guest.u64CSTAR));
1010 Log(("guest.u64SFMASK %VX64\n", pVMCB->guest.u64SFMASK));
1011 Log(("guest.u64KernelGSBase %VX64\n", pVMCB->guest.u64KernelGSBase));
1012 Log(("guest.u64GPAT %VX64\n", pVMCB->guest.u64GPAT));
1013 Log(("guest.u64DBGCTL %VX64\n", pVMCB->guest.u64DBGCTL));
1014 Log(("guest.u64BR_FROM %VX64\n", pVMCB->guest.u64BR_FROM));
1015 Log(("guest.u64BR_TO %VX64\n", pVMCB->guest.u64BR_TO));
1016 Log(("guest.u64LASTEXCPFROM %VX64\n", pVMCB->guest.u64LASTEXCPFROM));
1017 Log(("guest.u64LASTEXCPTO %VX64\n", pVMCB->guest.u64LASTEXCPTO));
1018
1019#endif
1020 rc = VERR_SVM_UNABLE_TO_START_VM;
1021 goto end;
1022 }
1023
1024 /* Let's first sync back eip, esp, and eflags. */
1025 pCtx->eip = pVMCB->guest.u64RIP;
1026 pCtx->esp = pVMCB->guest.u64RSP;
1027 pCtx->eflags.u32 = pVMCB->guest.u64RFlags;
1028 /* eax is saved/restore across the vmrun instruction */
1029 pCtx->eax = pVMCB->guest.u64RAX;
1030
1031 /* Guest CPU context: ES, CS, SS, DS, FS, GS. */
1032 SVM_READ_SELREG(SS, ss);
1033 SVM_READ_SELREG(CS, cs);
1034 SVM_READ_SELREG(DS, ds);
1035 SVM_READ_SELREG(ES, es);
1036 SVM_READ_SELREG(FS, fs);
1037 SVM_READ_SELREG(GS, gs);
1038
1039 /* Note: no reason to sync back the CRx and DRx registers. They can't be changed by the guest. */
1040 /* Note: only in the nested paging case can CR3 & CR4 be changed by the guest. */
1041 if (pVM->hwaccm.s.fNestedPaging)
1042 {
1043 CPUMSetGuestCR3(pVM, pVMCB->guest.u64CR3);
1044 CPUMSetGuestCR4(pVM, pVMCB->guest.u64CR4);
1045 }
1046
1047 /** @note NOW IT'S SAFE FOR LOGGING! */
1048
1049 /* Take care of instruction fusing (sti, mov ss) */
1050 if (pVMCB->ctrl.u64IntShadow & SVM_INTERRUPT_SHADOW_ACTIVE)
1051 {
1052 Log(("uInterruptState %x eip=%VGv\n", pVMCB->ctrl.u64IntShadow, pCtx->eip));
1053 EMSetInhibitInterruptsPC(pVM, pCtx->eip);
1054 }
1055 else
1056 VM_FF_CLEAR(pVM, VM_FF_INHIBIT_INTERRUPTS);
1057
1058 Log2(("exitCode = %x\n", exitCode));
1059
1060 /* Check if an injected event was interrupted prematurely. */
1061 pVM->hwaccm.s.Event.intInfo = pVMCB->ctrl.ExitIntInfo.au64[0];
1062 if ( pVMCB->ctrl.ExitIntInfo.n.u1Valid
1063 && pVMCB->ctrl.ExitIntInfo.n.u3Type != SVM_EVENT_SOFTWARE_INT /* we don't care about 'int xx' as the instruction will be restarted. */)
1064 {
1065 Log(("Pending inject %VX64 at %08x exit=%08x\n", pVM->hwaccm.s.Event.intInfo, pCtx->eip, exitCode));
1066 pVM->hwaccm.s.Event.fPending = true;
1067 /* Error code present? (redundant) */
1068 if (pVMCB->ctrl.ExitIntInfo.n.u1ErrorCodeValid)
1069 {
1070 pVM->hwaccm.s.Event.errCode = pVMCB->ctrl.ExitIntInfo.n.u32ErrorCode;
1071 }
1072 else
1073 pVM->hwaccm.s.Event.errCode = 0;
1074 }
1075 STAM_COUNTER_INC(&pVM->hwaccm.s.pStatExitReasonR0[exitCode & MASK_EXITREASON_STAT]);
1076
1077 /* Deal with the reason of the VM-exit. */
1078 switch (exitCode)
1079 {
1080 case SVM_EXIT_EXCEPTION_0: case SVM_EXIT_EXCEPTION_1: case SVM_EXIT_EXCEPTION_2: case SVM_EXIT_EXCEPTION_3:
1081 case SVM_EXIT_EXCEPTION_4: case SVM_EXIT_EXCEPTION_5: case SVM_EXIT_EXCEPTION_6: case SVM_EXIT_EXCEPTION_7:
1082 case SVM_EXIT_EXCEPTION_8: case SVM_EXIT_EXCEPTION_9: case SVM_EXIT_EXCEPTION_A: case SVM_EXIT_EXCEPTION_B:
1083 case SVM_EXIT_EXCEPTION_C: case SVM_EXIT_EXCEPTION_D: case SVM_EXIT_EXCEPTION_E: case SVM_EXIT_EXCEPTION_F:
1084 case SVM_EXIT_EXCEPTION_10: case SVM_EXIT_EXCEPTION_11: case SVM_EXIT_EXCEPTION_12: case SVM_EXIT_EXCEPTION_13:
1085 case SVM_EXIT_EXCEPTION_14: case SVM_EXIT_EXCEPTION_15: case SVM_EXIT_EXCEPTION_16: case SVM_EXIT_EXCEPTION_17:
1086 case SVM_EXIT_EXCEPTION_18: case SVM_EXIT_EXCEPTION_19: case SVM_EXIT_EXCEPTION_1A: case SVM_EXIT_EXCEPTION_1B:
1087 case SVM_EXIT_EXCEPTION_1C: case SVM_EXIT_EXCEPTION_1D: case SVM_EXIT_EXCEPTION_1E: case SVM_EXIT_EXCEPTION_1F:
1088 {
1089 /* Pending trap. */
1090 SVM_EVENT Event;
1091 uint32_t vector = exitCode - SVM_EXIT_EXCEPTION_0;
1092
1093 Log2(("Hardware/software interrupt %d\n", vector));
1094 switch (vector)
1095 {
1096#ifdef DEBUG
1097 case X86_XCPT_DB:
1098 rc = DBGFR0Trap01Handler(pVM, CPUMCTX2CORE(pCtx), pVMCB->guest.u64DR6);
1099 Assert(rc != VINF_EM_RAW_GUEST_TRAP);
1100 break;
1101#endif
1102
1103 case X86_XCPT_NM:
1104 {
1105 uint32_t oldCR0;
1106
1107 Log(("#NM fault at %VGv\n", pCtx->eip));
1108
1109 /** @todo don't intercept #NM exceptions anymore when we've activated the guest FPU state. */
1110 oldCR0 = ASMGetCR0();
1111 /* If we sync the FPU/XMM state on-demand, then we can continue execution as if nothing has happened. */
1112 rc = CPUMHandleLazyFPU(pVM);
1113 if (rc == VINF_SUCCESS)
1114 {
1115 Assert(CPUMIsGuestFPUStateActive(pVM));
1116
1117 /* CPUMHandleLazyFPU could have changed CR0; restore it. */
1118 ASMSetCR0(oldCR0);
1119
1120 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitShadowNM);
1121
1122 /* Continue execution. */
1123 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1124 pVM->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
1125
1126 goto ResumeExecution;
1127 }
1128
1129 Log(("Forward #NM fault to the guest\n"));
1130 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitGuestNM);
1131
1132 Event.au64[0] = 0;
1133 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1134 Event.n.u1Valid = 1;
1135 Event.n.u8Vector = X86_XCPT_NM;
1136
1137 SVMR0InjectEvent(pVM, pVMCB, pCtx, &Event);
1138 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1139 goto ResumeExecution;
1140 }
1141
1142 case X86_XCPT_PF: /* Page fault */
1143 {
1144 uint32_t errCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1145 RTGCUINTPTR uFaultAddress = pVMCB->ctrl.u64ExitInfo2; /* EXITINFO2 = fault address */
1146
1147 Assert(!pVM->hwaccm.s.fNestedPaging);
1148
1149 Log2(("Page fault at %VGv cr2=%VGv error code %x\n", pCtx->eip, uFaultAddress, errCode));
1150 /* Exit qualification contains the linear address of the page fault. */
1151 TRPMAssertTrap(pVM, X86_XCPT_PF, TRPM_TRAP);
1152 TRPMSetErrorCode(pVM, errCode);
1153 TRPMSetFaultAddress(pVM, uFaultAddress);
1154
1155 /* Forward it to our trap handler first, in case our shadow pages are out of sync. */
1156 rc = PGMTrap0eHandler(pVM, errCode, CPUMCTX2CORE(pCtx), (RTGCPTR)uFaultAddress);
1157 Log2(("PGMTrap0eHandler %VGv returned %Vrc\n", pCtx->eip, rc));
1158 if (rc == VINF_SUCCESS)
1159 { /* We've successfully synced our shadow pages, so let's just continue execution. */
1160 Log2(("Shadow page fault at %VGv cr2=%VGv error code %x\n", pCtx->eip, uFaultAddress, errCode));
1161 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitShadowPF);
1162
1163 TRPMResetTrap(pVM);
1164
1165 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1166 goto ResumeExecution;
1167 }
1168 else
1169 if (rc == VINF_EM_RAW_GUEST_TRAP)
1170 { /* A genuine pagefault.
1171 * Forward the trap to the guest by injecting the exception and resuming execution.
1172 */
1173 Log2(("Forward page fault to the guest\n"));
1174 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitGuestPF);
1175 /* The error code might have been changed. */
1176 errCode = TRPMGetErrorCode(pVM);
1177
1178 TRPMResetTrap(pVM);
1179
1180 /* Now we must update CR2. */
1181 pCtx->cr2 = uFaultAddress;
1182
1183 Event.au64[0] = 0;
1184 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1185 Event.n.u1Valid = 1;
1186 Event.n.u8Vector = X86_XCPT_PF;
1187 Event.n.u1ErrorCodeValid = 1;
1188 Event.n.u32ErrorCode = errCode;
1189
1190 SVMR0InjectEvent(pVM, pVMCB, pCtx, &Event);
1191
1192 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1193 goto ResumeExecution;
1194 }
1195#ifdef VBOX_STRICT
1196 if (rc != VINF_EM_RAW_EMULATE_INSTR)
1197 LogFlow(("PGMTrap0eHandler failed with %d\n", rc));
1198#endif
1199 /* Need to go back to the recompiler to emulate the instruction. */
1200 TRPMResetTrap(pVM);
1201 break;
1202 }
1203
1204 case X86_XCPT_MF: /* Floating point exception. */
1205 {
1206 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitGuestMF);
1207 if (!(pCtx->cr0 & X86_CR0_NE))
1208 {
1209 /* old style FPU error reporting needs some extra work. */
1210 /** @todo don't fall back to the recompiler, but do it manually. */
1211 rc = VINF_EM_RAW_EMULATE_INSTR;
1212 break;
1213 }
1214 Log(("Trap %x at %VGv\n", vector, pCtx->eip));
1215
1216 Event.au64[0] = 0;
1217 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1218 Event.n.u1Valid = 1;
1219 Event.n.u8Vector = X86_XCPT_MF;
1220
1221 SVMR0InjectEvent(pVM, pVMCB, pCtx, &Event);
1222
1223 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1224 goto ResumeExecution;
1225 }
1226
1227#ifdef VBOX_STRICT
1228 case X86_XCPT_GP: /* General protection failure exception.*/
1229 case X86_XCPT_UD: /* Unknown opcode exception. */
1230 case X86_XCPT_DE: /* Debug exception. */
1231 case X86_XCPT_SS: /* Stack segment exception. */
1232 case X86_XCPT_NP: /* Segment not present exception. */
1233 {
1234 Event.au64[0] = 0;
1235 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1236 Event.n.u1Valid = 1;
1237 Event.n.u8Vector = vector;
1238
1239 switch(vector)
1240 {
1241 case X86_XCPT_GP:
1242 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitGuestGP);
1243 Event.n.u1ErrorCodeValid = 1;
1244 Event.n.u32ErrorCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1245 break;
1246 case X86_XCPT_DE:
1247 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitGuestDE);
1248 break;
1249 case X86_XCPT_UD:
1250 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitGuestUD);
1251 break;
1252 case X86_XCPT_SS:
1253 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitGuestSS);
1254 Event.n.u1ErrorCodeValid = 1;
1255 Event.n.u32ErrorCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1256 break;
1257 case X86_XCPT_NP:
1258 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitGuestNP);
1259 Event.n.u1ErrorCodeValid = 1;
1260 Event.n.u32ErrorCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1261 break;
1262 }
1263 Log(("Trap %x at %VGv esi=%x\n", vector, pCtx->eip, pCtx->esi));
1264 SVMR0InjectEvent(pVM, pVMCB, pCtx, &Event);
1265
1266 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1267 goto ResumeExecution;
1268 }
1269#endif
1270 default:
1271 AssertMsgFailed(("Unexpected vm-exit caused by exception %x\n", vector));
1272 rc = VERR_EM_INTERNAL_ERROR;
1273 break;
1274
1275 } /* switch (vector) */
1276 break;
1277 }
1278
1279 case SVM_EXIT_NPF:
1280 {
1281 /* EXITINFO1 contains fault errorcode; EXITINFO2 contains the guest physical address causing the fault. */
1282 uint32_t errCode = pVMCB->ctrl.u64ExitInfo1; /* EXITINFO1 = error code */
1283 RTGCPHYS uFaultAddress = pVMCB->ctrl.u64ExitInfo2; /* EXITINFO2 = fault address */
1284
1285 Assert(pVM->hwaccm.s.fNestedPaging);
1286
1287 Log2(("Page fault at %VGp cr2=%VGv error code %x\n", pCtx->eip, uFaultAddress, errCode));
1288 /* Exit qualification contains the linear address of the page fault. */
1289 TRPMAssertTrap(pVM, X86_XCPT_PF, TRPM_TRAP);
1290 TRPMSetErrorCode(pVM, errCode);
1291 TRPMSetFaultAddress(pVM, uFaultAddress);
1292
1293 /* Handle the pagefault trap for the nested shadow table. */
1294 rc = PGMR0Trap0eHandlerNestedPaging(pVM, PGMGetShadowMode(pVM), errCode, CPUMCTX2CORE(pCtx), uFaultAddress);
1295 Log2(("PGMR0Trap0eHandlerNestedPaging %VGv returned %Vrc\n", pCtx->eip, rc));
1296 if (rc == VINF_SUCCESS)
1297 { /* We've successfully synced our shadow pages, so let's just continue execution. */
1298 Log2(("Shadow page fault at %VGv cr2=%VGp error code %x\n", pCtx->eip, uFaultAddress, errCode));
1299 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitShadowPF);
1300
1301 TRPMResetTrap(pVM);
1302
1303 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1304 goto ResumeExecution;
1305 }
1306
1307#ifdef VBOX_STRICT
1308 if (rc != VINF_EM_RAW_EMULATE_INSTR)
1309 LogFlow(("PGMTrap0eHandlerNestedPaging failed with %d\n", rc));
1310#endif
1311 /* Need to go back to the recompiler to emulate the instruction. */
1312 TRPMResetTrap(pVM);
1313 break;
1314 }
1315
1316 case SVM_EXIT_VINTR:
1317 /* A virtual interrupt is about to be delivered, which means IF=1. */
1318 Log(("SVM_EXIT_VINTR IF=%d\n", pCtx->eflags.Bits.u1IF));
1319 pVMCB->ctrl.IntCtrl.n.u1VIrqValid = 0;
1320 pVMCB->ctrl.IntCtrl.n.u1IgnoreTPR = 0;
1321 pVMCB->ctrl.IntCtrl.n.u8VIrqVector = 0;
1322 goto ResumeExecution;
1323
1324 case SVM_EXIT_FERR_FREEZE:
1325 case SVM_EXIT_INTR:
1326 case SVM_EXIT_NMI:
1327 case SVM_EXIT_SMI:
1328 case SVM_EXIT_INIT:
1329 /* External interrupt; leave to allow it to be dispatched again. */
1330 rc = VINF_EM_RAW_INTERRUPT;
1331 break;
1332
1333 case SVM_EXIT_WBINVD:
1334 case SVM_EXIT_INVD: /* Guest software attempted to execute INVD. */
1335 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitInvd);
1336 /* Skip instruction and continue directly. */
1337 pCtx->eip += 2; /** @note hardcoded opcode size! */
1338 /* Continue execution.*/
1339 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1340 goto ResumeExecution;
1341
1342 case SVM_EXIT_CPUID: /* Guest software attempted to execute CPUID. */
1343 {
1344 Log2(("SVM: Cpuid %x\n", pCtx->eax));
1345 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitCpuid);
1346 rc = EMInterpretCpuId(pVM, CPUMCTX2CORE(pCtx));
1347 if (rc == VINF_SUCCESS)
1348 {
1349 /* Update EIP and continue execution. */
1350 pCtx->eip += 2; /** @note hardcoded opcode size! */
1351 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1352 goto ResumeExecution;
1353 }
1354 AssertMsgFailed(("EMU: cpuid failed with %Vrc\n", rc));
1355 rc = VINF_EM_RAW_EMULATE_INSTR;
1356 break;
1357 }
1358
1359 case SVM_EXIT_RDTSC: /* Guest software attempted to execute RDTSC. */
1360 {
1361 Log2(("SVM: Rdtsc\n"));
1362 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitRdtsc);
1363 rc = EMInterpretRdtsc(pVM, CPUMCTX2CORE(pCtx));
1364 if (rc == VINF_SUCCESS)
1365 {
1366 /* Update EIP and continue execution. */
1367 pCtx->eip += 2; /** @note hardcoded opcode size! */
1368 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1369 goto ResumeExecution;
1370 }
1371 AssertMsgFailed(("EMU: rdtsc failed with %Vrc\n", rc));
1372 rc = VINF_EM_RAW_EMULATE_INSTR;
1373 break;
1374 }
1375
1376 case SVM_EXIT_INVLPG: /* Guest software attempted to execute INVPG. */
1377 {
1378 Log2(("SVM: invlpg\n"));
1379 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitInvpg);
1380
1381 Assert(!pVM->hwaccm.s.fNestedPaging);
1382
1383 /* Truly a pita. Why can't SVM give the same information as VMX? */
1384 rc = SVMR0InterpretInvpg(pVM, CPUMCTX2CORE(pCtx), pVMCB->ctrl.TLBCtrl.n.u32ASID);
1385 if (rc == VINF_SUCCESS)
1386 {
1387 STAM_COUNTER_INC(&pVM->hwaccm.s.StatFlushPageInvlpg);
1388 goto ResumeExecution; /* eip already updated */
1389 }
1390 break;
1391 }
1392
1393 case SVM_EXIT_WRITE_CR0: case SVM_EXIT_WRITE_CR1: case SVM_EXIT_WRITE_CR2: case SVM_EXIT_WRITE_CR3:
1394 case SVM_EXIT_WRITE_CR4: case SVM_EXIT_WRITE_CR5: case SVM_EXIT_WRITE_CR6: case SVM_EXIT_WRITE_CR7:
1395 case SVM_EXIT_WRITE_CR8: case SVM_EXIT_WRITE_CR9: case SVM_EXIT_WRITE_CR10: case SVM_EXIT_WRITE_CR11:
1396 case SVM_EXIT_WRITE_CR12: case SVM_EXIT_WRITE_CR13: case SVM_EXIT_WRITE_CR14: case SVM_EXIT_WRITE_CR15:
1397 {
1398 uint32_t cbSize;
1399
1400 Log2(("SVM: %VGv mov cr%d, \n", pCtx->eip, exitCode - SVM_EXIT_WRITE_CR0));
1401 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitCRxWrite);
1402 rc = EMInterpretInstruction(pVM, CPUMCTX2CORE(pCtx), 0, &cbSize);
1403
1404 switch (exitCode - SVM_EXIT_WRITE_CR0)
1405 {
1406 case 0:
1407 pVM->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR0;
1408 break;
1409 case 2:
1410 break;
1411 case 3:
1412 Assert(!pVM->hwaccm.s.fNestedPaging);
1413 pVM->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR3;
1414 break;
1415 case 4:
1416 Assert(!pVM->hwaccm.s.fNestedPaging);
1417 pVM->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_CR4;
1418 break;
1419 default:
1420 AssertFailed();
1421 }
1422 /* Check if a sync operation is pending. */
1423 if ( rc == VINF_SUCCESS /* don't bother if we are going to ring 3 anyway */
1424 && VM_FF_ISPENDING(pVM, VM_FF_PGM_SYNC_CR3 | VM_FF_PGM_SYNC_CR3_NON_GLOBAL))
1425 {
1426 rc = PGMSyncCR3(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR3(pVM), CPUMGetGuestCR4(pVM), VM_FF_ISSET(pVM, VM_FF_PGM_SYNC_CR3));
1427 AssertRC(rc);
1428
1429 STAM_COUNTER_INC(&pVM->hwaccm.s.StatFlushTLBCRxChange);
1430
1431 /** @note Force a TLB flush. SVM requires us to do it manually. */
1432 pVM->hwaccm.s.svm.fForceTLBFlush = true;
1433 }
1434 if (rc == VINF_SUCCESS)
1435 {
1436 /* EIP has been updated already. */
1437
1438 /* Only resume if successful. */
1439 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1440 goto ResumeExecution;
1441 }
1442 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
1443 break;
1444 }
1445
1446 case SVM_EXIT_READ_CR0: case SVM_EXIT_READ_CR1: case SVM_EXIT_READ_CR2: case SVM_EXIT_READ_CR3:
1447 case SVM_EXIT_READ_CR4: case SVM_EXIT_READ_CR5: case SVM_EXIT_READ_CR6: case SVM_EXIT_READ_CR7:
1448 case SVM_EXIT_READ_CR8: case SVM_EXIT_READ_CR9: case SVM_EXIT_READ_CR10: case SVM_EXIT_READ_CR11:
1449 case SVM_EXIT_READ_CR12: case SVM_EXIT_READ_CR13: case SVM_EXIT_READ_CR14: case SVM_EXIT_READ_CR15:
1450 {
1451 uint32_t cbSize;
1452
1453 Log2(("SVM: %VGv mov x, cr%d\n", pCtx->eip, exitCode - SVM_EXIT_READ_CR0));
1454 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitCRxRead);
1455 rc = EMInterpretInstruction(pVM, CPUMCTX2CORE(pCtx), 0, &cbSize);
1456 if (rc == VINF_SUCCESS)
1457 {
1458 /* EIP has been updated already. */
1459
1460 /* Only resume if successful. */
1461 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1462 goto ResumeExecution;
1463 }
1464 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
1465 break;
1466 }
1467
1468 case SVM_EXIT_WRITE_DR0: case SVM_EXIT_WRITE_DR1: case SVM_EXIT_WRITE_DR2: case SVM_EXIT_WRITE_DR3:
1469 case SVM_EXIT_WRITE_DR4: case SVM_EXIT_WRITE_DR5: case SVM_EXIT_WRITE_DR6: case SVM_EXIT_WRITE_DR7:
1470 case SVM_EXIT_WRITE_DR8: case SVM_EXIT_WRITE_DR9: case SVM_EXIT_WRITE_DR10: case SVM_EXIT_WRITE_DR11:
1471 case SVM_EXIT_WRITE_DR12: case SVM_EXIT_WRITE_DR13: case SVM_EXIT_WRITE_DR14: case SVM_EXIT_WRITE_DR15:
1472 {
1473 uint32_t cbSize;
1474
1475 Log2(("SVM: %VGv mov dr%d, x\n", pCtx->eip, exitCode - SVM_EXIT_WRITE_DR0));
1476 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitDRxRead);
1477 rc = EMInterpretInstruction(pVM, CPUMCTX2CORE(pCtx), 0, &cbSize);
1478 if (rc == VINF_SUCCESS)
1479 {
1480 /* EIP has been updated already. */
1481
1482 /* Only resume if successful. */
1483 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1484 goto ResumeExecution;
1485 }
1486 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
1487 break;
1488 }
1489
1490 case SVM_EXIT_READ_DR0: case SVM_EXIT_READ_DR1: case SVM_EXIT_READ_DR2: case SVM_EXIT_READ_DR3:
1491 case SVM_EXIT_READ_DR4: case SVM_EXIT_READ_DR5: case SVM_EXIT_READ_DR6: case SVM_EXIT_READ_DR7:
1492 case SVM_EXIT_READ_DR8: case SVM_EXIT_READ_DR9: case SVM_EXIT_READ_DR10: case SVM_EXIT_READ_DR11:
1493 case SVM_EXIT_READ_DR12: case SVM_EXIT_READ_DR13: case SVM_EXIT_READ_DR14: case SVM_EXIT_READ_DR15:
1494 {
1495 uint32_t cbSize;
1496
1497 Log2(("SVM: %VGv mov dr%d, x\n", pCtx->eip, exitCode - SVM_EXIT_READ_DR0));
1498 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitDRxRead);
1499 rc = EMInterpretInstruction(pVM, CPUMCTX2CORE(pCtx), 0, &cbSize);
1500 if (rc == VINF_SUCCESS)
1501 {
1502 /* EIP has been updated already. */
1503
1504 /* Only resume if successful. */
1505 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1506 goto ResumeExecution;
1507 }
1508 Assert(rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3);
1509 break;
1510 }
1511
1512 /* Note: We'll get a #GP if the IO instruction isn't allowed (IOPL or TSS bitmap); no need to double check. */
1513 case SVM_EXIT_IOIO: /* I/O instruction. */
1514 {
1515 SVM_IOIO_EXIT IoExitInfo;
1516 uint32_t uIOSize, uAndVal;
1517
1518 IoExitInfo.au32[0] = pVMCB->ctrl.u64ExitInfo1;
1519
1520 /** @todo could use a lookup table here */
1521 if (IoExitInfo.n.u1OP8)
1522 {
1523 uIOSize = 1;
1524 uAndVal = 0xff;
1525 }
1526 else
1527 if (IoExitInfo.n.u1OP16)
1528 {
1529 uIOSize = 2;
1530 uAndVal = 0xffff;
1531 }
1532 else
1533 if (IoExitInfo.n.u1OP32)
1534 {
1535 uIOSize = 4;
1536 uAndVal = 0xffffffff;
1537 }
1538 else
1539 {
1540 AssertFailed(); /* should be fatal. */
1541 rc = VINF_EM_RAW_EMULATE_INSTR;
1542 break;
1543 }
1544
1545 if (IoExitInfo.n.u1STR)
1546 {
1547 /* ins/outs */
1548 uint32_t prefix = 0;
1549 if (IoExitInfo.n.u1REP)
1550 prefix |= PREFIX_REP;
1551
1552 if (IoExitInfo.n.u1Type == 0)
1553 {
1554 Log2(("IOMInterpretOUTSEx %VGv %x size=%d\n", pCtx->eip, IoExitInfo.n.u16Port, uIOSize));
1555 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitIOStringWrite);
1556 rc = IOMInterpretOUTSEx(pVM, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, prefix, uIOSize);
1557 }
1558 else
1559 {
1560 Log2(("IOMInterpretINSEx %VGv %x size=%d\n", pCtx->eip, IoExitInfo.n.u16Port, uIOSize));
1561 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitIOStringRead);
1562 rc = IOMInterpretINSEx(pVM, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, prefix, uIOSize);
1563 }
1564 }
1565 else
1566 {
1567 /* normal in/out */
1568 Assert(!IoExitInfo.n.u1REP);
1569
1570 if (IoExitInfo.n.u1Type == 0)
1571 {
1572 Log2(("IOMIOPortWrite %VGv %x %x size=%d\n", pCtx->eip, IoExitInfo.n.u16Port, pCtx->eax & uAndVal, uIOSize));
1573 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitIOWrite);
1574 rc = IOMIOPortWrite(pVM, IoExitInfo.n.u16Port, pCtx->eax & uAndVal, uIOSize);
1575 }
1576 else
1577 {
1578 uint32_t u32Val = 0;
1579
1580 STAM_COUNTER_INC(&pVM->hwaccm.s.StatExitIORead);
1581 rc = IOMIOPortRead(pVM, IoExitInfo.n.u16Port, &u32Val, uIOSize);
1582 if (IOM_SUCCESS(rc))
1583 {
1584 /* Write back to the EAX register. */
1585 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Val & uAndVal);
1586 Log2(("IOMIOPortRead %VGv %x %x size=%d\n", pCtx->eip, IoExitInfo.n.u16Port, u32Val & uAndVal, uIOSize));
1587 }
1588 }
1589 }
1590 /*
1591 * Handled the I/O return codes.
1592 * (The unhandled cases end up with rc == VINF_EM_RAW_EMULATE_INSTR.)
1593 */
1594 if (IOM_SUCCESS(rc))
1595 {
1596 /* Update EIP and continue execution. */
1597 pCtx->eip = pVMCB->ctrl.u64ExitInfo2; /* RIP/EIP of the next instruction is saved in EXITINFO2. */
1598 if (RT_LIKELY(rc == VINF_SUCCESS))
1599 {
1600 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1601 goto ResumeExecution;
1602 }
1603 Log2(("EM status from IO at %VGv %x size %d: %Vrc\n", pCtx->eip, IoExitInfo.n.u16Port, uIOSize, rc));
1604 break;
1605 }
1606
1607#ifdef VBOX_STRICT
1608 if (rc == VINF_IOM_HC_IOPORT_READ)
1609 Assert(IoExitInfo.n.u1Type != 0);
1610 else if (rc == VINF_IOM_HC_IOPORT_WRITE)
1611 Assert(IoExitInfo.n.u1Type == 0);
1612 else
1613 AssertMsg(VBOX_FAILURE(rc) || rc == VINF_EM_RAW_EMULATE_INSTR || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_TRPM_XCPT_DISPATCHED, ("%Vrc\n", rc));
1614#endif
1615 Log2(("Failed IO at %VGv %x size %d\n", pCtx->eip, IoExitInfo.n.u16Port, uIOSize));
1616 break;
1617 }
1618
1619 case SVM_EXIT_HLT:
1620 /** Check if external interrupts are pending; if so, don't switch back. */
1621 if (VM_FF_ISPENDING(pVM, (VM_FF_INTERRUPT_APIC|VM_FF_INTERRUPT_PIC)))
1622 {
1623 pCtx->eip++; /* skip hlt */
1624 goto ResumeExecution;
1625 }
1626
1627 rc = VINF_EM_RAW_EMULATE_INSTR_HLT;
1628 break;
1629
1630 case SVM_EXIT_RSM:
1631 case SVM_EXIT_INVLPGA:
1632 case SVM_EXIT_VMRUN:
1633 case SVM_EXIT_VMMCALL:
1634 case SVM_EXIT_VMLOAD:
1635 case SVM_EXIT_VMSAVE:
1636 case SVM_EXIT_STGI:
1637 case SVM_EXIT_CLGI:
1638 case SVM_EXIT_SKINIT:
1639 case SVM_EXIT_RDTSCP:
1640 {
1641 /* Unsupported instructions. */
1642 SVM_EVENT Event;
1643
1644 Event.au64[0] = 0;
1645 Event.n.u3Type = SVM_EVENT_EXCEPTION;
1646 Event.n.u1Valid = 1;
1647 Event.n.u8Vector = X86_XCPT_UD;
1648
1649 Log(("Forced #UD trap at %VGv\n", pCtx->eip));
1650 SVMR0InjectEvent(pVM, pVMCB, pCtx, &Event);
1651
1652 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1653 goto ResumeExecution;
1654 }
1655
1656 /* Emulate in ring 3. */
1657 case SVM_EXIT_MONITOR:
1658 case SVM_EXIT_RDPMC:
1659 case SVM_EXIT_PAUSE:
1660 case SVM_EXIT_MWAIT_UNCOND:
1661 case SVM_EXIT_MWAIT_ARMED:
1662 case SVM_EXIT_MSR:
1663 case SVM_EXIT_TASK_SWITCH: /* can change CR3; emulate */
1664 rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
1665 break;
1666
1667 case SVM_EXIT_SHUTDOWN:
1668 rc = VINF_EM_RESET; /* Triple fault equals a reset. */
1669 break;
1670
1671 case SVM_EXIT_IDTR_READ:
1672 case SVM_EXIT_GDTR_READ:
1673 case SVM_EXIT_LDTR_READ:
1674 case SVM_EXIT_TR_READ:
1675 case SVM_EXIT_IDTR_WRITE:
1676 case SVM_EXIT_GDTR_WRITE:
1677 case SVM_EXIT_LDTR_WRITE:
1678 case SVM_EXIT_TR_WRITE:
1679 case SVM_EXIT_CR0_SEL_WRITE:
1680 default:
1681 /* Unexpected exit codes. */
1682 rc = VERR_EM_INTERNAL_ERROR;
1683 AssertMsgFailed(("Unexpected exit code %x\n", exitCode)); /* Can't happen. */
1684 break;
1685 }
1686
1687end:
1688 if (fGuestStateSynced)
1689 {
1690 /* Remaining guest CPU context: TR, IDTR, GDTR, LDTR. */
1691 SVM_READ_SELREG(LDTR, ldtr);
1692 SVM_READ_SELREG(TR, tr);
1693
1694 pCtx->gdtr.cbGdt = pVMCB->guest.GDTR.u32Limit;
1695 pCtx->gdtr.pGdt = pVMCB->guest.GDTR.u64Base;
1696
1697 pCtx->idtr.cbIdt = pVMCB->guest.IDTR.u32Limit;
1698 pCtx->idtr.pIdt = pVMCB->guest.IDTR.u64Base;
1699
1700 /*
1701 * System MSRs
1702 */
1703 pCtx->SysEnter.cs = pVMCB->guest.u64SysEnterCS;
1704 pCtx->SysEnter.eip = pVMCB->guest.u64SysEnterEIP;
1705 pCtx->SysEnter.esp = pVMCB->guest.u64SysEnterESP;
1706 }
1707
1708 /* Signal changes for the recompiler. */
1709 CPUMSetChangedFlags(pVM, CPUM_CHANGED_SYSENTER_MSR | CPUM_CHANGED_LDTR | CPUM_CHANGED_GDTR | CPUM_CHANGED_IDTR | CPUM_CHANGED_TR | CPUM_CHANGED_HIDDEN_SEL_REGS);
1710
1711 /* If we executed vmrun and an external irq was pending, then we don't have to do a full sync the next time. */
1712 if (exitCode == SVM_EXIT_INTR)
1713 {
1714 STAM_COUNTER_INC(&pVM->hwaccm.s.StatPendingHostIrq);
1715 /* On the next entry we'll only sync the host context. */
1716 pVM->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_HOST_CONTEXT;
1717 }
1718 else
1719 {
1720 /* On the next entry we'll sync everything. */
1721 /** @todo we can do better than this */
1722 pVM->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_ALL;
1723 }
1724
1725 /* translate into a less severe return code */
1726 if (rc == VERR_EM_INTERPRETER)
1727 rc = VINF_EM_RAW_EMULATE_INSTR;
1728
1729 STAM_PROFILE_ADV_STOP(&pVM->hwaccm.s.StatExit, x);
1730 return rc;
1731}
1732
1733/**
1734 * Enters the AMD-V session
1735 *
1736 * @returns VBox status code.
1737 * @param pVM The VM to operate on.
1738 * @param pCpu CPU info struct
1739 */
1740HWACCMR0DECL(int) SVMR0Enter(PVM pVM, PHWACCM_CPUINFO pCpu)
1741{
1742 Assert(pVM->hwaccm.s.svm.fSupported);
1743
1744 LogFlow(("SVMR0Enter cpu%d last=%d asid=%d\n", pCpu->idCpu, pVM->hwaccm.s.svm.idLastCpu, pCpu->uCurrentASID));
1745 pVM->hwaccm.s.svm.fResumeVM = false;
1746
1747 /* Force to reload LDTR, so we'll execute VMLoad to load additional guest state. */
1748 pVM->hwaccm.s.fContextUseFlags |= HWACCM_CHANGED_GUEST_LDTR;
1749
1750 return VINF_SUCCESS;
1751}
1752
1753
1754/**
1755 * Leaves the AMD-V session
1756 *
1757 * @returns VBox status code.
1758 * @param pVM The VM to operate on.
1759 */
1760HWACCMR0DECL(int) SVMR0Leave(PVM pVM)
1761{
1762 Assert(pVM->hwaccm.s.svm.fSupported);
1763 return VINF_SUCCESS;
1764}
1765
1766
1767static int svmInterpretInvlPg(PVM pVM, PDISCPUSTATE pCpu, PCPUMCTXCORE pRegFrame, uint32_t uASID)
1768{
1769 OP_PARAMVAL param1;
1770 RTGCPTR addr;
1771
1772 int rc = DISQueryParamVal(pRegFrame, pCpu, &pCpu->param1, &param1, PARAM_SOURCE);
1773 if(VBOX_FAILURE(rc))
1774 return VERR_EM_INTERPRETER;
1775
1776 switch(param1.type)
1777 {
1778 case PARMTYPE_IMMEDIATE:
1779 case PARMTYPE_ADDRESS:
1780 if(!(param1.flags & PARAM_VAL32))
1781 return VERR_EM_INTERPRETER;
1782 addr = (RTGCPTR)param1.val.val32;
1783 break;
1784
1785 default:
1786 return VERR_EM_INTERPRETER;
1787 }
1788
1789 /** @todo is addr always a flat linear address or ds based
1790 * (in absence of segment override prefixes)????
1791 */
1792 rc = PGMInvalidatePage(pVM, addr);
1793 if (VBOX_SUCCESS(rc))
1794 {
1795 /* Manually invalidate the page for the VM's TLB. */
1796 Log(("SVMInvlpgA %VGv ASID=%d\n", addr, uASID));
1797 SVMInvlpgA(addr, uASID);
1798 return VINF_SUCCESS;
1799 }
1800 Assert(rc == VERR_REM_FLUSHED_PAGES_OVERFLOW);
1801 return rc;
1802}
1803
1804/**
1805 * Interprets INVLPG
1806 *
1807 * @returns VBox status code.
1808 * @retval VINF_* Scheduling instructions.
1809 * @retval VERR_EM_INTERPRETER Something we can't cope with.
1810 * @retval VERR_* Fatal errors.
1811 *
1812 * @param pVM The VM handle.
1813 * @param pRegFrame The register frame.
1814 * @param ASID Tagged TLB id for the guest
1815 *
1816 * Updates the EIP if an instruction was executed successfully.
1817 */
1818static int SVMR0InterpretInvpg(PVM pVM, PCPUMCTXCORE pRegFrame, uint32_t uASID)
1819{
1820 /*
1821 * Only allow 32-bit code.
1822 */
1823 if (SELMIsSelector32Bit(pVM, pRegFrame->eflags, pRegFrame->cs, &pRegFrame->csHid))
1824 {
1825 RTGCPTR pbCode;
1826 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &pbCode);
1827 if (VBOX_SUCCESS(rc))
1828 {
1829 uint32_t cbOp;
1830 DISCPUSTATE Cpu;
1831
1832 Cpu.mode = CPUMODE_32BIT;
1833 rc = EMInterpretDisasOneEx(pVM, pbCode, pRegFrame, &Cpu, &cbOp);
1834 Assert(VBOX_FAILURE(rc) || Cpu.pCurInstr->opcode == OP_INVLPG);
1835 if (VBOX_SUCCESS(rc) && Cpu.pCurInstr->opcode == OP_INVLPG)
1836 {
1837 Assert(cbOp == Cpu.opsize);
1838 rc = svmInterpretInvlPg(pVM, &Cpu, pRegFrame, uASID);
1839 if (VBOX_SUCCESS(rc))
1840 {
1841 pRegFrame->eip += cbOp; /* Move on to the next instruction. */
1842 }
1843 return rc;
1844 }
1845 }
1846 }
1847 return VERR_EM_INTERPRETER;
1848}
1849
1850
1851/**
1852 * Invalidates a guest page
1853 *
1854 * @returns VBox status code.
1855 * @param pVM The VM to operate on.
1856 * @param GCVirt Page to invalidate
1857 */
1858HWACCMR0DECL(int) SVMR0InvalidatePage(PVM pVM, RTGCPTR GCVirt)
1859{
1860 bool fFlushPending = pVM->hwaccm.s.svm.fAlwaysFlushTLB | pVM->hwaccm.s.svm.fForceTLBFlush;
1861
1862 /* Skip it if a TLB flush is already pending. */
1863 if (!fFlushPending)
1864 {
1865 SVM_VMCB *pVMCB;
1866
1867 Log2(("SVMR0InvalidatePage %VGv\n", GCVirt));
1868 AssertReturn(pVM, VERR_INVALID_PARAMETER);
1869 Assert(pVM->hwaccm.s.svm.fSupported);
1870
1871 pVMCB = (SVM_VMCB *)pVM->hwaccm.s.svm.pVMCB;
1872 AssertMsgReturn(pVMCB, ("Invalid pVMCB\n"), VERR_EM_INTERNAL_ERROR);
1873
1874 STAM_COUNTER_INC(&pVM->hwaccm.s.StatFlushPageManual);
1875 SVMInvlpgA(GCVirt, pVMCB->ctrl.TLBCtrl.n.u32ASID);
1876 }
1877 return VINF_SUCCESS;
1878}
1879
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