VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/HMSVMR0.cpp@ 68444

Last change on this file since 68444 was 68434, checked in by vboxsync, 7 years ago

VMM: Nested Hw.virt: SVM bits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 296.7 KB
Line 
1/* $Id: HMSVMR0.cpp 68434 2017-08-17 08:28:18Z vboxsync $ */
2/** @file
3 * HM SVM (AMD-V) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2013-2016 Oracle Corporation
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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_HM
23#include <iprt/asm-amd64-x86.h>
24#include <iprt/thread.h>
25
26#include <VBox/vmm/pdmapi.h>
27#include <VBox/vmm/dbgf.h>
28#include <VBox/vmm/iem.h>
29#include <VBox/vmm/iom.h>
30#include <VBox/vmm/tm.h>
31#include <VBox/vmm/gim.h>
32#include <VBox/vmm/apic.h>
33#include "HMInternal.h"
34#include <VBox/vmm/vm.h>
35#include "HMSVMR0.h"
36#include "dtrace/VBoxVMM.h"
37
38#define HMSVM_USE_IEM_EVENT_REFLECTION
39#ifdef DEBUG_ramshankar
40# define HMSVM_SYNC_FULL_GUEST_STATE
41# define HMSVM_ALWAYS_TRAP_ALL_XCPTS
42# define HMSVM_ALWAYS_TRAP_PF
43# define HMSVM_ALWAYS_TRAP_TASK_SWITCH
44#endif
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50#ifdef VBOX_WITH_STATISTICS
51# define HMSVM_EXITCODE_STAM_COUNTER_INC(u64ExitCode) do { \
52 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitAll); \
53 if ((u64ExitCode) == SVM_EXIT_NPF) \
54 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitReasonNpf); \
55 else \
56 STAM_COUNTER_INC(&pVCpu->hm.s.paStatExitReasonR0[(u64ExitCode) & MASK_EXITREASON_STAT]); \
57 } while (0)
58#else
59# define HMSVM_EXITCODE_STAM_COUNTER_INC(u64ExitCode) do { } while (0)
60#endif
61
62/** If we decide to use a function table approach this can be useful to
63 * switch to a "static DECLCALLBACK(int)". */
64#define HMSVM_EXIT_DECL static int
65
66/** Macro for checking and returning from the using function for
67 * \#VMEXIT intercepts that maybe caused during delivering of another
68 * event in the guest. */
69#define HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY() \
70 do \
71 { \
72 int rc = hmR0SvmCheckExitDueToEventDelivery(pVCpu, pCtx, pSvmTransient); \
73 if (RT_LIKELY(rc == VINF_SUCCESS)) { /* likely */ } \
74 else if (rc == VINF_HM_DOUBLE_FAULT) \
75 return VINF_SUCCESS; \
76 else \
77 return rc; \
78 } while (0)
79
80/** Macro for upgrading a @a a_rc to VINF_EM_DBG_STEPPED after emulating an
81 * instruction that exited. */
82#define HMSVM_CHECK_SINGLE_STEP(a_pVCpu, a_rc) \
83 do { \
84 if ((a_pVCpu)->hm.s.fSingleInstruction && (a_rc) == VINF_SUCCESS) \
85 (a_rc) = VINF_EM_DBG_STEPPED; \
86 } while (0)
87
88/** Assert that preemption is disabled or covered by thread-context hooks. */
89#define HMSVM_ASSERT_PREEMPT_SAFE() Assert( VMMR0ThreadCtxHookIsEnabled(pVCpu) \
90 || !RTThreadPreemptIsEnabled(NIL_RTTHREAD));
91
92/** Assert that we haven't migrated CPUs when thread-context hooks are not
93 * used. */
94#define HMSVM_ASSERT_CPU_SAFE() AssertMsg( VMMR0ThreadCtxHookIsEnabled(pVCpu) \
95 || pVCpu->hm.s.idEnteredCpu == RTMpCpuId(), \
96 ("Illegal migration! Entered on CPU %u Current %u\n", \
97 pVCpu->hm.s.idEnteredCpu, RTMpCpuId()));
98
99/**
100 * Exception bitmap mask for all contributory exceptions.
101 *
102 * Page fault is deliberately excluded here as it's conditional as to whether
103 * it's contributory or benign. Page faults are handled separately.
104 */
105#define HMSVM_CONTRIBUTORY_XCPT_MASK ( RT_BIT(X86_XCPT_GP) | RT_BIT(X86_XCPT_NP) | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_TS) \
106 | RT_BIT(X86_XCPT_DE))
107
108/**
109 * Mandatory/unconditional guest control intercepts.
110 */
111#define HMSVM_MANDATORY_GUEST_CTRL_INTERCEPTS ( SVM_CTRL_INTERCEPT_INTR \
112 | SVM_CTRL_INTERCEPT_NMI \
113 | SVM_CTRL_INTERCEPT_INIT \
114 | SVM_CTRL_INTERCEPT_RDPMC \
115 | SVM_CTRL_INTERCEPT_CPUID \
116 | SVM_CTRL_INTERCEPT_RSM \
117 | SVM_CTRL_INTERCEPT_HLT \
118 | SVM_CTRL_INTERCEPT_IOIO_PROT \
119 | SVM_CTRL_INTERCEPT_MSR_PROT \
120 | SVM_CTRL_INTERCEPT_INVLPGA \
121 | SVM_CTRL_INTERCEPT_SHUTDOWN \
122 | SVM_CTRL_INTERCEPT_FERR_FREEZE \
123 | SVM_CTRL_INTERCEPT_VMRUN \
124 | SVM_CTRL_INTERCEPT_VMMCALL \
125 | SVM_CTRL_INTERCEPT_VMLOAD \
126 | SVM_CTRL_INTERCEPT_VMSAVE \
127 | SVM_CTRL_INTERCEPT_STGI \
128 | SVM_CTRL_INTERCEPT_CLGI \
129 | SVM_CTRL_INTERCEPT_SKINIT \
130 | SVM_CTRL_INTERCEPT_WBINVD \
131 | SVM_CTRL_INTERCEPT_MONITOR \
132 | SVM_CTRL_INTERCEPT_MWAIT \
133 | SVM_CTRL_INTERCEPT_XSETBV)
134
135/**
136 * Mandatory/unconditional nested-guest control intercepts.
137 */
138#define HMSVM_MANDATORY_NESTED_GUEST_CTRL_INTERCEPTS ( HMSVM_MANDATORY_GUEST_CTRL_INTERCEPTS \
139 | SVM_CTRL_INTERCEPT_SMI)
140
141/** @name VMCB Clean Bits.
142 *
143 * These flags are used for VMCB-state caching. A set VMCB Clean bit indicates
144 * AMD-V doesn't need to reload the corresponding value(s) from the VMCB in
145 * memory.
146 *
147 * @{ */
148/** All intercepts vectors, TSC offset, PAUSE filter counter. */
149#define HMSVM_VMCB_CLEAN_INTERCEPTS RT_BIT(0)
150/** I/O permission bitmap, MSR permission bitmap. */
151#define HMSVM_VMCB_CLEAN_IOPM_MSRPM RT_BIT(1)
152/** ASID. */
153#define HMSVM_VMCB_CLEAN_ASID RT_BIT(2)
154/** TRP: V_TPR, V_IRQ, V_INTR_PRIO, V_IGN_TPR, V_INTR_MASKING,
155V_INTR_VECTOR. */
156#define HMSVM_VMCB_CLEAN_TPR RT_BIT(3)
157/** Nested Paging: Nested CR3 (nCR3), PAT. */
158#define HMSVM_VMCB_CLEAN_NP RT_BIT(4)
159/** Control registers (CR0, CR3, CR4, EFER). */
160#define HMSVM_VMCB_CLEAN_CRX_EFER RT_BIT(5)
161/** Debug registers (DR6, DR7). */
162#define HMSVM_VMCB_CLEAN_DRX RT_BIT(6)
163/** GDT, IDT limit and base. */
164#define HMSVM_VMCB_CLEAN_DT RT_BIT(7)
165/** Segment register: CS, SS, DS, ES limit and base. */
166#define HMSVM_VMCB_CLEAN_SEG RT_BIT(8)
167/** CR2.*/
168#define HMSVM_VMCB_CLEAN_CR2 RT_BIT(9)
169/** Last-branch record (DbgCtlMsr, br_from, br_to, lastint_from, lastint_to) */
170#define HMSVM_VMCB_CLEAN_LBR RT_BIT(10)
171/** AVIC (AVIC APIC_BAR; AVIC APIC_BACKING_PAGE, AVIC
172PHYSICAL_TABLE and AVIC LOGICAL_TABLE Pointers). */
173#define HMSVM_VMCB_CLEAN_AVIC RT_BIT(11)
174/** Mask of all valid VMCB Clean bits. */
175#define HMSVM_VMCB_CLEAN_ALL ( HMSVM_VMCB_CLEAN_INTERCEPTS \
176 | HMSVM_VMCB_CLEAN_IOPM_MSRPM \
177 | HMSVM_VMCB_CLEAN_ASID \
178 | HMSVM_VMCB_CLEAN_TPR \
179 | HMSVM_VMCB_CLEAN_NP \
180 | HMSVM_VMCB_CLEAN_CRX_EFER \
181 | HMSVM_VMCB_CLEAN_DRX \
182 | HMSVM_VMCB_CLEAN_DT \
183 | HMSVM_VMCB_CLEAN_SEG \
184 | HMSVM_VMCB_CLEAN_CR2 \
185 | HMSVM_VMCB_CLEAN_LBR \
186 | HMSVM_VMCB_CLEAN_AVIC)
187/** @} */
188
189/** @name SVM transient.
190 *
191 * A state structure for holding miscellaneous information across AMD-V
192 * VMRUN/\#VMEXIT operation, restored after the transition.
193 *
194 * @{ */
195typedef struct SVMTRANSIENT
196{
197 /** The host's rflags/eflags. */
198 RTCCUINTREG fEFlags;
199#if HC_ARCH_BITS == 32
200 uint32_t u32Alignment0;
201#endif
202
203 /** The \#VMEXIT exit code (the EXITCODE field in the VMCB). */
204 uint64_t u64ExitCode;
205 /** The guest's TPR value used for TPR shadowing. */
206 uint8_t u8GuestTpr;
207 /** Alignment. */
208 uint8_t abAlignment0[7];
209
210 /** Whether the guest FPU state was active at the time of \#VMEXIT. */
211 bool fWasGuestFPUStateActive;
212 /** Whether the guest debug state was active at the time of \#VMEXIT. */
213 bool fWasGuestDebugStateActive;
214 /** Whether the hyper debug state was active at the time of \#VMEXIT. */
215 bool fWasHyperDebugStateActive;
216 /** Whether the TSC offset mode needs to be updated. */
217 bool fUpdateTscOffsetting;
218 /** Whether the TSC_AUX MSR needs restoring on \#VMEXIT. */
219 bool fRestoreTscAuxMsr;
220 /** Whether the \#VMEXIT was caused by a page-fault during delivery of a
221 * contributary exception or a page-fault. */
222 bool fVectoringDoublePF;
223 /** Whether the \#VMEXIT was caused by a page-fault during delivery of an
224 * external interrupt or NMI. */
225 bool fVectoringPF;
226} SVMTRANSIENT, *PSVMTRANSIENT;
227AssertCompileMemberAlignment(SVMTRANSIENT, u64ExitCode, sizeof(uint64_t));
228AssertCompileMemberAlignment(SVMTRANSIENT, fWasGuestFPUStateActive, sizeof(uint64_t));
229/** @} */
230
231/**
232 * MSRPM (MSR permission bitmap) read permissions (for guest RDMSR).
233 */
234typedef enum SVMMSREXITREAD
235{
236 /** Reading this MSR causes a \#VMEXIT. */
237 SVMMSREXIT_INTERCEPT_READ = 0xb,
238 /** Reading this MSR does not cause a \#VMEXIT. */
239 SVMMSREXIT_PASSTHRU_READ
240} SVMMSREXITREAD;
241
242/**
243 * MSRPM (MSR permission bitmap) write permissions (for guest WRMSR).
244 */
245typedef enum SVMMSREXITWRITE
246{
247 /** Writing to this MSR causes a \#VMEXIT. */
248 SVMMSREXIT_INTERCEPT_WRITE = 0xd,
249 /** Writing to this MSR does not cause a \#VMEXIT. */
250 SVMMSREXIT_PASSTHRU_WRITE
251} SVMMSREXITWRITE;
252
253/**
254 * SVM \#VMEXIT handler.
255 *
256 * @returns VBox status code.
257 * @param pVCpu The cross context virtual CPU structure.
258 * @param pMixedCtx Pointer to the guest-CPU context.
259 * @param pSvmTransient Pointer to the SVM-transient structure.
260 */
261typedef int FNSVMEXITHANDLER(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient);
262
263
264/*********************************************************************************************************************************
265* Internal Functions *
266*********************************************************************************************************************************/
267static void hmR0SvmSetMsrPermission(PSVMVMCB pVmcb, uint8_t *pbMsrBitmap, unsigned uMsr, SVMMSREXITREAD enmRead,
268 SVMMSREXITWRITE enmWrite);
269static void hmR0SvmPendingEventToTrpmTrap(PVMCPU pVCpu);
270static void hmR0SvmLeave(PVMCPU pVCpu);
271
272/** @name \#VMEXIT handlers.
273 * @{
274 */
275static FNSVMEXITHANDLER hmR0SvmExitIntr;
276static FNSVMEXITHANDLER hmR0SvmExitWbinvd;
277static FNSVMEXITHANDLER hmR0SvmExitInvd;
278static FNSVMEXITHANDLER hmR0SvmExitCpuid;
279static FNSVMEXITHANDLER hmR0SvmExitRdtsc;
280static FNSVMEXITHANDLER hmR0SvmExitRdtscp;
281static FNSVMEXITHANDLER hmR0SvmExitRdpmc;
282static FNSVMEXITHANDLER hmR0SvmExitInvlpg;
283static FNSVMEXITHANDLER hmR0SvmExitHlt;
284static FNSVMEXITHANDLER hmR0SvmExitMonitor;
285static FNSVMEXITHANDLER hmR0SvmExitMwait;
286static FNSVMEXITHANDLER hmR0SvmExitShutdown;
287static FNSVMEXITHANDLER hmR0SvmExitUnexpected;
288static FNSVMEXITHANDLER hmR0SvmExitReadCRx;
289static FNSVMEXITHANDLER hmR0SvmExitWriteCRx;
290static FNSVMEXITHANDLER hmR0SvmExitSetPendingXcptUD;
291static FNSVMEXITHANDLER hmR0SvmExitMsr;
292static FNSVMEXITHANDLER hmR0SvmExitReadDRx;
293static FNSVMEXITHANDLER hmR0SvmExitWriteDRx;
294static FNSVMEXITHANDLER hmR0SvmExitXsetbv;
295static FNSVMEXITHANDLER hmR0SvmExitIOInstr;
296static FNSVMEXITHANDLER hmR0SvmExitNestedPF;
297static FNSVMEXITHANDLER hmR0SvmExitVIntr;
298static FNSVMEXITHANDLER hmR0SvmExitTaskSwitch;
299static FNSVMEXITHANDLER hmR0SvmExitVmmCall;
300static FNSVMEXITHANDLER hmR0SvmExitPause;
301static FNSVMEXITHANDLER hmR0SvmExitIret;
302static FNSVMEXITHANDLER hmR0SvmExitXcptPF;
303static FNSVMEXITHANDLER hmR0SvmExitXcptNM;
304static FNSVMEXITHANDLER hmR0SvmExitXcptUD;
305static FNSVMEXITHANDLER hmR0SvmExitXcptMF;
306static FNSVMEXITHANDLER hmR0SvmExitXcptDB;
307static FNSVMEXITHANDLER hmR0SvmExitXcptAC;
308static FNSVMEXITHANDLER hmR0SvmExitXcptBP;
309#ifdef VBOX_WITH_NESTED_HWVIRT
310static FNSVMEXITHANDLER hmR0SvmExitClgi;
311static FNSVMEXITHANDLER hmR0SvmExitStgi;
312static FNSVMEXITHANDLER hmR0SvmExitVmload;
313static FNSVMEXITHANDLER hmR0SvmExitVmsave;
314static FNSVMEXITHANDLER hmR0SvmExitInvlpga;
315static FNSVMEXITHANDLER hmR0SvmExitVmrun;
316static FNSVMEXITHANDLER hmR0SvmNestedExitIret;
317static FNSVMEXITHANDLER hmR0SvmNestedExitVIntr;
318#endif
319/** @} */
320
321static int hmR0SvmHandleExit(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PSVMTRANSIENT pSvmTransient);
322#ifdef VBOX_WITH_NESTED_HWVIRT
323static int hmR0SvmHandleExitNested(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient);
324static int hmR0SvmExecVmexit(PVMCPU pVCpu, PCPUMCTX pCtx);
325#endif
326
327/*********************************************************************************************************************************
328* Global Variables *
329*********************************************************************************************************************************/
330/** Ring-0 memory object for the IO bitmap. */
331RTR0MEMOBJ g_hMemObjIOBitmap = NIL_RTR0MEMOBJ;
332/** Physical address of the IO bitmap. */
333RTHCPHYS g_HCPhysIOBitmap = 0;
334/** Pointer to the IO bitmap. */
335R0PTRTYPE(void *) g_pvIOBitmap = NULL;
336
337#ifdef VBOX_WITH_NESTED_HWVIRT
338/** Ring-0 memory object for the nested-guest MSRPM bitmap. */
339RTR0MEMOBJ g_hMemObjNstGstMsrBitmap = NIL_RTR0MEMOBJ;
340/** Physical address of the nested-guest MSRPM bitmap. */
341RTHCPHYS g_HCPhysNstGstMsrBitmap = 0;
342/** Pointer to the nested-guest MSRPM bitmap. */
343R0PTRTYPE(void *) g_pvNstGstMsrBitmap = NULL;
344#endif
345
346/**
347 * Sets up and activates AMD-V on the current CPU.
348 *
349 * @returns VBox status code.
350 * @param pCpu Pointer to the CPU info struct.
351 * @param pVM The cross context VM structure. Can be
352 * NULL after a resume!
353 * @param pvCpuPage Pointer to the global CPU page.
354 * @param HCPhysCpuPage Physical address of the global CPU page.
355 * @param fEnabledByHost Whether the host OS has already initialized AMD-V.
356 * @param pvArg Unused on AMD-V.
357 */
358VMMR0DECL(int) SVMR0EnableCpu(PHMGLOBALCPUINFO pCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost,
359 void *pvArg)
360{
361 Assert(!fEnabledByHost);
362 Assert(HCPhysCpuPage && HCPhysCpuPage != NIL_RTHCPHYS);
363 Assert(RT_ALIGN_T(HCPhysCpuPage, _4K, RTHCPHYS) == HCPhysCpuPage);
364 Assert(pvCpuPage); NOREF(pvCpuPage);
365 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
366
367 NOREF(pvArg);
368 NOREF(fEnabledByHost);
369
370 /* Paranoid: Disable interrupt as, in theory, interrupt handlers might mess with EFER. */
371 RTCCUINTREG fEFlags = ASMIntDisableFlags();
372
373 /*
374 * We must turn on AMD-V and setup the host state physical address, as those MSRs are per CPU.
375 */
376 uint64_t u64HostEfer = ASMRdMsr(MSR_K6_EFER);
377 if (u64HostEfer & MSR_K6_EFER_SVME)
378 {
379 /* If the VBOX_HWVIRTEX_IGNORE_SVM_IN_USE is active, then we blindly use AMD-V. */
380 if ( pVM
381 && pVM->hm.s.svm.fIgnoreInUseError)
382 {
383 pCpu->fIgnoreAMDVInUseError = true;
384 }
385
386 if (!pCpu->fIgnoreAMDVInUseError)
387 {
388 ASMSetFlags(fEFlags);
389 return VERR_SVM_IN_USE;
390 }
391 }
392
393 /* Turn on AMD-V in the EFER MSR. */
394 ASMWrMsr(MSR_K6_EFER, u64HostEfer | MSR_K6_EFER_SVME);
395
396 /* Write the physical page address where the CPU will store the host state while executing the VM. */
397 ASMWrMsr(MSR_K8_VM_HSAVE_PA, HCPhysCpuPage);
398
399 /* Restore interrupts. */
400 ASMSetFlags(fEFlags);
401
402 /*
403 * Theoretically, other hypervisors may have used ASIDs, ideally we should flush all non-zero ASIDs
404 * when enabling SVM. AMD doesn't have an SVM instruction to flush all ASIDs (flushing is done
405 * upon VMRUN). Therefore, just set the fFlushAsidBeforeUse flag which instructs hmR0SvmSetupTLB()
406 * to flush the TLB with before using a new ASID.
407 */
408 pCpu->fFlushAsidBeforeUse = true;
409
410 /*
411 * Ensure each VCPU scheduled on this CPU gets a new ASID on resume. See @bugref{6255}.
412 */
413 ++pCpu->cTlbFlushes;
414
415 return VINF_SUCCESS;
416}
417
418
419/**
420 * Deactivates AMD-V on the current CPU.
421 *
422 * @returns VBox status code.
423 * @param pCpu Pointer to the CPU info struct.
424 * @param pvCpuPage Pointer to the global CPU page.
425 * @param HCPhysCpuPage Physical address of the global CPU page.
426 */
427VMMR0DECL(int) SVMR0DisableCpu(PHMGLOBALCPUINFO pCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
428{
429 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
430 AssertReturn( HCPhysCpuPage
431 && HCPhysCpuPage != NIL_RTHCPHYS, VERR_INVALID_PARAMETER);
432 AssertReturn(pvCpuPage, VERR_INVALID_PARAMETER);
433 NOREF(pCpu);
434
435 /* Paranoid: Disable interrupts as, in theory, interrupt handlers might mess with EFER. */
436 RTCCUINTREG fEFlags = ASMIntDisableFlags();
437
438 /* Turn off AMD-V in the EFER MSR. */
439 uint64_t u64HostEfer = ASMRdMsr(MSR_K6_EFER);
440 ASMWrMsr(MSR_K6_EFER, u64HostEfer & ~MSR_K6_EFER_SVME);
441
442 /* Invalidate host state physical address. */
443 ASMWrMsr(MSR_K8_VM_HSAVE_PA, 0);
444
445 /* Restore interrupts. */
446 ASMSetFlags(fEFlags);
447
448 return VINF_SUCCESS;
449}
450
451
452/**
453 * Does global AMD-V initialization (called during module initialization).
454 *
455 * @returns VBox status code.
456 */
457VMMR0DECL(int) SVMR0GlobalInit(void)
458{
459 /*
460 * Allocate 12 KB for the IO bitmap. Since this is non-optional and we always intercept all IO accesses, it's done
461 * once globally here instead of per-VM.
462 */
463 Assert(g_hMemObjIOBitmap == NIL_RTR0MEMOBJ);
464 int rc = RTR0MemObjAllocCont(&g_hMemObjIOBitmap, SVM_IOPM_PAGES << X86_PAGE_4K_SHIFT, false /* fExecutable */);
465 if (RT_FAILURE(rc))
466 return rc;
467
468 g_pvIOBitmap = RTR0MemObjAddress(g_hMemObjIOBitmap);
469 g_HCPhysIOBitmap = RTR0MemObjGetPagePhysAddr(g_hMemObjIOBitmap, 0 /* iPage */);
470
471 /* Set all bits to intercept all IO accesses. */
472 ASMMemFill32(g_pvIOBitmap, SVM_IOPM_PAGES << X86_PAGE_4K_SHIFT, UINT32_C(0xffffffff));
473
474#ifdef VBOX_WITH_NESTED_HWVIRT
475 /*
476 * Allocate 8 KB for the MSR permission bitmap for the nested-guest.
477 */
478 Assert(g_hMemObjNstGstMsrBitmap == NIL_RTR0MEMOBJ);
479 rc = RTR0MemObjAllocCont(&g_hMemObjNstGstMsrBitmap, SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT, false /* fExecutable */);
480 if (RT_FAILURE(rc))
481 return rc;
482
483 g_pvNstGstMsrBitmap = RTR0MemObjAddress(g_hMemObjNstGstMsrBitmap);
484 g_HCPhysNstGstMsrBitmap = RTR0MemObjGetPagePhysAddr(g_hMemObjNstGstMsrBitmap, 0 /* iPage */);
485
486 /* Set all bits to intercept all MSR accesses. */
487 ASMMemFill32(g_pvNstGstMsrBitmap, SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT, UINT32_C(0xffffffff));
488#endif
489
490 return VINF_SUCCESS;
491}
492
493
494/**
495 * Does global AMD-V termination (called during module termination).
496 */
497VMMR0DECL(void) SVMR0GlobalTerm(void)
498{
499 if (g_hMemObjIOBitmap != NIL_RTR0MEMOBJ)
500 {
501 RTR0MemObjFree(g_hMemObjIOBitmap, true /* fFreeMappings */);
502 g_pvIOBitmap = NULL;
503 g_HCPhysIOBitmap = 0;
504 g_hMemObjIOBitmap = NIL_RTR0MEMOBJ;
505 }
506
507#ifdef VBOX_WITH_NESTED_HWVIRT
508 if (g_hMemObjNstGstMsrBitmap != NIL_RTR0MEMOBJ)
509 {
510 RTR0MemObjFree(g_hMemObjNstGstMsrBitmap, true /* fFreeMappings */);
511 g_pvNstGstMsrBitmap = NULL;
512 g_HCPhysNstGstMsrBitmap = 0;
513 g_hMemObjNstGstMsrBitmap = NIL_RTR0MEMOBJ;
514 }
515#endif
516}
517
518
519/**
520 * Frees any allocated per-VCPU structures for a VM.
521 *
522 * @param pVM The cross context VM structure.
523 */
524DECLINLINE(void) hmR0SvmFreeStructs(PVM pVM)
525{
526 for (uint32_t i = 0; i < pVM->cCpus; i++)
527 {
528 PVMCPU pVCpu = &pVM->aCpus[i];
529 AssertPtr(pVCpu);
530
531 if (pVCpu->hm.s.svm.hMemObjVmcbHost != NIL_RTR0MEMOBJ)
532 {
533 RTR0MemObjFree(pVCpu->hm.s.svm.hMemObjVmcbHost, false);
534 pVCpu->hm.s.svm.HCPhysVmcbHost = 0;
535 pVCpu->hm.s.svm.hMemObjVmcbHost = NIL_RTR0MEMOBJ;
536 }
537
538 if (pVCpu->hm.s.svm.hMemObjVmcb != NIL_RTR0MEMOBJ)
539 {
540 RTR0MemObjFree(pVCpu->hm.s.svm.hMemObjVmcb, false);
541 pVCpu->hm.s.svm.pVmcb = NULL;
542 pVCpu->hm.s.svm.HCPhysVmcb = 0;
543 pVCpu->hm.s.svm.hMemObjVmcb = NIL_RTR0MEMOBJ;
544 }
545
546 if (pVCpu->hm.s.svm.hMemObjMsrBitmap != NIL_RTR0MEMOBJ)
547 {
548 RTR0MemObjFree(pVCpu->hm.s.svm.hMemObjMsrBitmap, false);
549 pVCpu->hm.s.svm.pvMsrBitmap = NULL;
550 pVCpu->hm.s.svm.HCPhysMsrBitmap = 0;
551 pVCpu->hm.s.svm.hMemObjMsrBitmap = NIL_RTR0MEMOBJ;
552 }
553 }
554}
555
556
557/**
558 * Does per-VM AMD-V initialization.
559 *
560 * @returns VBox status code.
561 * @param pVM The cross context VM structure.
562 */
563VMMR0DECL(int) SVMR0InitVM(PVM pVM)
564{
565 int rc = VERR_INTERNAL_ERROR_5;
566
567 /*
568 * Check for an AMD CPU erratum which requires us to flush the TLB before every world-switch.
569 */
570 uint32_t u32Family;
571 uint32_t u32Model;
572 uint32_t u32Stepping;
573 if (HMAmdIsSubjectToErratum170(&u32Family, &u32Model, &u32Stepping))
574 {
575 Log4(("SVMR0InitVM: AMD cpu with erratum 170 family %#x model %#x stepping %#x\n", u32Family, u32Model, u32Stepping));
576 pVM->hm.s.svm.fAlwaysFlushTLB = true;
577 }
578
579 /*
580 * Initialize the R0 memory objects up-front so we can properly cleanup on allocation failures.
581 */
582 for (VMCPUID i = 0; i < pVM->cCpus; i++)
583 {
584 PVMCPU pVCpu = &pVM->aCpus[i];
585 pVCpu->hm.s.svm.hMemObjVmcbHost = NIL_RTR0MEMOBJ;
586 pVCpu->hm.s.svm.hMemObjVmcb = NIL_RTR0MEMOBJ;
587 pVCpu->hm.s.svm.hMemObjMsrBitmap = NIL_RTR0MEMOBJ;
588 }
589
590 for (VMCPUID i = 0; i < pVM->cCpus; i++)
591 {
592 PVMCPU pVCpu = &pVM->aCpus[i];
593
594 /*
595 * Allocate one page for the host-context VM control block (VMCB). This is used for additional host-state (such as
596 * FS, GS, Kernel GS Base, etc.) apart from the host-state save area specified in MSR_K8_VM_HSAVE_PA.
597 */
598 rc = RTR0MemObjAllocCont(&pVCpu->hm.s.svm.hMemObjVmcbHost, SVM_VMCB_PAGES << PAGE_SHIFT, false /* fExecutable */);
599 if (RT_FAILURE(rc))
600 goto failure_cleanup;
601
602 void *pvVmcbHost = RTR0MemObjAddress(pVCpu->hm.s.svm.hMemObjVmcbHost);
603 pVCpu->hm.s.svm.HCPhysVmcbHost = RTR0MemObjGetPagePhysAddr(pVCpu->hm.s.svm.hMemObjVmcbHost, 0 /* iPage */);
604 Assert(pVCpu->hm.s.svm.HCPhysVmcbHost < _4G);
605 ASMMemZeroPage(pvVmcbHost);
606
607 /*
608 * Allocate one page for the guest-state VMCB.
609 */
610 rc = RTR0MemObjAllocCont(&pVCpu->hm.s.svm.hMemObjVmcb, SVM_VMCB_PAGES << PAGE_SHIFT, false /* fExecutable */);
611 if (RT_FAILURE(rc))
612 goto failure_cleanup;
613
614 pVCpu->hm.s.svm.pVmcb = (PSVMVMCB)RTR0MemObjAddress(pVCpu->hm.s.svm.hMemObjVmcb);
615 pVCpu->hm.s.svm.HCPhysVmcb = RTR0MemObjGetPagePhysAddr(pVCpu->hm.s.svm.hMemObjVmcb, 0 /* iPage */);
616 Assert(pVCpu->hm.s.svm.HCPhysVmcb < _4G);
617 ASMMemZeroPage(pVCpu->hm.s.svm.pVmcb);
618
619 /*
620 * Allocate two pages (8 KB) for the MSR permission bitmap. There doesn't seem to be a way to convince
621 * SVM to not require one.
622 */
623 rc = RTR0MemObjAllocCont(&pVCpu->hm.s.svm.hMemObjMsrBitmap, SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT,
624 false /* fExecutable */);
625 if (RT_FAILURE(rc))
626 goto failure_cleanup;
627
628 pVCpu->hm.s.svm.pvMsrBitmap = RTR0MemObjAddress(pVCpu->hm.s.svm.hMemObjMsrBitmap);
629 pVCpu->hm.s.svm.HCPhysMsrBitmap = RTR0MemObjGetPagePhysAddr(pVCpu->hm.s.svm.hMemObjMsrBitmap, 0 /* iPage */);
630 /* Set all bits to intercept all MSR accesses (changed later on). */
631 ASMMemFill32(pVCpu->hm.s.svm.pvMsrBitmap, SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT, UINT32_C(0xffffffff));
632 }
633
634 return VINF_SUCCESS;
635
636failure_cleanup:
637 hmR0SvmFreeStructs(pVM);
638 return rc;
639}
640
641
642/**
643 * Does per-VM AMD-V termination.
644 *
645 * @returns VBox status code.
646 * @param pVM The cross context VM structure.
647 */
648VMMR0DECL(int) SVMR0TermVM(PVM pVM)
649{
650 hmR0SvmFreeStructs(pVM);
651 return VINF_SUCCESS;
652}
653
654
655/**
656 * Sets the permission bits for the specified MSR in the MSRPM.
657 *
658 * @param pVmcb Pointer to the VM control block.
659 * @param pbMsrBitmap Pointer to the MSR bitmap.
660 * @param uMsr The MSR for which the access permissions are being set.
661 * @param enmRead MSR read permissions.
662 * @param enmWrite MSR write permissions.
663 */
664static void hmR0SvmSetMsrPermission(PSVMVMCB pVmcb, uint8_t *pbMsrBitmap, unsigned uMsr, SVMMSREXITREAD enmRead,
665 SVMMSREXITWRITE enmWrite)
666{
667 uint16_t offMsrpm;
668 uint32_t uMsrpmBit;
669 int rc = HMSvmGetMsrpmOffsetAndBit(uMsr, &offMsrpm, &uMsrpmBit);
670 AssertRC(rc);
671
672 Assert(uMsrpmBit < 0x3fff);
673 Assert(offMsrpm < SVM_MSRPM_PAGES << X86_PAGE_4K_SHIFT);
674
675 pbMsrBitmap += offMsrpm;
676 if (enmRead == SVMMSREXIT_INTERCEPT_READ)
677 ASMBitSet(pbMsrBitmap, uMsrpmBit);
678 else
679 ASMBitClear(pbMsrBitmap, uMsrpmBit);
680
681 if (enmWrite == SVMMSREXIT_INTERCEPT_WRITE)
682 ASMBitSet(pbMsrBitmap, uMsrpmBit + 1);
683 else
684 ASMBitClear(pbMsrBitmap, uMsrpmBit + 1);
685
686 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_IOPM_MSRPM;
687}
688
689
690/**
691 * Sets up AMD-V for the specified VM.
692 * This function is only called once per-VM during initalization.
693 *
694 * @returns VBox status code.
695 * @param pVM The cross context VM structure.
696 */
697VMMR0DECL(int) SVMR0SetupVM(PVM pVM)
698{
699 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
700 AssertReturn(pVM, VERR_INVALID_PARAMETER);
701 Assert(pVM->hm.s.svm.fSupported);
702
703 bool const fPauseFilter = RT_BOOL(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER);
704 bool const fPauseFilterThreshold = RT_BOOL(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_PAUSE_FILTER_THRESHOLD);
705 bool const fUsePauseFilter = fPauseFilter && pVM->hm.s.svm.cPauseFilter && pVM->hm.s.svm.cPauseFilterThresholdTicks;
706
707 for (VMCPUID i = 0; i < pVM->cCpus; i++)
708 {
709 PVMCPU pVCpu = &pVM->aCpus[i];
710 PSVMVMCB pVmcb = pVM->aCpus[i].hm.s.svm.pVmcb;
711
712 AssertMsgReturn(pVmcb, ("Invalid pVmcb for vcpu[%u]\n", i), VERR_SVM_INVALID_PVMCB);
713
714 /* Initialize the #VMEXIT history array with end-of-array markers (UINT16_MAX). */
715 Assert(!pVCpu->hm.s.idxExitHistoryFree);
716 HMCPU_EXIT_HISTORY_RESET(pVCpu);
717
718 /* Always trap #AC for reasons of security. */
719 pVmcb->ctrl.u32InterceptXcpt |= RT_BIT_32(X86_XCPT_AC);
720
721 /* Always trap #DB for reasons of security. */
722 pVmcb->ctrl.u32InterceptXcpt |= RT_BIT_32(X86_XCPT_DB);
723
724 /* Trap exceptions unconditionally (debug purposes). */
725#ifdef HMSVM_ALWAYS_TRAP_PF
726 pVmcb->ctrl.u32InterceptXcpt |= RT_BIT(X86_XCPT_PF);
727#endif
728#ifdef HMSVM_ALWAYS_TRAP_ALL_XCPTS
729 /* If you add any exceptions here, make sure to update hmR0SvmHandleExit(). */
730 pVmcb->ctrl.u32InterceptXcpt |= 0
731 | RT_BIT(X86_XCPT_BP)
732 | RT_BIT(X86_XCPT_DE)
733 | RT_BIT(X86_XCPT_NM)
734 | RT_BIT(X86_XCPT_UD)
735 | RT_BIT(X86_XCPT_NP)
736 | RT_BIT(X86_XCPT_SS)
737 | RT_BIT(X86_XCPT_GP)
738 | RT_BIT(X86_XCPT_PF)
739 | RT_BIT(X86_XCPT_MF)
740 ;
741#endif
742
743 /* Set up unconditional intercepts and conditions. */
744 pVmcb->ctrl.u64InterceptCtrl = HMSVM_MANDATORY_GUEST_CTRL_INTERCEPTS;
745
746 /* CR0, CR4 reads must be intercepted, our shadow values are not necessarily the same as the guest's. */
747 pVmcb->ctrl.u16InterceptRdCRx = RT_BIT(0) | RT_BIT(4);
748
749 /* CR0, CR4 writes must be intercepted for the same reasons as above. */
750 pVmcb->ctrl.u16InterceptWrCRx = RT_BIT(0) | RT_BIT(4);
751
752 /* Intercept all DRx reads and writes by default. Changed later on. */
753 pVmcb->ctrl.u16InterceptRdDRx = 0xffff;
754 pVmcb->ctrl.u16InterceptWrDRx = 0xffff;
755
756 /* Virtualize masking of INTR interrupts. (reads/writes from/to CR8 go to the V_TPR register) */
757 pVmcb->ctrl.IntCtrl.n.u1VIntrMasking = 1;
758
759 /* Ignore the priority in the virtual TPR. This is necessary for delivering PIC style (ExtInt) interrupts
760 and we currently deliver both PIC and APIC interrupts alike. See hmR0SvmInjectPendingEvent() */
761 pVmcb->ctrl.IntCtrl.n.u1IgnoreTPR = 1;
762
763 /* Set IO and MSR bitmap permission bitmap physical addresses. */
764 pVmcb->ctrl.u64IOPMPhysAddr = g_HCPhysIOBitmap;
765 pVmcb->ctrl.u64MSRPMPhysAddr = pVCpu->hm.s.svm.HCPhysMsrBitmap;
766
767 /* No LBR virtualization. */
768 pVmcb->ctrl.u64LBRVirt = 0;
769
770 /* Initially set all VMCB clean bits to 0 indicating that everything should be loaded from the VMCB in memory. */
771 pVmcb->ctrl.u64VmcbCleanBits = 0;
772
773 /* The host ASID MBZ, for the guest start with 1. */
774 pVmcb->ctrl.TLBCtrl.n.u32ASID = 1;
775
776 /*
777 * Setup the PAT MSR (applicable for Nested Paging only).
778 * The default value should be 0x0007040600070406ULL, but we want to treat all guest memory as WB,
779 * so choose type 6 for all PAT slots.
780 */
781 pVmcb->guest.u64GPAT = UINT64_C(0x0006060606060606);
782
783 /* Setup Nested Paging. This doesn't change throughout the execution time of the VM. */
784 pVmcb->ctrl.NestedPaging.n.u1NestedPaging = pVM->hm.s.fNestedPaging;
785
786 /* Without Nested Paging, we need additionally intercepts. */
787 if (!pVM->hm.s.fNestedPaging)
788 {
789 /* CR3 reads/writes must be intercepted; our shadow values differ from the guest values. */
790 pVmcb->ctrl.u16InterceptRdCRx |= RT_BIT(3);
791 pVmcb->ctrl.u16InterceptWrCRx |= RT_BIT(3);
792
793 /* Intercept INVLPG and task switches (may change CR3, EFLAGS, LDT). */
794 pVmcb->ctrl.u64InterceptCtrl |= SVM_CTRL_INTERCEPT_INVLPG
795 | SVM_CTRL_INTERCEPT_TASK_SWITCH;
796
797 /* Page faults must be intercepted to implement shadow paging. */
798 pVmcb->ctrl.u32InterceptXcpt |= RT_BIT(X86_XCPT_PF);
799 }
800
801#ifdef HMSVM_ALWAYS_TRAP_TASK_SWITCH
802 pVmcb->ctrl.u64InterceptCtrl |= SVM_CTRL_INTERCEPT_TASK_SWITCH;
803#endif
804
805 /* Apply the exceptions intercepts needed by the GIM provider. */
806 if (pVCpu->hm.s.fGIMTrapXcptUD)
807 pVmcb->ctrl.u32InterceptXcpt |= RT_BIT(X86_XCPT_UD);
808
809 /* Setup Pause Filter for guest pause-loop (spinlock) exiting. */
810 if (fUsePauseFilter)
811 {
812 pVmcb->ctrl.u16PauseFilterCount = pVM->hm.s.svm.cPauseFilter;
813 if (fPauseFilterThreshold)
814 pVmcb->ctrl.u16PauseFilterThreshold = pVM->hm.s.svm.cPauseFilterThresholdTicks;
815 }
816
817 /*
818 * The following MSRs are saved/restored automatically during the world-switch.
819 * Don't intercept guest read/write accesses to these MSRs.
820 */
821 uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.svm.pvMsrBitmap;
822 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_LSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
823 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_CSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
824 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K6_STAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
825 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_SF_MASK, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
826 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_FS_BASE, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
827 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_GS_BASE, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
828 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_KERNEL_GS_BASE, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
829 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_IA32_SYSENTER_CS, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
830 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_IA32_SYSENTER_ESP, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
831 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_IA32_SYSENTER_EIP, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
832 }
833
834 return VINF_SUCCESS;
835}
836
837
838/**
839 * Invalidates a guest page by guest virtual address.
840 *
841 * @returns VBox status code.
842 * @param pVM The cross context VM structure.
843 * @param pVCpu The cross context virtual CPU structure.
844 * @param GCVirt Guest virtual address of the page to invalidate.
845 */
846VMMR0DECL(int) SVMR0InvalidatePage(PVM pVM, PVMCPU pVCpu, RTGCPTR GCVirt)
847{
848 AssertReturn(pVM, VERR_INVALID_PARAMETER);
849 Assert(pVM->hm.s.svm.fSupported);
850
851 bool fFlushPending = pVM->hm.s.svm.fAlwaysFlushTLB || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TLB_FLUSH);
852
853 /* Skip it if a TLB flush is already pending. */
854 if (!fFlushPending)
855 {
856 Log4(("SVMR0InvalidatePage %RGv\n", GCVirt));
857
858 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
859 AssertMsgReturn(pVmcb, ("Invalid pVmcb!\n"), VERR_SVM_INVALID_PVMCB);
860
861#if HC_ARCH_BITS == 32
862 /* If we get a flush in 64-bit guest mode, then force a full TLB flush. INVLPGA takes only 32-bit addresses. */
863 if (CPUMIsGuestInLongMode(pVCpu))
864 VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
865 else
866#endif
867 {
868 SVMR0InvlpgA(GCVirt, pVmcb->ctrl.TLBCtrl.n.u32ASID);
869 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbInvlpgVirt);
870 }
871 }
872 return VINF_SUCCESS;
873}
874
875
876/**
877 * Flushes the appropriate tagged-TLB entries.
878 *
879 * @param pVCpu The cross context virtual CPU structure.
880 * @param pCtx Pointer to the guest-CPU or nested-guest-CPU context.
881 * @param pVmcb Pointer to the VM control block.
882 */
883static void hmR0SvmFlushTaggedTlb(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMVMCB pVmcb)
884{
885 PVM pVM = pVCpu->CTX_SUFF(pVM);
886 PHMGLOBALCPUINFO pCpu = hmR0GetCurrentCpu();
887
888 /*
889 * Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last.
890 * This can happen both for start & resume due to long jumps back to ring-3.
891 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB,
892 * so we cannot reuse the ASIDs without flushing.
893 */
894 bool fNewAsid = false;
895 Assert(pCpu->idCpu != NIL_RTCPUID);
896 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
897 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
898 {
899 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
900 pVCpu->hm.s.fForceTLBFlush = true;
901 fNewAsid = true;
902 }
903
904 /* Set TLB flush state as checked until we return from the world switch. */
905 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true);
906
907 /* Check for explicit TLB flushes. */
908 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
909 {
910 pVCpu->hm.s.fForceTLBFlush = true;
911 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
912 }
913
914 /*
915 * If the AMD CPU erratum 170, We need to flush the entire TLB for each world switch. Sad.
916 * This Host CPU requirement takes precedence.
917 */
918 if (pVM->hm.s.svm.fAlwaysFlushTLB)
919 {
920 pCpu->uCurrentAsid = 1;
921 pVCpu->hm.s.uCurrentAsid = 1;
922 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
923 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
924
925 /* Clear the VMCB Clean Bit for NP while flushing the TLB. See @bugref{7152}. */
926 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_NP;
927
928 /* Keep track of last CPU ID even when flushing all the time. */
929 if (fNewAsid)
930 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
931 }
932 else
933 {
934#ifdef VBOX_WITH_NESTED_HWVIRT
935 /*
936 * Only if the nested hypervisor says it does not need to flush anything in the TLB,
937 * can we possibly apply it on the host. Otherwise, the nested-guest TLB flush setting
938 * should be used and then the host settings be added on top.
939 */
940 if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
941 {
942 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
943 if (pVmcbNstGstCache->TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_NOTHING)
944 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_NOTHING;
945 else
946 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = pVmcbNstGstCache->TLBCtrl.n.u8TLBFlush;
947 }
948#else
949 RT_NOREF(pCtx);
950 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_NOTHING;
951#endif
952 if (pVCpu->hm.s.fForceTLBFlush)
953 {
954 /* Clear the VMCB Clean Bit for NP while flushing the TLB. See @bugref{7152}. */
955 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_NP;
956
957 if (fNewAsid)
958 {
959 ++pCpu->uCurrentAsid;
960 bool fHitASIDLimit = false;
961 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
962 {
963 pCpu->uCurrentAsid = 1; /* Wraparound at 1; host uses 0 */
964 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new ASID. */
965 fHitASIDLimit = true;
966
967 if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
968 {
969 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
970 pCpu->fFlushAsidBeforeUse = true;
971 }
972 else
973 {
974 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
975 pCpu->fFlushAsidBeforeUse = false;
976 }
977 }
978
979 if ( !fHitASIDLimit
980 && pCpu->fFlushAsidBeforeUse)
981 {
982 if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
983 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
984 else
985 {
986 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
987 pCpu->fFlushAsidBeforeUse = false;
988 }
989 }
990
991 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
992 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
993 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
994 }
995 else
996 {
997 if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
998 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
999 else
1000 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
1001 }
1002
1003 pVCpu->hm.s.fForceTLBFlush = false;
1004 }
1005 }
1006
1007 /* Update VMCB with the ASID. */
1008 if (pVmcb->ctrl.TLBCtrl.n.u32ASID != pVCpu->hm.s.uCurrentAsid)
1009 {
1010 pVmcb->ctrl.TLBCtrl.n.u32ASID = pVCpu->hm.s.uCurrentAsid;
1011 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_ASID;
1012 }
1013
1014#ifdef VBOX_WITH_NESTED_HWVIRT
1015 Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx) || pVmcb->ctrl.TLBCtrl.n.u8TLBFlush != SVM_TLB_FLUSH_NOTHING);
1016#endif
1017
1018 AssertMsg(pVCpu->hm.s.idLastCpu == pCpu->idCpu,
1019 ("vcpu idLastCpu=%u pcpu idCpu=%u\n", pVCpu->hm.s.idLastCpu, pCpu->idCpu));
1020 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
1021 ("Flush count mismatch for cpu %u (%u vs %u)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
1022 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
1023 ("cpu%d uCurrentAsid = %x\n", pCpu->idCpu, pCpu->uCurrentAsid));
1024 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
1025 ("cpu%d VM uCurrentAsid = %x\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
1026
1027#ifdef VBOX_WITH_STATISTICS
1028 if (pVmcb->ctrl.TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_NOTHING)
1029 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch);
1030 else if ( pVmcb->ctrl.TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_SINGLE_CONTEXT
1031 || pVmcb->ctrl.TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_SINGLE_CONTEXT_RETAIN_GLOBALS)
1032 {
1033 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
1034 }
1035 else
1036 {
1037 Assert(pVmcb->ctrl.TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_ENTIRE);
1038 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushEntire);
1039 }
1040#endif
1041}
1042
1043
1044/** @name 64-bit guest on 32-bit host OS helper functions.
1045 *
1046 * The host CPU is still 64-bit capable but the host OS is running in 32-bit
1047 * mode (code segment, paging). These wrappers/helpers perform the necessary
1048 * bits for the 32->64 switcher.
1049 *
1050 * @{ */
1051#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
1052/**
1053 * Prepares for and executes VMRUN (64-bit guests on a 32-bit host).
1054 *
1055 * @returns VBox status code.
1056 * @param HCPhysVmcbHost Physical address of host VMCB.
1057 * @param HCPhysVmcb Physical address of the VMCB.
1058 * @param pCtx Pointer to the guest-CPU context.
1059 * @param pVM The cross context VM structure.
1060 * @param pVCpu The cross context virtual CPU structure.
1061 */
1062DECLASM(int) SVMR0VMSwitcherRun64(RTHCPHYS HCPhysVmcbHost, RTHCPHYS HCPhysVmcb, PCPUMCTX pCtx, PVM pVM, PVMCPU pVCpu)
1063{
1064 uint32_t aParam[8];
1065 aParam[0] = RT_LO_U32(HCPhysVmcbHost); /* Param 1: HCPhysVmcbHost - Lo. */
1066 aParam[1] = RT_HI_U32(HCPhysVmcbHost); /* Param 1: HCPhysVmcbHost - Hi. */
1067 aParam[2] = RT_LO_U32(HCPhysVmcb); /* Param 2: HCPhysVmcb - Lo. */
1068 aParam[3] = RT_HI_U32(HCPhysVmcb); /* Param 2: HCPhysVmcb - Hi. */
1069 aParam[4] = VM_RC_ADDR(pVM, pVM);
1070 aParam[5] = 0;
1071 aParam[6] = VM_RC_ADDR(pVM, pVCpu);
1072 aParam[7] = 0;
1073
1074 return SVMR0Execute64BitsHandler(pVM, pVCpu, pCtx, HM64ON32OP_SVMRCVMRun64, RT_ELEMENTS(aParam), &aParam[0]);
1075}
1076
1077
1078/**
1079 * Executes the specified VMRUN handler in 64-bit mode.
1080 *
1081 * @returns VBox status code.
1082 * @param pVM The cross context VM structure.
1083 * @param pVCpu The cross context virtual CPU structure.
1084 * @param pCtx Pointer to the guest-CPU context.
1085 * @param enmOp The operation to perform.
1086 * @param cParams Number of parameters.
1087 * @param paParam Array of 32-bit parameters.
1088 */
1089VMMR0DECL(int) SVMR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, HM64ON32OP enmOp,
1090 uint32_t cParams, uint32_t *paParam)
1091{
1092 AssertReturn(pVM->hm.s.pfnHost32ToGuest64R0, VERR_HM_NO_32_TO_64_SWITCHER);
1093 Assert(enmOp > HM64ON32OP_INVALID && enmOp < HM64ON32OP_END);
1094
1095 NOREF(pCtx);
1096
1097 /* Disable interrupts. */
1098 RTHCUINTREG uOldEFlags = ASMIntDisableFlags();
1099
1100#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
1101 RTCPUID idHostCpu = RTMpCpuId();
1102 CPUMR0SetLApic(pVCpu, idHostCpu);
1103#endif
1104
1105 CPUMSetHyperESP(pVCpu, VMMGetStackRC(pVCpu));
1106 CPUMSetHyperEIP(pVCpu, enmOp);
1107 for (int i = (int)cParams - 1; i >= 0; i--)
1108 CPUMPushHyper(pVCpu, paParam[i]);
1109
1110 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatWorldSwitch3264, z);
1111 /* Call the switcher. */
1112 int rc = pVM->hm.s.pfnHost32ToGuest64R0(pVM, RT_OFFSETOF(VM, aCpus[pVCpu->idCpu].cpum) - RT_OFFSETOF(VM, cpum));
1113 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatWorldSwitch3264, z);
1114
1115 /* Restore interrupts. */
1116 ASMSetFlags(uOldEFlags);
1117 return rc;
1118}
1119
1120#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) */
1121/** @} */
1122
1123
1124/**
1125 * Adds an exception to the intercept exception bitmap in the VMCB and updates
1126 * the corresponding VMCB Clean bit.
1127 *
1128 * @param pVmcb Pointer to the VM control block.
1129 * @param u32Xcpt The value of the exception (X86_XCPT_*).
1130 */
1131DECLINLINE(void) hmR0SvmAddXcptIntercept(PSVMVMCB pVmcb, uint32_t u32Xcpt)
1132{
1133 if (!(pVmcb->ctrl.u32InterceptXcpt & RT_BIT(u32Xcpt)))
1134 {
1135 pVmcb->ctrl.u32InterceptXcpt |= RT_BIT(u32Xcpt);
1136 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
1137 }
1138}
1139
1140
1141/**
1142 * Removes an exception from the intercept-exception bitmap in the VMCB and
1143 * updates the corresponding VMCB Clean bit.
1144 *
1145 * @param pVmcb Pointer to the VM control block.
1146 * @param u32Xcpt The value of the exception (X86_XCPT_*).
1147 */
1148DECLINLINE(void) hmR0SvmRemoveXcptIntercept(PSVMVMCB pVmcb, uint32_t u32Xcpt)
1149{
1150 Assert(u32Xcpt != X86_XCPT_DB);
1151 Assert(u32Xcpt != X86_XCPT_AC);
1152#ifndef HMSVM_ALWAYS_TRAP_ALL_XCPTS
1153 if (pVmcb->ctrl.u32InterceptXcpt & RT_BIT(u32Xcpt))
1154 {
1155 pVmcb->ctrl.u32InterceptXcpt &= ~RT_BIT(u32Xcpt);
1156 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
1157 }
1158#endif
1159}
1160
1161
1162/**
1163 * Loads the guest CR0 control register into the guest-state area in the VMCB.
1164 * Although the guest CR0 is a separate field in the VMCB we have to consider
1165 * the FPU state itself which is shared between the host and the guest.
1166 *
1167 * @returns VBox status code.
1168 * @param pVCpu The cross context virtual CPU structure.
1169 * @param pVmcb Pointer to the VM control block.
1170 * @param pCtx Pointer to the guest-CPU context.
1171 *
1172 * @remarks No-long-jump zone!!!
1173 */
1174static void hmR0SvmLoadSharedCR0(PVMCPU pVCpu, PSVMVMCB pVmcb, PCPUMCTX pCtx)
1175{
1176 uint64_t u64GuestCR0 = pCtx->cr0;
1177
1178 /* Always enable caching. */
1179 u64GuestCR0 &= ~(X86_CR0_CD | X86_CR0_NW);
1180
1181 /*
1182 * When Nested Paging is not available use shadow page tables and intercept #PFs (the latter done in SVMR0SetupVM()).
1183 */
1184 if (!pVmcb->ctrl.NestedPaging.n.u1NestedPaging)
1185 {
1186 u64GuestCR0 |= X86_CR0_PG; /* When Nested Paging is not available, use shadow page tables. */
1187 u64GuestCR0 |= X86_CR0_WP; /* Guest CPL 0 writes to its read-only pages should cause a #PF #VMEXIT. */
1188 }
1189
1190 /*
1191 * Guest FPU bits.
1192 */
1193 bool fInterceptNM = false;
1194 bool fInterceptMF = false;
1195 u64GuestCR0 |= X86_CR0_NE; /* Use internal x87 FPU exceptions handling rather than external interrupts. */
1196 if (CPUMIsGuestFPUStateActive(pVCpu))
1197 {
1198 /* Catch floating point exceptions if we need to report them to the guest in a different way. */
1199 if (!(pCtx->cr0 & X86_CR0_NE))
1200 {
1201 Log4(("hmR0SvmLoadGuestControlRegs: Intercepting Guest CR0.MP Old-style FPU handling!!!\n"));
1202 fInterceptMF = true;
1203 }
1204 }
1205 else
1206 {
1207 fInterceptNM = true; /* Guest FPU inactive, #VMEXIT on #NM for lazy FPU loading. */
1208 u64GuestCR0 |= X86_CR0_TS /* Guest can task switch quickly and do lazy FPU syncing. */
1209 | X86_CR0_MP; /* FWAIT/WAIT should not ignore CR0.TS and should generate #NM. */
1210 }
1211
1212 /*
1213 * Update the exception intercept bitmap.
1214 */
1215 if (fInterceptNM)
1216 hmR0SvmAddXcptIntercept(pVmcb, X86_XCPT_NM);
1217 else
1218 hmR0SvmRemoveXcptIntercept(pVmcb, X86_XCPT_NM);
1219
1220 if (fInterceptMF)
1221 hmR0SvmAddXcptIntercept(pVmcb, X86_XCPT_MF);
1222 else
1223 hmR0SvmRemoveXcptIntercept(pVmcb, X86_XCPT_MF);
1224
1225 pVmcb->guest.u64CR0 = u64GuestCR0;
1226 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CRX_EFER;
1227}
1228
1229
1230/**
1231 * Loads the guest control registers (CR2, CR3, CR4) into the VMCB.
1232 *
1233 * @returns VBox status code.
1234 * @param pVCpu The cross context virtual CPU structure.
1235 * @param pVmcb Pointer to the VM control block.
1236 * @param pCtx Pointer to the guest-CPU context.
1237 *
1238 * @remarks No-long-jump zone!!!
1239 */
1240static int hmR0SvmLoadGuestControlRegs(PVMCPU pVCpu, PSVMVMCB pVmcb, PCPUMCTX pCtx)
1241{
1242 PVM pVM = pVCpu->CTX_SUFF(pVM);
1243
1244 /*
1245 * Guest CR2.
1246 */
1247 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR2))
1248 {
1249 pVmcb->guest.u64CR2 = pCtx->cr2;
1250 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CR2;
1251 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR2);
1252 }
1253
1254 /*
1255 * Guest CR3.
1256 */
1257 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR3))
1258 {
1259 if (pVM->hm.s.fNestedPaging)
1260 {
1261 PGMMODE enmShwPagingMode;
1262#if HC_ARCH_BITS == 32
1263 if (CPUMIsGuestInLongModeEx(pCtx))
1264 enmShwPagingMode = PGMMODE_AMD64_NX;
1265 else
1266#endif
1267 enmShwPagingMode = PGMGetHostMode(pVM);
1268
1269 pVmcb->ctrl.u64NestedPagingCR3 = PGMGetNestedCR3(pVCpu, enmShwPagingMode);
1270 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_NP;
1271 Assert(pVmcb->ctrl.u64NestedPagingCR3);
1272 pVmcb->guest.u64CR3 = pCtx->cr3;
1273 }
1274 else
1275 pVmcb->guest.u64CR3 = PGMGetHyperCR3(pVCpu);
1276
1277 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CRX_EFER;
1278 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR3);
1279 }
1280
1281 /*
1282 * Guest CR4.
1283 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
1284 */
1285 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR4))
1286 {
1287 uint64_t u64GuestCR4 = pCtx->cr4;
1288 if (!pVM->hm.s.fNestedPaging)
1289 {
1290 switch (pVCpu->hm.s.enmShadowMode)
1291 {
1292 case PGMMODE_REAL:
1293 case PGMMODE_PROTECTED: /* Protected mode, no paging. */
1294 AssertFailed();
1295 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1296
1297 case PGMMODE_32_BIT: /* 32-bit paging. */
1298 u64GuestCR4 &= ~X86_CR4_PAE;
1299 break;
1300
1301 case PGMMODE_PAE: /* PAE paging. */
1302 case PGMMODE_PAE_NX: /* PAE paging with NX enabled. */
1303 /** Must use PAE paging as we could use physical memory > 4 GB */
1304 u64GuestCR4 |= X86_CR4_PAE;
1305 break;
1306
1307 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
1308 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
1309#ifdef VBOX_ENABLE_64_BITS_GUESTS
1310 break;
1311#else
1312 AssertFailed();
1313 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1314#endif
1315
1316 default: /* shut up gcc */
1317 AssertFailed();
1318 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1319 }
1320 }
1321
1322 pVmcb->guest.u64CR4 = u64GuestCR4;
1323 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CRX_EFER;
1324
1325 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+guest XCR0. */
1326 pVCpu->hm.s.fLoadSaveGuestXcr0 = (u64GuestCR4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
1327
1328 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR4);
1329 }
1330
1331 return VINF_SUCCESS;
1332}
1333
1334
1335#ifdef VBOX_WITH_NESTED_HWVIRT
1336/**
1337 * Loads the nested-guest control registers (CR2, CR3, CR4) into the VMCB.
1338 *
1339 * @param pVCpu The cross context virtual CPU structure.
1340 * @param pVmcbNstGst Pointer to the nested-guest VM control block.
1341 * @param pCtx Pointer to the guest-CPU context.
1342 *
1343 * @remarks No-long-jump zone!!!
1344 */
1345static void hmR0SvmLoadGuestControlRegsNested(PVMCPU pVCpu, PSVMVMCB pVmcbNstGst, PCPUMCTX pCtx)
1346{
1347 /*
1348 * Guest CR0.
1349 */
1350 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
1351 {
1352 pVmcbNstGst->guest.u64CR0 = pCtx->cr0;
1353 pVmcbNstGst->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CRX_EFER;
1354 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR0);
1355 }
1356
1357 /*
1358 * Guest CR2.
1359 */
1360 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR2))
1361 {
1362 pVmcbNstGst->guest.u64CR2 = pCtx->cr2;
1363 pVmcbNstGst->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CR2;
1364 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR2);
1365 }
1366
1367 /*
1368 * Guest CR3.
1369 */
1370 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR3))
1371 {
1372 Assert(!pVCpu->CTX_SUFF(pVM)->cpum.ro.GuestFeatures.fSvmNestedPaging);
1373 int rc = PGMPhysGCPhys2HCPhys(pVCpu->CTX_SUFF(pVM), pCtx->cr3, &pVmcbNstGst->guest.u64CR3);
1374 AssertRC(rc);
1375 pVmcbNstGst->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CRX_EFER;
1376 Log4(("hmR0SvmLoadGuestControlRegsNested: CR3=%#RX64 to HC phys CR3=%#RHp\n", pCtx->cr3, pVmcbNstGst->guest.u64CR3));
1377 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR3);
1378 }
1379
1380 /*
1381 * Guest CR4.
1382 * ASSUMES this is done everytime we get in from ring-3! (XCR0)
1383 */
1384 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR4))
1385 {
1386 Assert(!pVCpu->CTX_SUFF(pVM)->cpum.ro.GuestFeatures.fSvmNestedPaging);
1387 pVmcbNstGst->guest.u64CR4 = pCtx->cr4;
1388 pVmcbNstGst->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CRX_EFER;
1389
1390 /* Whether to save/load/restore XCR0 during world switch depends on CR4.OSXSAVE and host+nested-guest XCR0. */
1391 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
1392
1393 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR4);
1394 }
1395}
1396#endif
1397
1398
1399/**
1400 * Loads the guest segment registers into the VMCB.
1401 *
1402 * @returns VBox status code.
1403 * @param pVCpu The cross context virtual CPU structure.
1404 * @param pVmcb Pointer to the VM control block.
1405 * @param pCtx Pointer to the guest-CPU context.
1406 *
1407 * @remarks No-long-jump zone!!!
1408 */
1409static void hmR0SvmLoadGuestSegmentRegs(PVMCPU pVCpu, PSVMVMCB pVmcb, PCPUMCTX pCtx)
1410{
1411 /* Guest Segment registers: CS, SS, DS, ES, FS, GS. */
1412 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS))
1413 {
1414 HMSVM_SEG_REG_COPY_TO_VMCB(pCtx, &pVmcb->guest, CS, cs);
1415 HMSVM_SEG_REG_COPY_TO_VMCB(pCtx, &pVmcb->guest, SS, ss);
1416 HMSVM_SEG_REG_COPY_TO_VMCB(pCtx, &pVmcb->guest, DS, ds);
1417 HMSVM_SEG_REG_COPY_TO_VMCB(pCtx, &pVmcb->guest, ES, es);
1418 HMSVM_SEG_REG_COPY_TO_VMCB(pCtx, &pVmcb->guest, FS, fs);
1419 HMSVM_SEG_REG_COPY_TO_VMCB(pCtx, &pVmcb->guest, GS, gs);
1420
1421 pVmcb->guest.u8CPL = pCtx->ss.Attr.n.u2Dpl;
1422 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_SEG;
1423 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_SEGMENT_REGS);
1424 }
1425
1426 /* Guest TR. */
1427 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_TR))
1428 {
1429 HMSVM_SEG_REG_COPY_TO_VMCB(pCtx, &pVmcb->guest, TR, tr);
1430 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_TR);
1431 }
1432
1433 /* Guest LDTR. */
1434 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_LDTR))
1435 {
1436 HMSVM_SEG_REG_COPY_TO_VMCB(pCtx, &pVmcb->guest, LDTR, ldtr);
1437 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LDTR);
1438 }
1439
1440 /* Guest GDTR. */
1441 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_GDTR))
1442 {
1443 pVmcb->guest.GDTR.u32Limit = pCtx->gdtr.cbGdt;
1444 pVmcb->guest.GDTR.u64Base = pCtx->gdtr.pGdt;
1445 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DT;
1446 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_GDTR);
1447 }
1448
1449 /* Guest IDTR. */
1450 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_IDTR))
1451 {
1452 pVmcb->guest.IDTR.u32Limit = pCtx->idtr.cbIdt;
1453 pVmcb->guest.IDTR.u64Base = pCtx->idtr.pIdt;
1454 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DT;
1455 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_IDTR);
1456 }
1457}
1458
1459
1460/**
1461 * Loads the guest MSRs into the VMCB.
1462 *
1463 * @param pVCpu The cross context virtual CPU structure.
1464 * @param pVmcb Pointer to the VM control block.
1465 * @param pCtx Pointer to the guest-CPU context.
1466 *
1467 * @remarks No-long-jump zone!!!
1468 */
1469static void hmR0SvmLoadGuestMsrs(PVMCPU pVCpu, PSVMVMCB pVmcb, PCPUMCTX pCtx)
1470{
1471 /* Guest Sysenter MSRs. */
1472 pVmcb->guest.u64SysEnterCS = pCtx->SysEnter.cs;
1473 pVmcb->guest.u64SysEnterEIP = pCtx->SysEnter.eip;
1474 pVmcb->guest.u64SysEnterESP = pCtx->SysEnter.esp;
1475
1476 /*
1477 * Guest EFER MSR.
1478 * AMD-V requires guest EFER.SVME to be set. Weird.
1479 * See AMD spec. 15.5.1 "Basic Operation" | "Canonicalization and Consistency Checks".
1480 */
1481 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_EFER_MSR))
1482 {
1483 pVmcb->guest.u64EFER = pCtx->msrEFER | MSR_K6_EFER_SVME;
1484 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CRX_EFER;
1485 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_EFER_MSR);
1486 }
1487
1488 /* 64-bit MSRs. */
1489 if (CPUMIsGuestInLongModeEx(pCtx))
1490 {
1491 pVmcb->guest.FS.u64Base = pCtx->fs.u64Base;
1492 pVmcb->guest.GS.u64Base = pCtx->gs.u64Base;
1493 }
1494 else
1495 {
1496 /* If the guest isn't in 64-bit mode, clear MSR_K6_LME bit from guest EFER otherwise AMD-V expects amd64 shadow paging. */
1497 if (pCtx->msrEFER & MSR_K6_EFER_LME)
1498 {
1499 pVmcb->guest.u64EFER &= ~MSR_K6_EFER_LME;
1500 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_CRX_EFER;
1501 }
1502 }
1503
1504 /** @todo The following are used in 64-bit only (SYSCALL/SYSRET) but they might
1505 * be writable in 32-bit mode. Clarify with AMD spec. */
1506 pVmcb->guest.u64STAR = pCtx->msrSTAR;
1507 pVmcb->guest.u64LSTAR = pCtx->msrLSTAR;
1508 pVmcb->guest.u64CSTAR = pCtx->msrCSTAR;
1509 pVmcb->guest.u64SFMASK = pCtx->msrSFMASK;
1510 pVmcb->guest.u64KernelGSBase = pCtx->msrKERNELGSBASE;
1511}
1512
1513
1514/**
1515 * Loads the guest (or nested-guest) debug state into the VMCB and programs the
1516 * necessary intercepts accordingly.
1517 *
1518 * @param pVCpu The cross context virtual CPU structure.
1519 * @param pVmcb Pointer to the VM control block.
1520 * @param pCtx Pointer to the guest-CPU context.
1521 *
1522 * @remarks No-long-jump zone!!!
1523 * @remarks Requires EFLAGS to be up-to-date in the VMCB!
1524 */
1525static void hmR0SvmLoadSharedDebugState(PVMCPU pVCpu, PSVMVMCB pVmcb, PCPUMCTX pCtx)
1526{
1527 Assert((pCtx->dr[6] & X86_DR6_RA1_MASK) == X86_DR6_RA1_MASK);
1528 Assert((pCtx->dr[6] & X86_DR6_RAZ_MASK) == 0);
1529 Assert((pCtx->dr[7] & X86_DR7_RA1_MASK) == X86_DR7_RA1_MASK);
1530 Assert((pCtx->dr[7] & X86_DR7_RAZ_MASK) == 0);
1531
1532 bool fInterceptMovDRx = false;
1533
1534 /*
1535 * Anyone single stepping on the host side? If so, we'll have to use the
1536 * trap flag in the guest EFLAGS since AMD-V doesn't have a trap flag on
1537 * the VMM level like the VT-x implementations does.
1538 */
1539 bool const fStepping = pVCpu->hm.s.fSingleInstruction;
1540 if (fStepping)
1541 {
1542 pVCpu->hm.s.fClearTrapFlag = true;
1543 pVmcb->guest.u64RFlags |= X86_EFL_TF;
1544 fInterceptMovDRx = true; /* Need clean DR6, no guest mess. */
1545 }
1546 else
1547 Assert(!DBGFIsStepping(pVCpu));
1548
1549 if ( fStepping
1550 || (CPUMGetHyperDR7(pVCpu) & X86_DR7_ENABLED_MASK))
1551 {
1552 /*
1553 * Use the combined guest and host DRx values found in the hypervisor
1554 * register set because the debugger has breakpoints active or someone
1555 * is single stepping on the host side.
1556 *
1557 * Note! DBGF expects a clean DR6 state before executing guest code.
1558 */
1559#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
1560 if ( CPUMIsGuestInLongModeEx(pCtx)
1561 && !CPUMIsHyperDebugStateActivePending(pVCpu))
1562 {
1563 CPUMR0LoadHyperDebugState(pVCpu, false /* include DR6 */);
1564 Assert(!CPUMIsGuestDebugStateActivePending(pVCpu));
1565 Assert(CPUMIsHyperDebugStateActivePending(pVCpu));
1566 }
1567 else
1568#endif
1569 if (!CPUMIsHyperDebugStateActive(pVCpu))
1570 {
1571 CPUMR0LoadHyperDebugState(pVCpu, false /* include DR6 */);
1572 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
1573 Assert(CPUMIsHyperDebugStateActive(pVCpu));
1574 }
1575
1576 /* Update DR6 & DR7. (The other DRx values are handled by CPUM one way or the other.) */
1577 if ( pVmcb->guest.u64DR6 != X86_DR6_INIT_VAL
1578 || pVmcb->guest.u64DR7 != CPUMGetHyperDR7(pVCpu))
1579 {
1580 pVmcb->guest.u64DR7 = CPUMGetHyperDR7(pVCpu);
1581 pVmcb->guest.u64DR6 = X86_DR6_INIT_VAL;
1582 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DRX;
1583 pVCpu->hm.s.fUsingHyperDR7 = true;
1584 }
1585
1586 /** @todo If we cared, we could optimize to allow the guest to read registers
1587 * with the same values. */
1588 fInterceptMovDRx = true;
1589 Log5(("hmR0SvmLoadSharedDebugState: Loaded hyper DRx\n"));
1590 }
1591 else
1592 {
1593 /*
1594 * Update DR6, DR7 with the guest values if necessary.
1595 */
1596 if ( pVmcb->guest.u64DR7 != pCtx->dr[7]
1597 || pVmcb->guest.u64DR6 != pCtx->dr[6])
1598 {
1599 pVmcb->guest.u64DR7 = pCtx->dr[7];
1600 pVmcb->guest.u64DR6 = pCtx->dr[6];
1601 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DRX;
1602 pVCpu->hm.s.fUsingHyperDR7 = false;
1603 }
1604
1605 /*
1606 * If the guest has enabled debug registers, we need to load them prior to
1607 * executing guest code so they'll trigger at the right time.
1608 */
1609 if (pCtx->dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD)) /** @todo Why GD? */
1610 {
1611#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
1612 if ( CPUMIsGuestInLongModeEx(pCtx)
1613 && !CPUMIsGuestDebugStateActivePending(pVCpu))
1614 {
1615 CPUMR0LoadGuestDebugState(pVCpu, false /* include DR6 */);
1616 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
1617 Assert(!CPUMIsHyperDebugStateActivePending(pVCpu));
1618 Assert(CPUMIsGuestDebugStateActivePending(pVCpu));
1619 }
1620 else
1621#endif
1622 if (!CPUMIsGuestDebugStateActive(pVCpu))
1623 {
1624 CPUMR0LoadGuestDebugState(pVCpu, false /* include DR6 */);
1625 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
1626 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
1627 Assert(CPUMIsGuestDebugStateActive(pVCpu));
1628 }
1629 Log5(("hmR0SvmLoadSharedDebugState: Loaded guest DRx\n"));
1630 }
1631 /*
1632 * If no debugging enabled, we'll lazy load DR0-3. We don't need to
1633 * intercept #DB as DR6 is updated in the VMCB.
1634 *
1635 * Note! If we cared and dared, we could skip intercepting \#DB here.
1636 * However, \#DB shouldn't be performance critical, so we'll play safe
1637 * and keep the code similar to the VT-x code and always intercept it.
1638 */
1639#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
1640 else if ( !CPUMIsGuestDebugStateActivePending(pVCpu)
1641 && !CPUMIsGuestDebugStateActive(pVCpu))
1642#else
1643 else if (!CPUMIsGuestDebugStateActive(pVCpu))
1644#endif
1645 {
1646 fInterceptMovDRx = true;
1647 }
1648 }
1649
1650 Assert(pVmcb->ctrl.u32InterceptXcpt & RT_BIT_32(X86_XCPT_DB));
1651 if (fInterceptMovDRx)
1652 {
1653 if ( pVmcb->ctrl.u16InterceptRdDRx != 0xffff
1654 || pVmcb->ctrl.u16InterceptWrDRx != 0xffff)
1655 {
1656 pVmcb->ctrl.u16InterceptRdDRx = 0xffff;
1657 pVmcb->ctrl.u16InterceptWrDRx = 0xffff;
1658 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
1659 }
1660 }
1661 else
1662 {
1663 if ( pVmcb->ctrl.u16InterceptRdDRx
1664 || pVmcb->ctrl.u16InterceptWrDRx)
1665 {
1666 pVmcb->ctrl.u16InterceptRdDRx = 0;
1667 pVmcb->ctrl.u16InterceptWrDRx = 0;
1668 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
1669 }
1670 }
1671}
1672
1673
1674#ifdef VBOX_WITH_NESTED_HWVIRT
1675/**
1676 * Loads the nested-guest APIC state (currently just the TPR).
1677 *
1678 * @param pVCpu The cross context virtual CPU structure.
1679 * @param pVmcbNstGst Pointer to the nested-guest VM control block.
1680 */
1681static void hmR0SvmLoadGuestApicStateNested(PVMCPU pVCpu, PSVMVMCB pVmcbNstGst)
1682{
1683 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE))
1684 {
1685 /* Always enable V_INTR_MASKING as we do not want to allow access to the physical APIC TPR. */
1686 pVmcbNstGst->ctrl.IntCtrl.n.u1VIntrMasking = 1;
1687 pVCpu->hm.s.svm.fSyncVTpr = false;
1688 pVmcbNstGst->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_TPR;
1689
1690 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE);
1691 }
1692}
1693#endif
1694
1695/**
1696 * Loads the guest APIC state (currently just the TPR).
1697 *
1698 * @returns VBox status code.
1699 * @param pVCpu The cross context virtual CPU structure.
1700 * @param pVmcb Pointer to the VM control block.
1701 * @param pCtx Pointer to the guest-CPU context.
1702 */
1703static int hmR0SvmLoadGuestApicState(PVMCPU pVCpu, PSVMVMCB pVmcb, PCPUMCTX pCtx)
1704{
1705 if (!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE))
1706 return VINF_SUCCESS;
1707
1708 int rc = VINF_SUCCESS;
1709 PVM pVM = pVCpu->CTX_SUFF(pVM);
1710 if ( PDMHasApic(pVM)
1711 && APICIsEnabled(pVCpu))
1712 {
1713 bool fPendingIntr;
1714 uint8_t u8Tpr;
1715 rc = APICGetTpr(pVCpu, &u8Tpr, &fPendingIntr, NULL /* pu8PendingIrq */);
1716 AssertRCReturn(rc, rc);
1717
1718 /* Assume that we need to trap all TPR accesses and thus need not check on
1719 every #VMEXIT if we should update the TPR. */
1720 Assert(pVmcb->ctrl.IntCtrl.n.u1VIntrMasking);
1721 pVCpu->hm.s.svm.fSyncVTpr = false;
1722
1723 /* 32-bit guests uses LSTAR MSR for patching guest code which touches the TPR. */
1724 if (pVM->hm.s.fTPRPatchingActive)
1725 {
1726 pCtx->msrLSTAR = u8Tpr;
1727 uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.svm.pvMsrBitmap;
1728
1729 /* If there are interrupts pending, intercept LSTAR writes, otherwise don't intercept reads or writes. */
1730 if (fPendingIntr)
1731 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_LSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_INTERCEPT_WRITE);
1732 else
1733 {
1734 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_LSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
1735 pVCpu->hm.s.svm.fSyncVTpr = true;
1736 }
1737 }
1738 else
1739 {
1740 /* Bits 3-0 of the VTPR field correspond to bits 7-4 of the TPR (which is the Task-Priority Class). */
1741 pVmcb->ctrl.IntCtrl.n.u8VTPR = (u8Tpr >> 4);
1742
1743 /* If there are interrupts pending, intercept CR8 writes to evaluate ASAP if we can deliver the interrupt to the guest. */
1744 if (fPendingIntr)
1745 pVmcb->ctrl.u16InterceptWrCRx |= RT_BIT(8);
1746 else
1747 {
1748 pVmcb->ctrl.u16InterceptWrCRx &= ~RT_BIT(8);
1749 pVCpu->hm.s.svm.fSyncVTpr = true;
1750 }
1751
1752 pVmcb->ctrl.u64VmcbCleanBits &= ~(HMSVM_VMCB_CLEAN_INTERCEPTS | HMSVM_VMCB_CLEAN_TPR);
1753 }
1754 }
1755
1756 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE);
1757 return rc;
1758}
1759
1760
1761/**
1762 * Loads the exception interrupts required for guest (or nested-guest) execution in
1763 * the VMCB.
1764 *
1765 * @param pVCpu The cross context virtual CPU structure.
1766 * @param pVmcb Pointer to the VM control block.
1767 */
1768static void hmR0SvmLoadGuestXcptIntercepts(PVMCPU pVCpu, PSVMVMCB pVmcb)
1769{
1770 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
1771 {
1772 /* Trap #UD for GIM provider (e.g. for hypercalls). */
1773 if (pVCpu->hm.s.fGIMTrapXcptUD)
1774 hmR0SvmAddXcptIntercept(pVmcb, X86_XCPT_UD);
1775 else
1776 hmR0SvmRemoveXcptIntercept(pVmcb, X86_XCPT_UD);
1777
1778 /* Trap #BP for INT3 debug breakpoints set by the VM debugger. */
1779 if (pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledInt3Breakpoints)
1780 hmR0SvmAddXcptIntercept(pVmcb, X86_XCPT_BP);
1781 else
1782 hmR0SvmRemoveXcptIntercept(pVmcb, X86_XCPT_BP);
1783
1784 /* The remaining intercepts are handled elsewhere, e.g. in hmR0SvmLoadSharedCR0(). */
1785 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS);
1786 }
1787}
1788
1789
1790#ifdef VBOX_WITH_NESTED_HWVIRT
1791/**
1792 * Loads the intercepts required for nested-guest execution in the VMCB.
1793 *
1794 * This merges the guest and nested-guest intercepts in a way that if the outer
1795 * guest intercepts an exception we need to intercept it in the nested-guest as
1796 * well and handle it accordingly.
1797 *
1798 * @param pVCpu The cross context virtual CPU structure.
1799 * @param pVmcb Pointer to the VM control block.
1800 * @param pVmcbNstGst Pointer to the nested-guest VM control block.
1801 */
1802static void hmR0SvmLoadGuestXcptInterceptsNested(PVMCPU pVCpu, PSVMVMCB pVmcb, PSVMVMCB pVmcbNstGst)
1803{
1804 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS))
1805 {
1806 hmR0SvmLoadGuestXcptIntercepts(pVCpu, pVmcb);
1807
1808 pVmcbNstGst->ctrl.u16InterceptRdCRx |= pVmcb->ctrl.u16InterceptRdCRx;
1809 pVmcbNstGst->ctrl.u16InterceptWrCRx |= pVmcb->ctrl.u16InterceptWrCRx;
1810
1811 /** @todo Figure out debugging with nested-guests, till then just intercept
1812 * all DR[0-15] accesses. */
1813 pVmcbNstGst->ctrl.u16InterceptRdDRx |= 0xffff;
1814 pVmcbNstGst->ctrl.u16InterceptWrDRx |= 0xffff;
1815
1816 pVmcbNstGst->ctrl.u32InterceptXcpt |= pVmcb->ctrl.u32InterceptXcpt;
1817 pVmcbNstGst->ctrl.u64InterceptCtrl |= pVmcb->ctrl.u64InterceptCtrl
1818 | HMSVM_MANDATORY_NESTED_GUEST_CTRL_INTERCEPTS;
1819
1820 Assert( (pVmcbNstGst->ctrl.u64InterceptCtrl & HMSVM_MANDATORY_GUEST_CTRL_INTERCEPTS)
1821 == HMSVM_MANDATORY_GUEST_CTRL_INTERCEPTS);
1822
1823 Assert(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_XCPT_INTERCEPTS));
1824 }
1825}
1826#endif
1827
1828
1829/**
1830 * Sets up the appropriate function to run guest code.
1831 *
1832 * @returns VBox status code.
1833 * @param pVCpu The cross context virtual CPU structure.
1834 *
1835 * @remarks No-long-jump zone!!!
1836 */
1837static int hmR0SvmSetupVMRunHandler(PVMCPU pVCpu)
1838{
1839 if (CPUMIsGuestInLongMode(pVCpu))
1840 {
1841#ifndef VBOX_ENABLE_64_BITS_GUESTS
1842 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1843#endif
1844 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
1845#if HC_ARCH_BITS == 32
1846 /* 32-bit host. We need to switch to 64-bit before running the 64-bit guest. */
1847 pVCpu->hm.s.svm.pfnVMRun = SVMR0VMSwitcherRun64;
1848#else
1849 /* 64-bit host or hybrid host. */
1850 pVCpu->hm.s.svm.pfnVMRun = SVMR0VMRun64;
1851#endif
1852 }
1853 else
1854 {
1855 /* Guest is not in long mode, use the 32-bit handler. */
1856 pVCpu->hm.s.svm.pfnVMRun = SVMR0VMRun;
1857 }
1858 return VINF_SUCCESS;
1859}
1860
1861
1862/**
1863 * Enters the AMD-V session.
1864 *
1865 * @returns VBox status code.
1866 * @param pVM The cross context VM structure.
1867 * @param pVCpu The cross context virtual CPU structure.
1868 * @param pCpu Pointer to the CPU info struct.
1869 */
1870VMMR0DECL(int) SVMR0Enter(PVM pVM, PVMCPU pVCpu, PHMGLOBALCPUINFO pCpu)
1871{
1872 AssertPtr(pVM);
1873 AssertPtr(pVCpu);
1874 Assert(pVM->hm.s.svm.fSupported);
1875 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1876 NOREF(pVM); NOREF(pCpu);
1877
1878 LogFlowFunc(("pVM=%p pVCpu=%p\n", pVM, pVCpu));
1879 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
1880
1881 pVCpu->hm.s.fLeaveDone = false;
1882 return VINF_SUCCESS;
1883}
1884
1885
1886/**
1887 * Thread-context callback for AMD-V.
1888 *
1889 * @param enmEvent The thread-context event.
1890 * @param pVCpu The cross context virtual CPU structure.
1891 * @param fGlobalInit Whether global VT-x/AMD-V init. is used.
1892 * @thread EMT(pVCpu)
1893 */
1894VMMR0DECL(void) SVMR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, PVMCPU pVCpu, bool fGlobalInit)
1895{
1896 NOREF(fGlobalInit);
1897
1898 switch (enmEvent)
1899 {
1900 case RTTHREADCTXEVENT_OUT:
1901 {
1902 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1903 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
1904 VMCPU_ASSERT_EMT(pVCpu);
1905
1906 /* No longjmps (log-flush, locks) in this fragile context. */
1907 VMMRZCallRing3Disable(pVCpu);
1908
1909 if (!pVCpu->hm.s.fLeaveDone)
1910 {
1911 hmR0SvmLeave(pVCpu);
1912 pVCpu->hm.s.fLeaveDone = true;
1913 }
1914
1915 /* Leave HM context, takes care of local init (term). */
1916 int rc = HMR0LeaveCpu(pVCpu);
1917 AssertRC(rc); NOREF(rc);
1918
1919 /* Restore longjmp state. */
1920 VMMRZCallRing3Enable(pVCpu);
1921 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatSwitchPreempt);
1922 break;
1923 }
1924
1925 case RTTHREADCTXEVENT_IN:
1926 {
1927 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1928 Assert(VMMR0ThreadCtxHookIsEnabled(pVCpu));
1929 VMCPU_ASSERT_EMT(pVCpu);
1930
1931 /* No longjmps (log-flush, locks) in this fragile context. */
1932 VMMRZCallRing3Disable(pVCpu);
1933
1934 /*
1935 * Initialize the bare minimum state required for HM. This takes care of
1936 * initializing AMD-V if necessary (onlined CPUs, local init etc.)
1937 */
1938 int rc = HMR0EnterCpu(pVCpu);
1939 AssertRC(rc); NOREF(rc);
1940 Assert(HMCPU_CF_IS_SET(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE));
1941
1942 pVCpu->hm.s.fLeaveDone = false;
1943
1944 /* Restore longjmp state. */
1945 VMMRZCallRing3Enable(pVCpu);
1946 break;
1947 }
1948
1949 default:
1950 break;
1951 }
1952}
1953
1954
1955/**
1956 * Saves the host state.
1957 *
1958 * @returns VBox status code.
1959 * @param pVM The cross context VM structure.
1960 * @param pVCpu The cross context virtual CPU structure.
1961 *
1962 * @remarks No-long-jump zone!!!
1963 */
1964VMMR0DECL(int) SVMR0SaveHostState(PVM pVM, PVMCPU pVCpu)
1965{
1966 NOREF(pVM);
1967 NOREF(pVCpu);
1968 /* Nothing to do here. AMD-V does this for us automatically during the world-switch. */
1969 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_HOST_CONTEXT);
1970 return VINF_SUCCESS;
1971}
1972
1973
1974/**
1975 * Loads the guest state into the VMCB.
1976 *
1977 * The CPU state will be loaded from these fields on every successful VM-entry.
1978 * Also sets up the appropriate VMRUN function to execute guest code based on
1979 * the guest CPU mode.
1980 *
1981 * @returns VBox status code.
1982 * @param pVM The cross context VM structure.
1983 * @param pVCpu The cross context virtual CPU structure.
1984 * @param pCtx Pointer to the guest-CPU context.
1985 *
1986 * @remarks No-long-jump zone!!!
1987 */
1988static int hmR0SvmLoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1989{
1990 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
1991 AssertMsgReturn(pVmcb, ("Invalid pVmcb\n"), VERR_SVM_INVALID_PVMCB);
1992
1993 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestState, x);
1994
1995 int rc = hmR0SvmLoadGuestControlRegs(pVCpu, pVmcb, pCtx);
1996 AssertLogRelMsgRCReturn(rc, ("hmR0SvmLoadGuestControlRegs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
1997
1998 hmR0SvmLoadGuestSegmentRegs(pVCpu, pVmcb, pCtx);
1999 hmR0SvmLoadGuestMsrs(pVCpu, pVmcb, pCtx);
2000
2001 pVmcb->guest.u64RIP = pCtx->rip;
2002 pVmcb->guest.u64RSP = pCtx->rsp;
2003 pVmcb->guest.u64RFlags = pCtx->eflags.u32;
2004 pVmcb->guest.u64RAX = pCtx->rax;
2005
2006 rc = hmR0SvmLoadGuestApicState(pVCpu, pVmcb, pCtx);
2007 AssertLogRelMsgRCReturn(rc, ("hmR0SvmLoadGuestApicState! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
2008
2009 hmR0SvmLoadGuestXcptIntercepts(pVCpu, pVmcb);
2010
2011 rc = hmR0SvmSetupVMRunHandler(pVCpu);
2012 AssertLogRelMsgRCReturn(rc, ("hmR0SvmSetupVMRunHandler! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
2013
2014 /* Clear any unused and reserved bits. */
2015 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RIP /* Unused (loaded unconditionally). */
2016 | HM_CHANGED_GUEST_RSP
2017 | HM_CHANGED_GUEST_RFLAGS
2018 | HM_CHANGED_GUEST_SYSENTER_CS_MSR
2019 | HM_CHANGED_GUEST_SYSENTER_EIP_MSR
2020 | HM_CHANGED_GUEST_SYSENTER_ESP_MSR
2021 | HM_CHANGED_GUEST_LAZY_MSRS /* Unused. */
2022 | HM_CHANGED_SVM_NESTED_GUEST
2023 | HM_CHANGED_SVM_RESERVED1 /* Reserved. */
2024 | HM_CHANGED_SVM_RESERVED2
2025 | HM_CHANGED_SVM_RESERVED3);
2026
2027 /* All the guest state bits should be loaded except maybe the host context and/or shared host/guest bits. */
2028 AssertMsg( !HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_ALL_GUEST)
2029 || HMCPU_CF_IS_PENDING_ONLY(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE),
2030 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
2031
2032 Log4(("hmR0SvmLoadGuestState: CS:RIP=%04x:%RX64 EFL=%#x CR0=%#RX32 CR3=%#RX32 CR4=%#RX32\n", pCtx->cs.Sel, pCtx->rip,
2033 pCtx->eflags.u, pCtx->cr0, pCtx->cr3, pCtx->cr4));
2034 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
2035 return rc;
2036}
2037
2038
2039#ifdef VBOX_WITH_NESTED_HWVIRT
2040/**
2041 * Caches the nested-guest VMCB fields before we modify them for execution using
2042 * hardware-assisted SVM.
2043 *
2044 * @param pCtx Pointer to the guest-CPU context.
2045 *
2046 * @sa HMSvmNstGstVmExitNotify.
2047 */
2048static void hmR0SvmVmRunCacheVmcb(PVMCPU pVCpu, PCPUMCTX pCtx)
2049{
2050 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
2051 PCSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
2052 PCSVMVMCBSTATESAVE pVmcbNstGstState = &pVmcbNstGst->guest;
2053 PSVMNESTEDVMCBCACHE pNstGstVmcbCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
2054
2055 pNstGstVmcbCache->u16InterceptRdCRx = pVmcbNstGstCtrl->u16InterceptRdCRx;
2056 pNstGstVmcbCache->u16InterceptWrCRx = pVmcbNstGstCtrl->u16InterceptWrCRx;
2057 pNstGstVmcbCache->u16InterceptRdDRx = pVmcbNstGstCtrl->u16InterceptRdDRx;
2058 pNstGstVmcbCache->u16InterceptWrCRx = pVmcbNstGstCtrl->u16InterceptWrDRx;
2059 pNstGstVmcbCache->u32InterceptXcpt = pVmcbNstGstCtrl->u32InterceptXcpt;
2060 pNstGstVmcbCache->u64InterceptCtrl = pVmcbNstGstCtrl->u64InterceptCtrl;
2061 pNstGstVmcbCache->u64CR3 = pVmcbNstGstState->u64CR3;
2062 pNstGstVmcbCache->u64IOPMPhysAddr = pVmcbNstGstCtrl->u64IOPMPhysAddr;
2063 pNstGstVmcbCache->u64MSRPMPhysAddr = pVmcbNstGstCtrl->u64MSRPMPhysAddr;
2064 pNstGstVmcbCache->u64VmcbCleanBits = pVmcbNstGstCtrl->u64VmcbCleanBits;
2065 pNstGstVmcbCache->fVIntrMasking = pVmcbNstGstCtrl->IntCtrl.n.u1VIntrMasking;
2066 pNstGstVmcbCache->TLBCtrl = pVmcbNstGstCtrl->TLBCtrl;
2067 pNstGstVmcbCache->fValid = true;
2068}
2069
2070
2071/**
2072 * Sets up the nested-guest VMCB for execution using hardware-assisted SVM.
2073 *
2074 * @param pVCpu The cross context virtual CPU structure.
2075 * @param pCtx Pointer to the guest-CPU context.
2076 */
2077static void hmR0SvmVmRunSetupVmcb(PVMCPU pVCpu, PCPUMCTX pCtx)
2078{
2079 RT_NOREF(pVCpu);
2080 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
2081 PSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
2082
2083 /*
2084 * First cache the nested-guest VMCB fields we may potentially modify.
2085 */
2086 hmR0SvmVmRunCacheVmcb(pVCpu, pCtx);
2087
2088 /*
2089 * The IOPM of the nested-guest can be ignored because the the guest always
2090 * intercepts all IO port accesses. Thus, we'll swap to the guest IOPM rather
2091 * into the nested-guest one and swap it back on the #VMEXIT.
2092 */
2093 pVmcbNstGstCtrl->u64IOPMPhysAddr = g_HCPhysIOBitmap;
2094
2095 /*
2096 * Load the host-physical address into the MSRPM rather than the nested-guest
2097 * physical address (currently we trap all MSRs in the nested-guest).
2098 */
2099 pVmcbNstGstCtrl->u64MSRPMPhysAddr = g_HCPhysNstGstMsrBitmap;
2100}
2101
2102
2103/**
2104 * Sets up the nested-guest for hardware-assisted SVM execution.
2105 *
2106 * @param pVCpu The cross context virtual CPU structure.
2107 * @param pCtx Pointer to the guest-CPU context.
2108 *
2109 * @remarks This must be called only after the guest exceptions are up to date as
2110 * otherwise we risk overwriting the guest exceptions with the nested-guest
2111 * exceptions.
2112 */
2113static void hmR0SvmLoadGuestVmcbNested(PVMCPU pVCpu, PCPUMCTX pCtx)
2114{
2115 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_SVM_NESTED_GUEST))
2116 {
2117 hmR0SvmVmRunSetupVmcb(pVCpu, pCtx);
2118 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_SVM_NESTED_GUEST);
2119 }
2120}
2121
2122
2123/**
2124 * Loads the nested-guest state into the VMCB.
2125 *
2126 * @returns VBox status code.
2127 * @param pVCpu The cross context virtual CPU structure.
2128 * @param pCtx Pointer to the guest-CPU context.
2129 *
2130 * @remarks No-long-jump zone!!!
2131 */
2132static int hmR0SvmLoadGuestStateNested(PVMCPU pVCpu, PCPUMCTX pCtx)
2133{
2134 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestState, x);
2135
2136 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
2137 Assert(pVmcbNstGst);
2138
2139 /*
2140 * If we just emulated VMRUN, the VMCB is already in-sync with the guest-CPU context.
2141 */
2142 if (!pVCpu->hm.s.svm.NstGstVmcbCache.fVmrunEmulatedInR0)
2143 {
2144 /* First, we need to setup the nested-guest VMCB for hardware-assisted SVM execution. */
2145 hmR0SvmLoadGuestVmcbNested(pVCpu, pCtx);
2146
2147 hmR0SvmLoadGuestSegmentRegs(pVCpu, pVmcbNstGst, pCtx);
2148 hmR0SvmLoadGuestMsrs(pVCpu, pVmcbNstGst, pCtx);
2149
2150 pVmcbNstGst->guest.u64RIP = pCtx->rip;
2151 pVmcbNstGst->guest.u64RSP = pCtx->rsp;
2152 pVmcbNstGst->guest.u64RFlags = pCtx->eflags.u32;
2153 pVmcbNstGst->guest.u64RAX = pCtx->rax;
2154 }
2155
2156 hmR0SvmLoadGuestControlRegsNested(pVCpu, pVmcbNstGst, pCtx);
2157 hmR0SvmLoadGuestApicStateNested(pVCpu, pVmcbNstGst);
2158
2159 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
2160 hmR0SvmLoadGuestXcptInterceptsNested(pVCpu, pVmcb, pVmcbNstGst);
2161
2162 int rc = hmR0SvmSetupVMRunHandler(pVCpu);
2163 AssertRCReturn(rc, rc);
2164
2165 /* Clear any unused and reserved bits. */
2166 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_RIP /* Unused (loaded unconditionally). */
2167 | HM_CHANGED_GUEST_RSP
2168 | HM_CHANGED_GUEST_RFLAGS
2169 | HM_CHANGED_GUEST_SYSENTER_CS_MSR
2170 | HM_CHANGED_GUEST_SYSENTER_EIP_MSR
2171 | HM_CHANGED_GUEST_SYSENTER_ESP_MSR
2172 | HM_CHANGED_GUEST_LAZY_MSRS /* Unused. */
2173 | HM_CHANGED_SVM_RESERVED1 /* Reserved. */
2174 | HM_CHANGED_SVM_RESERVED2
2175 | HM_CHANGED_SVM_RESERVED3);
2176
2177 /* All the guest state bits should be loaded except maybe the host context and/or shared host/guest bits. */
2178 AssertMsg( !HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_ALL_GUEST)
2179 || HMCPU_CF_IS_PENDING_ONLY(pVCpu, HM_CHANGED_HOST_CONTEXT | HM_CHANGED_HOST_GUEST_SHARED_STATE),
2180 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
2181
2182 Log4(("hmR0SvmLoadGuestStateNested: CS:RIP=%04x:%RX64 EFL=%#x CR0=%#RX32 CR3=%#RX32 CR4=%#RX32\n", pCtx->cs.Sel, pCtx->rip,
2183 pCtx->eflags.u, pCtx->cr0, pCtx->cr3, pCtx->cr4));
2184 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
2185 return rc;
2186}
2187#endif
2188
2189
2190/**
2191 * Loads the state shared between the host and guest or nested-guest into the
2192 * VMCB.
2193 *
2194 * @param pVCpu The cross context virtual CPU structure.
2195 * @param pVmcb Pointer to the VM control block.
2196 * @param pCtx Pointer to the guest-CPU context.
2197 *
2198 * @remarks No-long-jump zone!!!
2199 */
2200static void hmR0SvmLoadSharedState(PVMCPU pVCpu, PSVMVMCB pVmcb, PCPUMCTX pCtx)
2201{
2202 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2203 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2204
2205 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0))
2206 {
2207#ifdef VBOX_WITH_NESTED_HWVIRT
2208 /* We use nested-guest CR0 unmodified, hence nothing to do here. */
2209 if (!CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
2210 hmR0SvmLoadSharedCR0(pVCpu, pVmcb, pCtx);
2211 else
2212 Assert(pVmcb->guest.u64CR0 == pCtx->cr0);
2213#else
2214 hmR0SvmLoadSharedCR0(pVCpu, pVmcb, pCtx);
2215#endif
2216 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_CR0);
2217 }
2218
2219 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_DEBUG))
2220 {
2221 hmR0SvmLoadSharedDebugState(pVCpu, pVmcb, pCtx);
2222 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_DEBUG);
2223 }
2224
2225 /* Unused on AMD-V. */
2226 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_GUEST_LAZY_MSRS);
2227
2228 AssertMsg(!HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE),
2229 ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
2230}
2231
2232
2233/**
2234 * Saves the guest (or nested-guest) state from the VMCB into the guest-CPU context.
2235 *
2236 * Currently there is no residual state left in the CPU that is not updated in the
2237 * VMCB.
2238 *
2239 * @returns VBox status code.
2240 * @param pVCpu The cross context virtual CPU structure.
2241 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
2242 * out-of-sync. Make sure to update the required fields
2243 * before using them.
2244 * @param pVmcb Pointer to the VM control block.
2245 */
2246static void hmR0SvmSaveGuestState(PVMCPU pVCpu, PCPUMCTX pMixedCtx, PCSVMVMCB pVmcb)
2247{
2248 Assert(VMMRZCallRing3IsEnabled(pVCpu));
2249
2250 pMixedCtx->rip = pVmcb->guest.u64RIP;
2251 pMixedCtx->rsp = pVmcb->guest.u64RSP;
2252 pMixedCtx->eflags.u32 = pVmcb->guest.u64RFlags;
2253 pMixedCtx->rax = pVmcb->guest.u64RAX;
2254
2255 /*
2256 * Guest interrupt shadow.
2257 */
2258 if (pVmcb->ctrl.u64IntShadow & SVM_INTERRUPT_SHADOW_ACTIVE)
2259 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
2260 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
2261 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
2262
2263 /*
2264 * Guest Control registers: CR2, CR3 (handled at the end) - accesses to other control registers are always intercepted.
2265 */
2266 pMixedCtx->cr2 = pVmcb->guest.u64CR2;
2267
2268#ifdef VBOX_WITH_NESTED_GUEST
2269 /*
2270 * The nested hypervisor might not be intercepting these control registers,
2271 */
2272 if (CPUMIsGuestInNestedHwVirtMode(pMixedCtx))
2273 {
2274 pMixedCtx->cr3 = pVmcb->guest.u64CR3;
2275 pMixedCtx->cr4 = pVmcb->guest.u64CR4;
2276 pMixedCtx->cr0 = pVmcb->guest.u64CR0;
2277 }
2278#endif
2279
2280 /*
2281 * Guest MSRs.
2282 */
2283 pMixedCtx->msrSTAR = pVmcb->guest.u64STAR; /* legacy syscall eip, cs & ss */
2284 pMixedCtx->msrLSTAR = pVmcb->guest.u64LSTAR; /* 64-bit mode syscall rip */
2285 pMixedCtx->msrCSTAR = pVmcb->guest.u64CSTAR; /* compatibility mode syscall rip */
2286 pMixedCtx->msrSFMASK = pVmcb->guest.u64SFMASK; /* syscall flag mask */
2287 pMixedCtx->msrKERNELGSBASE = pVmcb->guest.u64KernelGSBase; /* swapgs exchange value */
2288 pMixedCtx->SysEnter.cs = pVmcb->guest.u64SysEnterCS;
2289 pMixedCtx->SysEnter.eip = pVmcb->guest.u64SysEnterEIP;
2290 pMixedCtx->SysEnter.esp = pVmcb->guest.u64SysEnterESP;
2291
2292 /*
2293 * Guest segment registers (includes FS, GS base MSRs for 64-bit guests).
2294 */
2295 HMSVM_SEG_REG_COPY_FROM_VMCB(pMixedCtx, &pVmcb->guest, CS, cs);
2296 HMSVM_SEG_REG_COPY_FROM_VMCB(pMixedCtx, &pVmcb->guest, SS, ss);
2297 HMSVM_SEG_REG_COPY_FROM_VMCB(pMixedCtx, &pVmcb->guest, DS, ds);
2298 HMSVM_SEG_REG_COPY_FROM_VMCB(pMixedCtx, &pVmcb->guest, ES, es);
2299 HMSVM_SEG_REG_COPY_FROM_VMCB(pMixedCtx, &pVmcb->guest, FS, fs);
2300 HMSVM_SEG_REG_COPY_FROM_VMCB(pMixedCtx, &pVmcb->guest, GS, gs);
2301
2302 /*
2303 * Correct the hidden CS granularity bit. Haven't seen it being wrong in any other
2304 * register (yet).
2305 */
2306 /** @todo SELM might need to be fixed as it too should not care about the
2307 * granularity bit. See @bugref{6785}. */
2308 if ( !pMixedCtx->cs.Attr.n.u1Granularity
2309 && pMixedCtx->cs.Attr.n.u1Present
2310 && pMixedCtx->cs.u32Limit > UINT32_C(0xfffff))
2311 {
2312 Assert((pMixedCtx->cs.u32Limit & 0xfff) == 0xfff);
2313 pMixedCtx->cs.Attr.n.u1Granularity = 1;
2314 }
2315
2316#ifdef VBOX_STRICT
2317# define HMSVM_ASSERT_SEG_GRANULARITY(reg) \
2318 AssertMsg( !pMixedCtx->reg.Attr.n.u1Present \
2319 || ( pMixedCtx->reg.Attr.n.u1Granularity \
2320 ? (pMixedCtx->reg.u32Limit & 0xfff) == 0xfff \
2321 : pMixedCtx->reg.u32Limit <= UINT32_C(0xfffff)), \
2322 ("Invalid Segment Attributes Limit=%#RX32 Attr=%#RX32 Base=%#RX64\n", pMixedCtx->reg.u32Limit, \
2323 pMixedCtx->reg.Attr.u, pMixedCtx->reg.u64Base))
2324
2325 HMSVM_ASSERT_SEG_GRANULARITY(cs);
2326 HMSVM_ASSERT_SEG_GRANULARITY(ss);
2327 HMSVM_ASSERT_SEG_GRANULARITY(ds);
2328 HMSVM_ASSERT_SEG_GRANULARITY(es);
2329 HMSVM_ASSERT_SEG_GRANULARITY(fs);
2330 HMSVM_ASSERT_SEG_GRANULARITY(gs);
2331
2332# undef HMSVM_ASSERT_SEL_GRANULARITY
2333#endif
2334
2335 /*
2336 * Sync the hidden SS DPL field. AMD CPUs have a separate CPL field in the VMCB and uses that
2337 * and thus it's possible that when the CPL changes during guest execution that the SS DPL
2338 * isn't updated by AMD-V. Observed on some AMD Fusion CPUs with 64-bit guests.
2339 * See AMD spec. 15.5.1 "Basic operation".
2340 */
2341 Assert(!(pVmcb->guest.u8CPL & ~0x3));
2342 pMixedCtx->ss.Attr.n.u2Dpl = pVmcb->guest.u8CPL & 0x3;
2343
2344 /*
2345 * Guest TR.
2346 * Fixup TR attributes so it's compatible with Intel. Important when saved-states are used
2347 * between Intel and AMD. See @bugref{6208#c39}.
2348 * ASSUME that it's normally correct and that we're in 32-bit or 64-bit mode.
2349 */
2350 HMSVM_SEG_REG_COPY_FROM_VMCB(pMixedCtx, &pVmcb->guest, TR, tr);
2351 if (pMixedCtx->tr.Attr.n.u4Type != X86_SEL_TYPE_SYS_386_TSS_BUSY)
2352 {
2353 if ( pMixedCtx->tr.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_AVAIL
2354 || CPUMIsGuestInLongModeEx(pMixedCtx))
2355 pMixedCtx->tr.Attr.n.u4Type = X86_SEL_TYPE_SYS_386_TSS_BUSY;
2356 else if (pMixedCtx->tr.Attr.n.u4Type == X86_SEL_TYPE_SYS_286_TSS_AVAIL)
2357 pMixedCtx->tr.Attr.n.u4Type = X86_SEL_TYPE_SYS_286_TSS_BUSY;
2358 }
2359
2360 /*
2361 * Guest Descriptor-Table registers.
2362 */
2363 HMSVM_SEG_REG_COPY_FROM_VMCB(pMixedCtx, &pVmcb->guest, LDTR, ldtr);
2364 pMixedCtx->gdtr.cbGdt = pVmcb->guest.GDTR.u32Limit;
2365 pMixedCtx->gdtr.pGdt = pVmcb->guest.GDTR.u64Base;
2366
2367 pMixedCtx->idtr.cbIdt = pVmcb->guest.IDTR.u32Limit;
2368 pMixedCtx->idtr.pIdt = pVmcb->guest.IDTR.u64Base;
2369
2370 /*
2371 * Guest Debug registers.
2372 */
2373 if (!pVCpu->hm.s.fUsingHyperDR7)
2374 {
2375 pMixedCtx->dr[6] = pVmcb->guest.u64DR6;
2376 pMixedCtx->dr[7] = pVmcb->guest.u64DR7;
2377 }
2378 else
2379 {
2380 Assert(pVmcb->guest.u64DR7 == CPUMGetHyperDR7(pVCpu));
2381 CPUMSetHyperDR6(pVCpu, pVmcb->guest.u64DR6);
2382 }
2383
2384 /*
2385 * With Nested Paging, CR3 changes are not intercepted. Therefore, sync. it now.
2386 * This is done as the very last step of syncing the guest state, as PGMUpdateCR3() may cause longjmp's to ring-3.
2387 */
2388#ifdef VBOX_WITH_NESTED_HWVIRT
2389 Assert(!CPUMIsGuestInSvmNestedHwVirtMode(pMixedCtx) || !pVmcb->ctrl.NestedPaging.n.u1NestedPaging);
2390#endif
2391 if ( pVmcb->ctrl.NestedPaging.n.u1NestedPaging
2392 && pMixedCtx->cr3 != pVmcb->guest.u64CR3)
2393 {
2394 CPUMSetGuestCR3(pVCpu, pVmcb->guest.u64CR3);
2395 PGMUpdateCR3(pVCpu, pVmcb->guest.u64CR3);
2396 }
2397}
2398
2399
2400/**
2401 * Does the necessary state syncing before returning to ring-3 for any reason
2402 * (longjmp, preemption, voluntary exits to ring-3) from AMD-V.
2403 *
2404 * @param pVCpu The cross context virtual CPU structure.
2405 *
2406 * @remarks No-long-jmp zone!!!
2407 */
2408static void hmR0SvmLeave(PVMCPU pVCpu)
2409{
2410 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2411 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2412 Assert(VMMR0IsLogFlushDisabled(pVCpu));
2413
2414 /*
2415 * !!! IMPORTANT !!!
2416 * If you modify code here, make sure to check whether hmR0SvmCallRing3Callback() needs to be updated too.
2417 */
2418
2419 /* Restore host FPU state if necessary and resync on next R0 reentry .*/
2420 if (CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu))
2421 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
2422
2423 /*
2424 * Restore host debug registers if necessary and resync on next R0 reentry.
2425 */
2426#ifdef VBOX_STRICT
2427 if (CPUMIsHyperDebugStateActive(pVCpu))
2428 {
2429 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
2430 Assert(pVmcb->ctrl.u16InterceptRdDRx == 0xffff);
2431 Assert(pVmcb->ctrl.u16InterceptWrDRx == 0xffff);
2432 }
2433#endif
2434 if (CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, false /* save DR6 */))
2435 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
2436
2437 Assert(!CPUMIsHyperDebugStateActive(pVCpu));
2438 Assert(!CPUMIsGuestDebugStateActive(pVCpu));
2439
2440 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatEntry);
2441 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatLoadGuestState);
2442 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit1);
2443 STAM_PROFILE_ADV_SET_STOPPED(&pVCpu->hm.s.StatExit2);
2444 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
2445
2446 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_HM, VMCPUSTATE_STARTED_EXEC);
2447}
2448
2449
2450/**
2451 * Leaves the AMD-V session.
2452 *
2453 * @returns VBox status code.
2454 * @param pVCpu The cross context virtual CPU structure.
2455 */
2456static int hmR0SvmLeaveSession(PVMCPU pVCpu)
2457{
2458 HM_DISABLE_PREEMPT();
2459 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
2460 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
2461
2462 /* When thread-context hooks are used, we can avoid doing the leave again if we had been preempted before
2463 and done this from the SVMR0ThreadCtxCallback(). */
2464 if (!pVCpu->hm.s.fLeaveDone)
2465 {
2466 hmR0SvmLeave(pVCpu);
2467 pVCpu->hm.s.fLeaveDone = true;
2468 }
2469
2470 /*
2471 * !!! IMPORTANT !!!
2472 * If you modify code here, make sure to check whether hmR0SvmCallRing3Callback() needs to be updated too.
2473 */
2474
2475 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
2476 /* Deregister hook now that we've left HM context before re-enabling preemption. */
2477 VMMR0ThreadCtxHookDisable(pVCpu);
2478
2479 /* Leave HM context. This takes care of local init (term). */
2480 int rc = HMR0LeaveCpu(pVCpu);
2481
2482 HM_RESTORE_PREEMPT();
2483 return rc;
2484}
2485
2486
2487/**
2488 * Does the necessary state syncing before doing a longjmp to ring-3.
2489 *
2490 * @returns VBox status code.
2491 * @param pVCpu The cross context virtual CPU structure.
2492 *
2493 * @remarks No-long-jmp zone!!!
2494 */
2495static int hmR0SvmLongJmpToRing3(PVMCPU pVCpu)
2496{
2497 return hmR0SvmLeaveSession(pVCpu);
2498}
2499
2500
2501/**
2502 * VMMRZCallRing3() callback wrapper which saves the guest state (or restores
2503 * any remaining host state) before we longjump to ring-3 and possibly get
2504 * preempted.
2505 *
2506 * @param pVCpu The cross context virtual CPU structure.
2507 * @param enmOperation The operation causing the ring-3 longjump.
2508 * @param pvUser The user argument (pointer to the possibly
2509 * out-of-date guest-CPU context).
2510 */
2511static DECLCALLBACK(int) hmR0SvmCallRing3Callback(PVMCPU pVCpu, VMMCALLRING3 enmOperation, void *pvUser)
2512{
2513 RT_NOREF_PV(pvUser);
2514
2515 if (enmOperation == VMMCALLRING3_VM_R0_ASSERTION)
2516 {
2517 /*
2518 * !!! IMPORTANT !!!
2519 * If you modify code here, make sure to check whether hmR0SvmLeave() and hmR0SvmLeaveSession() needs
2520 * to be updated too. This is a stripped down version which gets out ASAP trying to not trigger any assertion.
2521 */
2522 VMMRZCallRing3RemoveNotification(pVCpu);
2523 VMMRZCallRing3Disable(pVCpu);
2524 HM_DISABLE_PREEMPT();
2525
2526 /* Restore host FPU state if necessary and resync on next R0 reentry. */
2527 CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(pVCpu);
2528
2529 /* Restore host debug registers if necessary and resync on next R0 reentry. */
2530 CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(pVCpu, false /* save DR6 */);
2531
2532 /* Deregister the hook now that we've left HM context before re-enabling preemption. */
2533 /** @todo eliminate the need for calling VMMR0ThreadCtxHookDisable here! */
2534 VMMR0ThreadCtxHookDisable(pVCpu);
2535
2536 /* Leave HM context. This takes care of local init (term). */
2537 HMR0LeaveCpu(pVCpu);
2538
2539 HM_RESTORE_PREEMPT();
2540 return VINF_SUCCESS;
2541 }
2542
2543 Assert(pVCpu);
2544 Assert(pvUser);
2545 Assert(VMMRZCallRing3IsEnabled(pVCpu));
2546 HMSVM_ASSERT_PREEMPT_SAFE();
2547
2548 VMMRZCallRing3Disable(pVCpu);
2549 Assert(VMMR0IsLogFlushDisabled(pVCpu));
2550
2551 Log4(("hmR0SvmCallRing3Callback->hmR0SvmLongJmpToRing3\n"));
2552 int rc = hmR0SvmLongJmpToRing3(pVCpu);
2553 AssertRCReturn(rc, rc);
2554
2555 VMMRZCallRing3Enable(pVCpu);
2556 return VINF_SUCCESS;
2557}
2558
2559
2560/**
2561 * Take necessary actions before going back to ring-3.
2562 *
2563 * An action requires us to go back to ring-3. This function does the necessary
2564 * steps before we can safely return to ring-3. This is not the same as longjmps
2565 * to ring-3, this is voluntary.
2566 *
2567 * @returns VBox status code.
2568 * @param pVM The cross context VM structure.
2569 * @param pVCpu The cross context virtual CPU structure.
2570 * @param pCtx Pointer to the guest-CPU context.
2571 * @param rcExit The reason for exiting to ring-3. Can be
2572 * VINF_VMM_UNKNOWN_RING3_CALL.
2573 */
2574static int hmR0SvmExitToRing3(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, int rcExit)
2575{
2576 Assert(pVM);
2577 Assert(pVCpu);
2578 Assert(pCtx);
2579 HMSVM_ASSERT_PREEMPT_SAFE();
2580
2581 /* Please, no longjumps here (any logging shouldn't flush jump back to ring-3). NO LOGGING BEFORE THIS POINT! */
2582 VMMRZCallRing3Disable(pVCpu);
2583 Log4(("hmR0SvmExitToRing3: rcExit=%d\n", rcExit));
2584
2585 /* We need to do this only while truly exiting the "inner loop" back to ring-3 and -not- for any longjmp to ring3. */
2586 if (pVCpu->hm.s.Event.fPending)
2587 {
2588 hmR0SvmPendingEventToTrpmTrap(pVCpu);
2589 Assert(!pVCpu->hm.s.Event.fPending);
2590 }
2591
2592 /* Sync. the necessary state for going back to ring-3. */
2593 hmR0SvmLeaveSession(pVCpu);
2594 STAM_COUNTER_DEC(&pVCpu->hm.s.StatSwitchLongJmpToR3);
2595
2596 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
2597 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR
2598 | CPUM_CHANGED_LDTR
2599 | CPUM_CHANGED_GDTR
2600 | CPUM_CHANGED_IDTR
2601 | CPUM_CHANGED_TR
2602 | CPUM_CHANGED_HIDDEN_SEL_REGS);
2603 if ( pVM->hm.s.fNestedPaging
2604 && CPUMIsGuestPagingEnabledEx(pCtx))
2605 {
2606 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
2607 }
2608
2609#ifdef VBOX_WITH_NESTED_HWVIRT
2610 pVCpu->hm.s.svm.NstGstVmcbCache.fVmrunEmulatedInR0 = false;
2611#endif
2612
2613 /* On our way back from ring-3 reload the guest state if there is a possibility of it being changed. */
2614 if (rcExit != VINF_EM_RAW_INTERRUPT)
2615 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
2616
2617 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchExitToR3);
2618
2619 /* We do -not- want any longjmp notifications after this! We must return to ring-3 ASAP. */
2620 VMMRZCallRing3RemoveNotification(pVCpu);
2621 VMMRZCallRing3Enable(pVCpu);
2622
2623 /*
2624 * If we're emulating an instruction, we shouldn't have any TRPM traps pending
2625 * and if we're injecting an event we should have a TRPM trap pending.
2626 */
2627 AssertReturnStmt(rcExit != VINF_EM_RAW_INJECT_TRPM_EVENT || TRPMHasTrap(pVCpu),
2628 pVCpu->hm.s.u32HMError = rcExit,
2629 VERR_SVM_IPE_5);
2630 AssertReturnStmt(rcExit != VINF_EM_RAW_EMULATE_INSTR || !TRPMHasTrap(pVCpu),
2631 pVCpu->hm.s.u32HMError = rcExit,
2632 VERR_SVM_IPE_4);
2633
2634 return rcExit;
2635}
2636
2637
2638/**
2639 * Updates the use of TSC offsetting mode for the CPU and adjusts the necessary
2640 * intercepts.
2641 *
2642 * @param pVM The cross context VM structure.
2643 * @param pVCpu The cross context virtual CPU structure.
2644 * @param pVmcb Pointer to the VM control block.
2645 *
2646 * @remarks No-long-jump zone!!!
2647 */
2648static void hmR0SvmUpdateTscOffsetting(PVM pVM, PVMCPU pVCpu, PSVMVMCB pVmcb)
2649{
2650 bool fParavirtTsc;
2651 bool fCanUseRealTsc = TMCpuTickCanUseRealTSC(pVM, pVCpu, &pVmcb->ctrl.u64TSCOffset, &fParavirtTsc);
2652 if (fCanUseRealTsc)
2653 {
2654 pVmcb->ctrl.u64InterceptCtrl &= ~SVM_CTRL_INTERCEPT_RDTSC;
2655 pVmcb->ctrl.u64InterceptCtrl &= ~SVM_CTRL_INTERCEPT_RDTSCP;
2656 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscOffset);
2657 }
2658 else
2659 {
2660 pVmcb->ctrl.u64InterceptCtrl |= SVM_CTRL_INTERCEPT_RDTSC;
2661 pVmcb->ctrl.u64InterceptCtrl |= SVM_CTRL_INTERCEPT_RDTSCP;
2662 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscIntercept);
2663 }
2664 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
2665
2666 /** @todo later optimize this to be done elsewhere and not before every
2667 * VM-entry. */
2668 if (fParavirtTsc)
2669 {
2670 /* Currently neither Hyper-V nor KVM need to update their paravirt. TSC
2671 information before every VM-entry, hence disable it for performance sake. */
2672#if 0
2673 int rc = GIMR0UpdateParavirtTsc(pVM, 0 /* u64Offset */);
2674 AssertRC(rc);
2675#endif
2676 STAM_COUNTER_INC(&pVCpu->hm.s.StatTscParavirt);
2677 }
2678}
2679
2680
2681/**
2682 * Sets an event as a pending event to be injected into the guest.
2683 *
2684 * @param pVCpu The cross context virtual CPU structure.
2685 * @param pEvent Pointer to the SVM event.
2686 * @param GCPtrFaultAddress The fault-address (CR2) in case it's a
2687 * page-fault.
2688 *
2689 * @remarks Statistics counter assumes this is a guest event being reflected to
2690 * the guest i.e. 'StatInjectPendingReflect' is incremented always.
2691 */
2692DECLINLINE(void) hmR0SvmSetPendingEvent(PVMCPU pVCpu, PSVMEVENT pEvent, RTGCUINTPTR GCPtrFaultAddress)
2693{
2694 Assert(!pVCpu->hm.s.Event.fPending);
2695 Assert(pEvent->n.u1Valid);
2696
2697 pVCpu->hm.s.Event.u64IntInfo = pEvent->u;
2698 pVCpu->hm.s.Event.fPending = true;
2699 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress;
2700
2701 Log4(("hmR0SvmSetPendingEvent: u=%#RX64 u8Vector=%#x Type=%#x ErrorCodeValid=%RTbool ErrorCode=%#RX32\n", pEvent->u,
2702 pEvent->n.u8Vector, (uint8_t)pEvent->n.u3Type, !!pEvent->n.u1ErrorCodeValid, pEvent->n.u32ErrorCode));
2703}
2704
2705
2706/**
2707 * Sets an invalid-opcode (\#UD) exception as pending-for-injection into the VM.
2708 *
2709 * @param pVCpu The cross context virtual CPU structure.
2710 */
2711DECLINLINE(void) hmR0SvmSetPendingXcptUD(PVMCPU pVCpu)
2712{
2713 SVMEVENT Event;
2714 Event.u = 0;
2715 Event.n.u1Valid = 1;
2716 Event.n.u3Type = SVM_EVENT_EXCEPTION;
2717 Event.n.u8Vector = X86_XCPT_UD;
2718 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
2719}
2720
2721
2722/**
2723 * Sets a debug (\#DB) exception as pending-for-injection into the VM.
2724 *
2725 * @param pVCpu The cross context virtual CPU structure.
2726 */
2727DECLINLINE(void) hmR0SvmSetPendingXcptDB(PVMCPU pVCpu)
2728{
2729 SVMEVENT Event;
2730 Event.u = 0;
2731 Event.n.u1Valid = 1;
2732 Event.n.u3Type = SVM_EVENT_EXCEPTION;
2733 Event.n.u8Vector = X86_XCPT_DB;
2734 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
2735}
2736
2737
2738/**
2739 * Sets a page fault (\#PF) exception as pending-for-injection into the VM.
2740 *
2741 * @param pVCpu The cross context virtual CPU structure.
2742 * @param pCtx Pointer to the guest-CPU context.
2743 * @param u32ErrCode The error-code for the page-fault.
2744 * @param uFaultAddress The page fault address (CR2).
2745 *
2746 * @remarks This updates the guest CR2 with @a uFaultAddress!
2747 */
2748DECLINLINE(void) hmR0SvmSetPendingXcptPF(PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t u32ErrCode, RTGCUINTPTR uFaultAddress)
2749{
2750 SVMEVENT Event;
2751 Event.u = 0;
2752 Event.n.u1Valid = 1;
2753 Event.n.u3Type = SVM_EVENT_EXCEPTION;
2754 Event.n.u8Vector = X86_XCPT_PF;
2755 Event.n.u1ErrorCodeValid = 1;
2756 Event.n.u32ErrorCode = u32ErrCode;
2757
2758 /* Update CR2 of the guest. */
2759 if (pCtx->cr2 != uFaultAddress)
2760 {
2761 pCtx->cr2 = uFaultAddress;
2762 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR2);
2763 }
2764
2765 hmR0SvmSetPendingEvent(pVCpu, &Event, uFaultAddress);
2766}
2767
2768
2769/**
2770 * Sets a device-not-available (\#NM) exception as pending-for-injection into
2771 * the VM.
2772 *
2773 * @param pVCpu The cross context virtual CPU structure.
2774 */
2775DECLINLINE(void) hmR0SvmSetPendingXcptNM(PVMCPU pVCpu)
2776{
2777 SVMEVENT Event;
2778 Event.u = 0;
2779 Event.n.u1Valid = 1;
2780 Event.n.u3Type = SVM_EVENT_EXCEPTION;
2781 Event.n.u8Vector = X86_XCPT_NM;
2782 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
2783}
2784
2785
2786/**
2787 * Sets a math-fault (\#MF) exception as pending-for-injection into the VM.
2788 *
2789 * @param pVCpu The cross context virtual CPU structure.
2790 */
2791DECLINLINE(void) hmR0SvmSetPendingXcptMF(PVMCPU pVCpu)
2792{
2793 SVMEVENT Event;
2794 Event.u = 0;
2795 Event.n.u1Valid = 1;
2796 Event.n.u3Type = SVM_EVENT_EXCEPTION;
2797 Event.n.u8Vector = X86_XCPT_MF;
2798 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
2799}
2800
2801
2802/**
2803 * Sets a double fault (\#DF) exception as pending-for-injection into the VM.
2804 *
2805 * @param pVCpu The cross context virtual CPU structure.
2806 */
2807DECLINLINE(void) hmR0SvmSetPendingXcptDF(PVMCPU pVCpu)
2808{
2809 SVMEVENT Event;
2810 Event.u = 0;
2811 Event.n.u1Valid = 1;
2812 Event.n.u3Type = SVM_EVENT_EXCEPTION;
2813 Event.n.u8Vector = X86_XCPT_DF;
2814 Event.n.u1ErrorCodeValid = 1;
2815 Event.n.u32ErrorCode = 0;
2816 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
2817}
2818
2819
2820/**
2821 * Injects an event into the guest upon VMRUN by updating the relevant field
2822 * in the VMCB.
2823 *
2824 * @param pVCpu The cross context virtual CPU structure.
2825 * @param pVmcb Pointer to the guest VM control block.
2826 * @param pCtx Pointer to the guest-CPU context.
2827 * @param pEvent Pointer to the event.
2828 *
2829 * @remarks No-long-jump zone!!!
2830 * @remarks Requires CR0!
2831 */
2832DECLINLINE(void) hmR0SvmInjectEventVmcb(PVMCPU pVCpu, PSVMVMCB pVmcb, PCPUMCTX pCtx, PSVMEVENT pEvent)
2833{
2834 NOREF(pVCpu); NOREF(pCtx);
2835
2836 pVmcb->ctrl.EventInject.u = pEvent->u;
2837 STAM_COUNTER_INC(&pVCpu->hm.s.paStatInjectedIrqsR0[pEvent->n.u8Vector & MASK_INJECT_IRQ_STAT]);
2838
2839 Log4(("hmR0SvmInjectEventVmcb: u=%#RX64 u8Vector=%#x Type=%#x ErrorCodeValid=%RTbool ErrorCode=%#RX32\n", pEvent->u,
2840 pEvent->n.u8Vector, (uint8_t)pEvent->n.u3Type, !!pEvent->n.u1ErrorCodeValid, pEvent->n.u32ErrorCode));
2841}
2842
2843
2844
2845/**
2846 * Converts any TRPM trap into a pending HM event. This is typically used when
2847 * entering from ring-3 (not longjmp returns).
2848 *
2849 * @param pVCpu The cross context virtual CPU structure.
2850 */
2851static void hmR0SvmTrpmTrapToPendingEvent(PVMCPU pVCpu)
2852{
2853 Assert(TRPMHasTrap(pVCpu));
2854 Assert(!pVCpu->hm.s.Event.fPending);
2855
2856 uint8_t uVector;
2857 TRPMEVENT enmTrpmEvent;
2858 RTGCUINT uErrCode;
2859 RTGCUINTPTR GCPtrFaultAddress;
2860 uint8_t cbInstr;
2861
2862 int rc = TRPMQueryTrapAll(pVCpu, &uVector, &enmTrpmEvent, &uErrCode, &GCPtrFaultAddress, &cbInstr);
2863 AssertRC(rc);
2864
2865 SVMEVENT Event;
2866 Event.u = 0;
2867 Event.n.u1Valid = 1;
2868 Event.n.u8Vector = uVector;
2869
2870 /* Refer AMD spec. 15.20 "Event Injection" for the format. */
2871 if (enmTrpmEvent == TRPM_TRAP)
2872 {
2873 Event.n.u3Type = SVM_EVENT_EXCEPTION;
2874 switch (uVector)
2875 {
2876 case X86_XCPT_NMI:
2877 {
2878 Event.n.u3Type = SVM_EVENT_NMI;
2879 break;
2880 }
2881
2882 case X86_XCPT_PF:
2883 case X86_XCPT_DF:
2884 case X86_XCPT_TS:
2885 case X86_XCPT_NP:
2886 case X86_XCPT_SS:
2887 case X86_XCPT_GP:
2888 case X86_XCPT_AC:
2889 {
2890 Event.n.u1ErrorCodeValid = 1;
2891 Event.n.u32ErrorCode = uErrCode;
2892 break;
2893 }
2894 }
2895 }
2896 else if (enmTrpmEvent == TRPM_HARDWARE_INT)
2897 Event.n.u3Type = SVM_EVENT_EXTERNAL_IRQ;
2898 else if (enmTrpmEvent == TRPM_SOFTWARE_INT)
2899 Event.n.u3Type = SVM_EVENT_SOFTWARE_INT;
2900 else
2901 AssertMsgFailed(("Invalid TRPM event type %d\n", enmTrpmEvent));
2902
2903 rc = TRPMResetTrap(pVCpu);
2904 AssertRC(rc);
2905
2906 Log4(("TRPM->HM event: u=%#RX64 u8Vector=%#x uErrorCodeValid=%RTbool uErrorCode=%#RX32\n", Event.u, Event.n.u8Vector,
2907 !!Event.n.u1ErrorCodeValid, Event.n.u32ErrorCode));
2908
2909 hmR0SvmSetPendingEvent(pVCpu, &Event, GCPtrFaultAddress);
2910}
2911
2912
2913/**
2914 * Converts any pending SVM event into a TRPM trap. Typically used when leaving
2915 * AMD-V to execute any instruction.
2916 *
2917 * @param pVCpu The cross context virtual CPU structure.
2918 */
2919static void hmR0SvmPendingEventToTrpmTrap(PVMCPU pVCpu)
2920{
2921 Assert(pVCpu->hm.s.Event.fPending);
2922 Assert(TRPMQueryTrap(pVCpu, NULL /* pu8TrapNo */, NULL /* pEnmType */) == VERR_TRPM_NO_ACTIVE_TRAP);
2923
2924 SVMEVENT Event;
2925 Event.u = pVCpu->hm.s.Event.u64IntInfo;
2926
2927 uint8_t uVector = Event.n.u8Vector;
2928 uint8_t uVectorType = Event.n.u3Type;
2929 TRPMEVENT enmTrapType = HMSvmEventToTrpmEventType(&Event);
2930
2931 Log4(("HM event->TRPM: uVector=%#x enmTrapType=%d\n", uVector, uVectorType));
2932
2933 int rc = TRPMAssertTrap(pVCpu, uVector, enmTrapType);
2934 AssertRC(rc);
2935
2936 if (Event.n.u1ErrorCodeValid)
2937 TRPMSetErrorCode(pVCpu, Event.n.u32ErrorCode);
2938
2939 if ( uVectorType == SVM_EVENT_EXCEPTION
2940 && uVector == X86_XCPT_PF)
2941 {
2942 TRPMSetFaultAddress(pVCpu, pVCpu->hm.s.Event.GCPtrFaultAddress);
2943 Assert(pVCpu->hm.s.Event.GCPtrFaultAddress == CPUMGetGuestCR2(pVCpu));
2944 }
2945 else if (uVectorType == SVM_EVENT_SOFTWARE_INT)
2946 {
2947 AssertMsg( uVectorType == SVM_EVENT_SOFTWARE_INT
2948 || (uVector == X86_XCPT_BP || uVector == X86_XCPT_OF),
2949 ("Invalid vector: uVector=%#x uVectorType=%#x\n", uVector, uVectorType));
2950 TRPMSetInstrLength(pVCpu, pVCpu->hm.s.Event.cbInstr);
2951 }
2952 pVCpu->hm.s.Event.fPending = false;
2953}
2954
2955
2956/**
2957 * Checks if the guest (or nested-guest) has an interrupt shadow active right
2958 * now.
2959 *
2960 * @returns true if the interrupt shadow is active, false otherwise.
2961 * @param pVCpu The cross context virtual CPU structure.
2962 * @param pCtx Pointer to the guest-CPU context.
2963 *
2964 * @remarks No-long-jump zone!!!
2965 * @remarks Has side-effects with VMCPU_FF_INHIBIT_INTERRUPTS force-flag.
2966 */
2967DECLINLINE(bool) hmR0SvmIsIntrShadowActive(PVMCPU pVCpu, PCPUMCTX pCtx)
2968{
2969 /*
2970 * Instructions like STI and MOV SS inhibit interrupts till the next instruction completes. Check if we should
2971 * inhibit interrupts or clear any existing interrupt-inhibition.
2972 */
2973 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
2974 {
2975 if (pCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
2976 {
2977 /*
2978 * We can clear the inhibit force flag as even if we go back to the recompiler without executing guest code in
2979 * AMD-V, the flag's condition to be cleared is met and thus the cleared state is correct.
2980 */
2981 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
2982 return false;
2983 }
2984 return true;
2985 }
2986 return false;
2987}
2988
2989
2990/**
2991 * Sets the virtual interrupt intercept control in the VMCB which
2992 * instructs AMD-V to cause a \#VMEXIT as soon as the guest is in a state to
2993 * receive interrupts.
2994 *
2995 * @param pVmcb Pointer to the VM control block.
2996 */
2997DECLINLINE(void) hmR0SvmSetVirtIntrIntercept(PSVMVMCB pVmcb)
2998{
2999 if (!(pVmcb->ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VINTR))
3000 {
3001 pVmcb->ctrl.IntCtrl.n.u1VIrqPending = 1; /* A virtual interrupt is pending. */
3002 pVmcb->ctrl.IntCtrl.n.u8VIntrVector = 0; /* Vector not necessary as we #VMEXIT for delivering the interrupt. */
3003 pVmcb->ctrl.u64InterceptCtrl |= SVM_CTRL_INTERCEPT_VINTR;
3004 pVmcb->ctrl.u64VmcbCleanBits &= ~(HMSVM_VMCB_CLEAN_INTERCEPTS | HMSVM_VMCB_CLEAN_TPR);
3005
3006 Log4(("Setting VINTR intercept\n"));
3007 }
3008}
3009
3010
3011#if 0
3012/**
3013 * Clears the virtual interrupt intercept control in the VMCB as
3014 * we are figured the guest is unable process any interrupts
3015 * at this point of time.
3016 *
3017 * @param pVmcb Pointer to the VM control block.
3018 */
3019DECLINLINE(void) hmR0SvmClearVirtIntrIntercept(PSVMVMCB pVmcb)
3020{
3021 if (pVmcb->ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VINTR)
3022 {
3023 pVmcb->ctrl.u64InterceptCtrl &= ~SVM_CTRL_INTERCEPT_VINTR;
3024 pVmcb->ctrl.u64VmcbCleanBits &= ~(HMSVM_VMCB_CLEAN_INTERCEPTS);
3025 Log4(("Clearing VINTR intercept\n"));
3026 }
3027}
3028#endif
3029
3030
3031/**
3032 * Sets the IRET intercept control in the VMCB which instructs AMD-V to cause a
3033 * \#VMEXIT as soon as a guest starts executing an IRET. This is used to unblock
3034 * virtual NMIs.
3035 *
3036 * @param pVmcb Pointer to the VM control block.
3037 */
3038DECLINLINE(void) hmR0SvmSetIretIntercept(PSVMVMCB pVmcb)
3039{
3040 if (!(pVmcb->ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_IRET))
3041 {
3042 pVmcb->ctrl.u64InterceptCtrl |= SVM_CTRL_INTERCEPT_IRET;
3043 pVmcb->ctrl.u64VmcbCleanBits &= ~(HMSVM_VMCB_CLEAN_INTERCEPTS);
3044
3045 Log4(("Setting IRET intercept\n"));
3046 }
3047}
3048
3049
3050/**
3051 * Clears the IRET intercept control in the VMCB.
3052 *
3053 * @param pVmcb Pointer to the VM control block.
3054 */
3055DECLINLINE(void) hmR0SvmClearIretIntercept(PSVMVMCB pVmcb)
3056{
3057 if (pVmcb->ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_IRET)
3058 {
3059 pVmcb->ctrl.u64InterceptCtrl &= ~SVM_CTRL_INTERCEPT_IRET;
3060 pVmcb->ctrl.u64VmcbCleanBits &= ~(HMSVM_VMCB_CLEAN_INTERCEPTS);
3061
3062 Log4(("Clearing IRET intercept\n"));
3063 }
3064}
3065
3066#ifdef VBOX_WITH_NESTED_HWVIRT
3067/**
3068 * Evaluates the event to be delivered to the nested-guest and sets it as the
3069 * pending event.
3070 *
3071 * @param pVCpu The cross context virtual CPU structure.
3072 * @param pCtx Pointer to the guest-CPU context.
3073 */
3074static void hmR0SvmEvaluatePendingEventNested(PVMCPU pVCpu, PCPUMCTX pCtx)
3075{
3076 Log4Func(("\n"));
3077
3078 Assert(!pVCpu->hm.s.Event.fPending);
3079 Assert(pCtx->hwvirt.svm.fGif);
3080
3081 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
3082
3083 SVMEVENT Event;
3084 Event.u = 0;
3085 bool const fIntShadow = hmR0SvmIsIntrShadowActive(pVCpu, pCtx);
3086
3087 /** @todo SMI. SMIs take priority over NMIs. */
3088 /*
3089 * Check if the nested-guest can receive NMIs.
3090 * NMIs are higher priority than regular interrupts.
3091 */
3092 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NMI))
3093 {
3094 bool const fBlockNmi = VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS);
3095 if (fBlockNmi)
3096 hmR0SvmSetIretIntercept(pVmcbNstGst);
3097 else if (fIntShadow)
3098 {
3099 /** @todo Figure this out, how we shall manage virt. intercept if the
3100 * nested-guest already has one set and/or if we really need it? */
3101#if 0
3102 hmR0SvmSetVirtIntrIntercept(pVmcbNstGst);
3103#endif
3104 }
3105 else
3106 {
3107 Log4(("Pending NMI\n"));
3108
3109 Event.n.u1Valid = 1;
3110 Event.n.u8Vector = X86_XCPT_NMI;
3111 Event.n.u3Type = SVM_EVENT_NMI;
3112
3113 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
3114 hmR0SvmSetIretIntercept(pVmcbNstGst);
3115 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
3116 return;
3117 }
3118 }
3119
3120 /*
3121 * Check if the nested-guest can receive external interrupts (PIC/APIC).
3122 */
3123 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
3124 && !pVCpu->hm.s.fSingleInstruction)
3125 {
3126 /* Note: it is critical we call CPUMCanSvmNstGstTakePhysIntr -before- modifying the nested-guests's V_INTR_MASKING
3127 bit, currently it gets modified in hmR0SvmLoadGuestApicStateNested. */
3128 bool const fIntEnabled = CPUMCanSvmNstGstTakePhysIntr(pCtx);
3129 if ( fIntEnabled
3130 && !fIntShadow)
3131 {
3132 uint8_t u8Interrupt;
3133 int rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
3134 if (RT_SUCCESS(rc))
3135 {
3136 Log4(("Injecting external interrupt u8Interrupt=%#x\n", u8Interrupt));
3137
3138 Event.n.u1Valid = 1;
3139 Event.n.u8Vector = u8Interrupt;
3140 Event.n.u3Type = SVM_EVENT_EXTERNAL_IRQ;
3141
3142 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
3143 }
3144 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
3145 {
3146 /*
3147 * AMD-V has no TPR thresholding feature. We just avoid posting the interrupt.
3148 * We just avoid delivering the TPR-masked interrupt here. TPR will be updated
3149 * always via hmR0SvmLoadGuestState() -> hmR0SvmLoadGuestApicState().
3150 */
3151 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
3152 }
3153 else
3154 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
3155 }
3156 else
3157 {
3158 /** @todo Figure this out, how we shall manage virt. intercept if the
3159 * nested-guest already has one set and/or if we really need it? */
3160#if 0
3161 hmR0SvmSetVirtIntrIntercept(pVmcbNstGst);
3162#endif
3163 }
3164 }
3165 /*
3166 * Check if the nested-guest can receive virtual interrupts.
3167 */
3168 else if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST))
3169 {
3170 bool const fIntEnabled = CPUMCanSvmNstGstTakeVirtIntr(pCtx);
3171 if (fIntEnabled)
3172 {
3173 uint8_t const u8Interrupt = CPUMGetSvmNstGstInterrupt(pCtx);
3174 Log4(("Injecting virtual interrupt u8Interrupt=%#x\n", u8Interrupt));
3175
3176 Event.n.u1Valid = 1;
3177 Event.n.u8Vector = u8Interrupt;
3178 Event.n.u3Type = SVM_EVENT_EXTERNAL_IRQ;
3179
3180 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
3181 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
3182 }
3183 }
3184}
3185#endif
3186
3187/**
3188 * Evaluates the event to be delivered to the guest and sets it as the pending
3189 * event.
3190 *
3191 * @param pVCpu The cross context virtual CPU structure.
3192 * @param pCtx Pointer to the guest-CPU context.
3193 */
3194static void hmR0SvmEvaluatePendingEvent(PVMCPU pVCpu, PCPUMCTX pCtx)
3195{
3196 Assert(!pVCpu->hm.s.Event.fPending);
3197 Log4Func(("\n"));
3198
3199#ifdef VBOX_WITH_NESTED_HWVIRT
3200 bool const fGif = pCtx->hwvirt.svm.fGif;
3201#else
3202 bool const fGif = true;
3203#endif
3204 /*
3205 * If the global interrupt flag (GIF) isn't set, even NMIs and other events are blocked.
3206 * See AMD spec. Table 15-10. "Effect of the GIF on Interrupt Handling".
3207 */
3208 if (fGif)
3209 {
3210 bool const fIntShadow = hmR0SvmIsIntrShadowActive(pVCpu, pCtx);
3211 bool const fBlockInt = !(pCtx->eflags.u32 & X86_EFL_IF);
3212 bool const fBlockNmi = VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS);
3213 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
3214
3215 SVMEVENT Event;
3216 Event.u = 0;
3217
3218 /** @todo SMI. SMIs take priority over NMIs. */
3219 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NMI)) /* NMI. NMIs take priority over regular interrupts. */
3220 {
3221 if (fBlockNmi)
3222 hmR0SvmSetIretIntercept(pVmcb);
3223 else if (fIntShadow)
3224 hmR0SvmSetVirtIntrIntercept(pVmcb);
3225 else
3226 {
3227 Log4(("Pending NMI\n"));
3228
3229 Event.n.u1Valid = 1;
3230 Event.n.u8Vector = X86_XCPT_NMI;
3231 Event.n.u3Type = SVM_EVENT_NMI;
3232
3233 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
3234 hmR0SvmSetIretIntercept(pVmcb);
3235 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
3236 return;
3237 }
3238 }
3239 else if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC)
3240 && !pVCpu->hm.s.fSingleInstruction)
3241 {
3242 /*
3243 * Check if the guest can receive external interrupts (PIC/APIC). Once PDMGetInterrupt() returns
3244 * a valid interrupt we -must- deliver the interrupt. We can no longer re-request it from the APIC.
3245 */
3246 if ( !fBlockInt
3247 && !fIntShadow)
3248 {
3249 uint8_t u8Interrupt;
3250 int rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
3251 if (RT_SUCCESS(rc))
3252 {
3253 Log4(("Injecting external interrupt u8Interrupt=%#x\n", u8Interrupt));
3254
3255 Event.n.u1Valid = 1;
3256 Event.n.u8Vector = u8Interrupt;
3257 Event.n.u3Type = SVM_EVENT_EXTERNAL_IRQ;
3258
3259 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
3260 }
3261 else if (rc == VERR_APIC_INTR_MASKED_BY_TPR)
3262 {
3263 /*
3264 * AMD-V has no TPR thresholding feature. We just avoid posting the interrupt.
3265 * We just avoid delivering the TPR-masked interrupt here. TPR will be updated
3266 * always via hmR0SvmLoadGuestState() -> hmR0SvmLoadGuestApicState().
3267 */
3268 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchTprMaskedIrq);
3269 }
3270 else
3271 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchGuestIrq);
3272 }
3273 else
3274 hmR0SvmSetVirtIntrIntercept(pVmcb);
3275 }
3276 }
3277}
3278
3279
3280/**
3281 * Injects any pending events into the guest or nested-guest.
3282 *
3283 * @param pVCpu The cross context virtual CPU structure.
3284 * @param pCtx Pointer to the guest-CPU context.
3285 * @param pVmcb Pointer to the VM control block.
3286 */
3287static void hmR0SvmInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMVMCB pVmcb)
3288{
3289 Assert(!TRPMHasTrap(pVCpu));
3290 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
3291
3292 bool const fIntShadow = hmR0SvmIsIntrShadowActive(pVCpu, pCtx);
3293
3294 /*
3295 * When executing the nested-guest, we avoid assertions on whether the
3296 * event injection is valid purely based on EFLAGS, as V_INTR_MASKING
3297 * affects the interpretation of interruptibility (see CPUMCanSvmNstGstTakePhysIntr).
3298 */
3299#ifndef VBOX_WITH_NESTED_HWVIRT
3300 bool const fBlockInt = !(pCtx->eflags.u32 & X86_EFL_IF);
3301#endif
3302
3303 if (pVCpu->hm.s.Event.fPending) /* First, inject any pending HM events. */
3304 {
3305 SVMEVENT Event;
3306 Event.u = pVCpu->hm.s.Event.u64IntInfo;
3307 Assert(Event.n.u1Valid);
3308
3309#ifndef VBOX_WITH_NESTED_HWVIRT
3310 if (Event.n.u3Type == SVM_EVENT_EXTERNAL_IRQ)
3311 {
3312 Assert(!fBlockInt);
3313 Assert(!fIntShadow);
3314 }
3315 else if (Event.n.u3Type == SVM_EVENT_NMI)
3316 Assert(!fIntShadow);
3317 NOREF(fBlockInt);
3318#endif
3319
3320 Log4(("Injecting pending HM event\n"));
3321 hmR0SvmInjectEventVmcb(pVCpu, pVmcb, pCtx, &Event);
3322 pVCpu->hm.s.Event.fPending = false;
3323
3324#ifdef VBOX_WITH_STATISTICS
3325 if (Event.n.u3Type == SVM_EVENT_EXTERNAL_IRQ)
3326 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectInterrupt);
3327 else
3328 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectXcpt);
3329#endif
3330 }
3331
3332 /*
3333 * Update the guest interrupt shadow in the guest or nested-guest VMCB.
3334 *
3335 * For nested-guests: We need to update it too for the scenario where IEM executes
3336 * the nested-guest but execution later continues here with an interrupt shadow active.
3337 */
3338 pVmcb->ctrl.u64IntShadow = !!fIntShadow;
3339}
3340
3341
3342/**
3343 * Reports world-switch error and dumps some useful debug info.
3344 *
3345 * @param pVM The cross context VM structure.
3346 * @param pVCpu The cross context virtual CPU structure.
3347 * @param rcVMRun The return code from VMRUN (or
3348 * VERR_SVM_INVALID_GUEST_STATE for invalid
3349 * guest-state).
3350 * @param pCtx Pointer to the guest-CPU context.
3351 */
3352static void hmR0SvmReportWorldSwitchError(PVM pVM, PVMCPU pVCpu, int rcVMRun, PCPUMCTX pCtx)
3353{
3354 NOREF(pCtx);
3355 HMSVM_ASSERT_PREEMPT_SAFE();
3356 PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
3357
3358 if (rcVMRun == VERR_SVM_INVALID_GUEST_STATE)
3359 {
3360 hmR0DumpRegs(pVM, pVCpu, pCtx); NOREF(pVM);
3361#ifdef VBOX_STRICT
3362 Log4(("ctrl.u64VmcbCleanBits %#RX64\n", pVmcb->ctrl.u64VmcbCleanBits));
3363 Log4(("ctrl.u16InterceptRdCRx %#x\n", pVmcb->ctrl.u16InterceptRdCRx));
3364 Log4(("ctrl.u16InterceptWrCRx %#x\n", pVmcb->ctrl.u16InterceptWrCRx));
3365 Log4(("ctrl.u16InterceptRdDRx %#x\n", pVmcb->ctrl.u16InterceptRdDRx));
3366 Log4(("ctrl.u16InterceptWrDRx %#x\n", pVmcb->ctrl.u16InterceptWrDRx));
3367 Log4(("ctrl.u32InterceptXcpt %#x\n", pVmcb->ctrl.u32InterceptXcpt));
3368 Log4(("ctrl.u64InterceptCtrl %#RX64\n", pVmcb->ctrl.u64InterceptCtrl));
3369 Log4(("ctrl.u64IOPMPhysAddr %#RX64\n", pVmcb->ctrl.u64IOPMPhysAddr));
3370 Log4(("ctrl.u64MSRPMPhysAddr %#RX64\n", pVmcb->ctrl.u64MSRPMPhysAddr));
3371 Log4(("ctrl.u64TSCOffset %#RX64\n", pVmcb->ctrl.u64TSCOffset));
3372
3373 Log4(("ctrl.TLBCtrl.u32ASID %#x\n", pVmcb->ctrl.TLBCtrl.n.u32ASID));
3374 Log4(("ctrl.TLBCtrl.u8TLBFlush %#x\n", pVmcb->ctrl.TLBCtrl.n.u8TLBFlush));
3375 Log4(("ctrl.TLBCtrl.u24Reserved %#x\n", pVmcb->ctrl.TLBCtrl.n.u24Reserved));
3376
3377 Log4(("ctrl.IntCtrl.u8VTPR %#x\n", pVmcb->ctrl.IntCtrl.n.u8VTPR));
3378 Log4(("ctrl.IntCtrl.u1VIrqPending %#x\n", pVmcb->ctrl.IntCtrl.n.u1VIrqPending));
3379 Log4(("ctrl.IntCtrl.u7Reserved %#x\n", pVmcb->ctrl.IntCtrl.n.u7Reserved));
3380 Log4(("ctrl.IntCtrl.u4VIntrPrio %#x\n", pVmcb->ctrl.IntCtrl.n.u4VIntrPrio));
3381 Log4(("ctrl.IntCtrl.u1IgnoreTPR %#x\n", pVmcb->ctrl.IntCtrl.n.u1IgnoreTPR));
3382 Log4(("ctrl.IntCtrl.u3Reserved %#x\n", pVmcb->ctrl.IntCtrl.n.u3Reserved));
3383 Log4(("ctrl.IntCtrl.u1VIntrMasking %#x\n", pVmcb->ctrl.IntCtrl.n.u1VIntrMasking));
3384 Log4(("ctrl.IntCtrl.u6Reserved %#x\n", pVmcb->ctrl.IntCtrl.n.u6Reserved));
3385 Log4(("ctrl.IntCtrl.u8VIntrVector %#x\n", pVmcb->ctrl.IntCtrl.n.u8VIntrVector));
3386 Log4(("ctrl.IntCtrl.u24Reserved %#x\n", pVmcb->ctrl.IntCtrl.n.u24Reserved));
3387
3388 Log4(("ctrl.u64IntShadow %#RX64\n", pVmcb->ctrl.u64IntShadow));
3389 Log4(("ctrl.u64ExitCode %#RX64\n", pVmcb->ctrl.u64ExitCode));
3390 Log4(("ctrl.u64ExitInfo1 %#RX64\n", pVmcb->ctrl.u64ExitInfo1));
3391 Log4(("ctrl.u64ExitInfo2 %#RX64\n", pVmcb->ctrl.u64ExitInfo2));
3392 Log4(("ctrl.ExitIntInfo.u8Vector %#x\n", pVmcb->ctrl.ExitIntInfo.n.u8Vector));
3393 Log4(("ctrl.ExitIntInfo.u3Type %#x\n", pVmcb->ctrl.ExitIntInfo.n.u3Type));
3394 Log4(("ctrl.ExitIntInfo.u1ErrorCodeValid %#x\n", pVmcb->ctrl.ExitIntInfo.n.u1ErrorCodeValid));
3395 Log4(("ctrl.ExitIntInfo.u19Reserved %#x\n", pVmcb->ctrl.ExitIntInfo.n.u19Reserved));
3396 Log4(("ctrl.ExitIntInfo.u1Valid %#x\n", pVmcb->ctrl.ExitIntInfo.n.u1Valid));
3397 Log4(("ctrl.ExitIntInfo.u32ErrorCode %#x\n", pVmcb->ctrl.ExitIntInfo.n.u32ErrorCode));
3398 Log4(("ctrl.NestedPaging %#RX64\n", pVmcb->ctrl.NestedPaging.u));
3399 Log4(("ctrl.EventInject.u8Vector %#x\n", pVmcb->ctrl.EventInject.n.u8Vector));
3400 Log4(("ctrl.EventInject.u3Type %#x\n", pVmcb->ctrl.EventInject.n.u3Type));
3401 Log4(("ctrl.EventInject.u1ErrorCodeValid %#x\n", pVmcb->ctrl.EventInject.n.u1ErrorCodeValid));
3402 Log4(("ctrl.EventInject.u19Reserved %#x\n", pVmcb->ctrl.EventInject.n.u19Reserved));
3403 Log4(("ctrl.EventInject.u1Valid %#x\n", pVmcb->ctrl.EventInject.n.u1Valid));
3404 Log4(("ctrl.EventInject.u32ErrorCode %#x\n", pVmcb->ctrl.EventInject.n.u32ErrorCode));
3405
3406 Log4(("ctrl.u64NestedPagingCR3 %#RX64\n", pVmcb->ctrl.u64NestedPagingCR3));
3407 Log4(("ctrl.u64LBRVirt %#RX64\n", pVmcb->ctrl.u64LBRVirt));
3408
3409 Log4(("guest.CS.u16Sel %RTsel\n", pVmcb->guest.CS.u16Sel));
3410 Log4(("guest.CS.u16Attr %#x\n", pVmcb->guest.CS.u16Attr));
3411 Log4(("guest.CS.u32Limit %#RX32\n", pVmcb->guest.CS.u32Limit));
3412 Log4(("guest.CS.u64Base %#RX64\n", pVmcb->guest.CS.u64Base));
3413 Log4(("guest.DS.u16Sel %#RTsel\n", pVmcb->guest.DS.u16Sel));
3414 Log4(("guest.DS.u16Attr %#x\n", pVmcb->guest.DS.u16Attr));
3415 Log4(("guest.DS.u32Limit %#RX32\n", pVmcb->guest.DS.u32Limit));
3416 Log4(("guest.DS.u64Base %#RX64\n", pVmcb->guest.DS.u64Base));
3417 Log4(("guest.ES.u16Sel %RTsel\n", pVmcb->guest.ES.u16Sel));
3418 Log4(("guest.ES.u16Attr %#x\n", pVmcb->guest.ES.u16Attr));
3419 Log4(("guest.ES.u32Limit %#RX32\n", pVmcb->guest.ES.u32Limit));
3420 Log4(("guest.ES.u64Base %#RX64\n", pVmcb->guest.ES.u64Base));
3421 Log4(("guest.FS.u16Sel %RTsel\n", pVmcb->guest.FS.u16Sel));
3422 Log4(("guest.FS.u16Attr %#x\n", pVmcb->guest.FS.u16Attr));
3423 Log4(("guest.FS.u32Limit %#RX32\n", pVmcb->guest.FS.u32Limit));
3424 Log4(("guest.FS.u64Base %#RX64\n", pVmcb->guest.FS.u64Base));
3425 Log4(("guest.GS.u16Sel %RTsel\n", pVmcb->guest.GS.u16Sel));
3426 Log4(("guest.GS.u16Attr %#x\n", pVmcb->guest.GS.u16Attr));
3427 Log4(("guest.GS.u32Limit %#RX32\n", pVmcb->guest.GS.u32Limit));
3428 Log4(("guest.GS.u64Base %#RX64\n", pVmcb->guest.GS.u64Base));
3429
3430 Log4(("guest.GDTR.u32Limit %#RX32\n", pVmcb->guest.GDTR.u32Limit));
3431 Log4(("guest.GDTR.u64Base %#RX64\n", pVmcb->guest.GDTR.u64Base));
3432
3433 Log4(("guest.LDTR.u16Sel %RTsel\n", pVmcb->guest.LDTR.u16Sel));
3434 Log4(("guest.LDTR.u16Attr %#x\n", pVmcb->guest.LDTR.u16Attr));
3435 Log4(("guest.LDTR.u32Limit %#RX32\n", pVmcb->guest.LDTR.u32Limit));
3436 Log4(("guest.LDTR.u64Base %#RX64\n", pVmcb->guest.LDTR.u64Base));
3437
3438 Log4(("guest.IDTR.u32Limit %#RX32\n", pVmcb->guest.IDTR.u32Limit));
3439 Log4(("guest.IDTR.u64Base %#RX64\n", pVmcb->guest.IDTR.u64Base));
3440
3441 Log4(("guest.TR.u16Sel %RTsel\n", pVmcb->guest.TR.u16Sel));
3442 Log4(("guest.TR.u16Attr %#x\n", pVmcb->guest.TR.u16Attr));
3443 Log4(("guest.TR.u32Limit %#RX32\n", pVmcb->guest.TR.u32Limit));
3444 Log4(("guest.TR.u64Base %#RX64\n", pVmcb->guest.TR.u64Base));
3445
3446 Log4(("guest.u8CPL %#x\n", pVmcb->guest.u8CPL));
3447 Log4(("guest.u64CR0 %#RX64\n", pVmcb->guest.u64CR0));
3448 Log4(("guest.u64CR2 %#RX64\n", pVmcb->guest.u64CR2));
3449 Log4(("guest.u64CR3 %#RX64\n", pVmcb->guest.u64CR3));
3450 Log4(("guest.u64CR4 %#RX64\n", pVmcb->guest.u64CR4));
3451 Log4(("guest.u64DR6 %#RX64\n", pVmcb->guest.u64DR6));
3452 Log4(("guest.u64DR7 %#RX64\n", pVmcb->guest.u64DR7));
3453
3454 Log4(("guest.u64RIP %#RX64\n", pVmcb->guest.u64RIP));
3455 Log4(("guest.u64RSP %#RX64\n", pVmcb->guest.u64RSP));
3456 Log4(("guest.u64RAX %#RX64\n", pVmcb->guest.u64RAX));
3457 Log4(("guest.u64RFlags %#RX64\n", pVmcb->guest.u64RFlags));
3458
3459 Log4(("guest.u64SysEnterCS %#RX64\n", pVmcb->guest.u64SysEnterCS));
3460 Log4(("guest.u64SysEnterEIP %#RX64\n", pVmcb->guest.u64SysEnterEIP));
3461 Log4(("guest.u64SysEnterESP %#RX64\n", pVmcb->guest.u64SysEnterESP));
3462
3463 Log4(("guest.u64EFER %#RX64\n", pVmcb->guest.u64EFER));
3464 Log4(("guest.u64STAR %#RX64\n", pVmcb->guest.u64STAR));
3465 Log4(("guest.u64LSTAR %#RX64\n", pVmcb->guest.u64LSTAR));
3466 Log4(("guest.u64CSTAR %#RX64\n", pVmcb->guest.u64CSTAR));
3467 Log4(("guest.u64SFMASK %#RX64\n", pVmcb->guest.u64SFMASK));
3468 Log4(("guest.u64KernelGSBase %#RX64\n", pVmcb->guest.u64KernelGSBase));
3469 Log4(("guest.u64GPAT %#RX64\n", pVmcb->guest.u64GPAT));
3470 Log4(("guest.u64DBGCTL %#RX64\n", pVmcb->guest.u64DBGCTL));
3471 Log4(("guest.u64BR_FROM %#RX64\n", pVmcb->guest.u64BR_FROM));
3472 Log4(("guest.u64BR_TO %#RX64\n", pVmcb->guest.u64BR_TO));
3473 Log4(("guest.u64LASTEXCPFROM %#RX64\n", pVmcb->guest.u64LASTEXCPFROM));
3474 Log4(("guest.u64LASTEXCPTO %#RX64\n", pVmcb->guest.u64LASTEXCPTO));
3475#endif /* VBOX_STRICT */
3476 }
3477 else
3478 Log4(("hmR0SvmReportWorldSwitchError: rcVMRun=%d\n", rcVMRun));
3479
3480 NOREF(pVmcb);
3481}
3482
3483
3484/**
3485 * Check per-VM and per-VCPU force flag actions that require us to go back to
3486 * ring-3 for one reason or another.
3487 *
3488 * @returns VBox status code (information status code included).
3489 * @retval VINF_SUCCESS if we don't have any actions that require going back to
3490 * ring-3.
3491 * @retval VINF_PGM_SYNC_CR3 if we have pending PGM CR3 sync.
3492 * @retval VINF_EM_PENDING_REQUEST if we have pending requests (like hardware
3493 * interrupts)
3494 * @retval VINF_PGM_POOL_FLUSH_PENDING if PGM is doing a pool flush and requires
3495 * all EMTs to be in ring-3.
3496 * @retval VINF_EM_RAW_TO_R3 if there is pending DMA requests.
3497 * @retval VINF_EM_NO_MEMORY PGM is out of memory, we need to return
3498 * to the EM loop.
3499 *
3500 * @param pVM The cross context VM structure.
3501 * @param pVCpu The cross context virtual CPU structure.
3502 * @param pCtx Pointer to the guest-CPU context.
3503 */
3504static int hmR0SvmCheckForceFlags(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
3505{
3506 Assert(VMMRZCallRing3IsEnabled(pVCpu));
3507
3508 /* On AMD-V we don't need to update CR3, PAE PDPES lazily. See hmR0SvmSaveGuestState(). */
3509 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_CR3));
3510 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_UPDATE_PAE_PDPES));
3511
3512 /* Update pending interrupts into the APIC's IRR. */
3513 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_UPDATE_APIC))
3514 APICUpdatePendingInterrupts(pVCpu);
3515
3516 if ( VM_FF_IS_PENDING(pVM, !pVCpu->hm.s.fSingleInstruction
3517 ? VM_FF_HP_R0_PRE_HM_MASK : VM_FF_HP_R0_PRE_HM_STEP_MASK)
3518 || VMCPU_FF_IS_PENDING(pVCpu, !pVCpu->hm.s.fSingleInstruction
3519 ? VMCPU_FF_HP_R0_PRE_HM_MASK : VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
3520 {
3521 /* Pending PGM C3 sync. */
3522 if (VMCPU_FF_IS_PENDING(pVCpu,VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL))
3523 {
3524 int rc = PGMSyncCR3(pVCpu, pCtx->cr0, pCtx->cr3, pCtx->cr4, VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_PGM_SYNC_CR3));
3525 if (rc != VINF_SUCCESS)
3526 {
3527 Log4(("hmR0SvmCheckForceFlags: PGMSyncCR3 forcing us back to ring-3. rc=%d\n", rc));
3528 return rc;
3529 }
3530 }
3531
3532 /* Pending HM-to-R3 operations (critsects, timers, EMT rendezvous etc.) */
3533 /* -XXX- what was that about single stepping? */
3534 if ( VM_FF_IS_PENDING(pVM, VM_FF_HM_TO_R3_MASK)
3535 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
3536 {
3537 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
3538 int rc = RT_UNLIKELY(VM_FF_IS_PENDING(pVM, VM_FF_PGM_NO_MEMORY)) ? VINF_EM_NO_MEMORY : VINF_EM_RAW_TO_R3;
3539 Log4(("hmR0SvmCheckForceFlags: HM_TO_R3 forcing us back to ring-3. rc=%d\n", rc));
3540 return rc;
3541 }
3542
3543 /* Pending VM request packets, such as hardware interrupts. */
3544 if ( VM_FF_IS_PENDING(pVM, VM_FF_REQUEST)
3545 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_REQUEST))
3546 {
3547 Log4(("hmR0SvmCheckForceFlags: Pending VM request forcing us back to ring-3\n"));
3548 return VINF_EM_PENDING_REQUEST;
3549 }
3550
3551 /* Pending PGM pool flushes. */
3552 if (VM_FF_IS_PENDING(pVM, VM_FF_PGM_POOL_FLUSH_PENDING))
3553 {
3554 Log4(("hmR0SvmCheckForceFlags: PGM pool flush pending forcing us back to ring-3\n"));
3555 return VINF_PGM_POOL_FLUSH_PENDING;
3556 }
3557
3558 /* Pending DMA requests. */
3559 if (VM_FF_IS_PENDING(pVM, VM_FF_PDM_DMA))
3560 {
3561 Log4(("hmR0SvmCheckForceFlags: Pending DMA request forcing us back to ring-3\n"));
3562 return VINF_EM_RAW_TO_R3;
3563 }
3564 }
3565
3566 return VINF_SUCCESS;
3567}
3568
3569
3570#ifdef VBOX_WITH_NESTED_HWVIRT
3571/**
3572 * Does the preparations before executing nested-guest code in AMD-V.
3573 *
3574 * @returns VBox status code (informational status codes included).
3575 * @retval VINF_SUCCESS if we can proceed with running the guest.
3576 * @retval VINF_* scheduling changes, we have to go back to ring-3.
3577 *
3578 * @param pVM The cross context VM structure.
3579 * @param pVCpu The cross context virtual CPU structure.
3580 * @param pCtx Pointer to the guest-CPU context.
3581 * @param pSvmTransient Pointer to the SVM transient structure.
3582 *
3583 * @remarks Same caveats regarding longjumps as hmR0SvmPreRunGuest applies.
3584 * @sa hmR0SvmPreRunGuest.
3585 */
3586static int hmR0SvmPreRunGuestNested(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
3587{
3588 HMSVM_ASSERT_PREEMPT_SAFE();
3589
3590#ifdef VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM
3591 if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
3592 {
3593 Log2(("hmR0SvmPreRunGuest: Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
3594 return VINF_EM_RESCHEDULE_REM;
3595 }
3596#endif
3597
3598 /* Check force flag actions that might require us to go back to ring-3. */
3599 int rc = hmR0SvmCheckForceFlags(pVM, pVCpu, pCtx);
3600 if (rc != VINF_SUCCESS)
3601 return rc;
3602
3603 if (TRPMHasTrap(pVCpu))
3604 hmR0SvmTrpmTrapToPendingEvent(pVCpu);
3605 else if (!pVCpu->hm.s.Event.fPending)
3606 hmR0SvmEvaluatePendingEventNested(pVCpu, pCtx);
3607
3608 /*
3609 * On the oldest AMD-V systems, we may not get enough information to reinject an NMI.
3610 * Just do it in software, see @bugref{8411}.
3611 * NB: If we could continue a task switch exit we wouldn't need to do this.
3612 */
3613 if (RT_UNLIKELY( !pVM->hm.s.svm.u32Features
3614 && pVCpu->hm.s.Event.fPending
3615 && SVM_EVENT_GET_TYPE(pVCpu->hm.s.Event.u64IntInfo) == SVM_EVENT_NMI))
3616 {
3617 return VINF_EM_RAW_INJECT_TRPM_EVENT;
3618 }
3619
3620 /*
3621 * Load the nested-guest state. We can optimize this later to be avoided when VMRUN is
3622 * just emulated in hmR0SvmExecVmrun since the VMCB is already setup by the nested-hypervisor,
3623 * We currently do this because we may pre-maturely return to ring-3 before executing the
3624 * nested-guest and doing it here is simpler.
3625 */
3626 rc = hmR0SvmLoadGuestStateNested(pVCpu, pCtx);
3627 AssertRCReturn(rc, rc);
3628 /** @todo Get new STAM counter for this? */
3629 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadFull);
3630
3631 /*
3632 * No longjmps to ring-3 from this point on!!!
3633 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
3634 * This also disables flushing of the R0-logger instance (if any).
3635 */
3636 VMMRZCallRing3Disable(pVCpu);
3637
3638 /*
3639 * We disable interrupts so that we don't miss any interrupts that would flag preemption (IPI/timers etc.)
3640 * when thread-context hooks aren't used and we've been running with preemption disabled for a while.
3641 *
3642 * We need to check for force-flags that could've possible been altered since we last checked them (e.g.
3643 * by PDMGetInterrupt() leaving the PDM critical section, see @bugref{6398}).
3644 *
3645 * We also check a couple of other force-flags as a last opportunity to get the EMT back to ring-3 before
3646 * executing guest code.
3647 */
3648 pSvmTransient->fEFlags = ASMIntDisableFlags();
3649 if ( VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
3650 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
3651 {
3652 ASMSetFlags(pSvmTransient->fEFlags);
3653 VMMRZCallRing3Enable(pVCpu);
3654 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
3655 return VINF_EM_RAW_TO_R3;
3656 }
3657 if (RTThreadPreemptIsPending(NIL_RTTHREAD))
3658 {
3659 ASMSetFlags(pSvmTransient->fEFlags);
3660 VMMRZCallRing3Enable(pVCpu);
3661 STAM_COUNTER_INC(&pVCpu->hm.s.StatPendingHostIrq);
3662 return VINF_EM_RAW_INTERRUPT;
3663 }
3664
3665 /*
3666 * If we are injecting an NMI, we must set VMCPU_FF_BLOCK_NMIS only when we are going to execute
3667 * guest code for certain (no exits to ring-3). Otherwise, we could re-read the flag on re-entry into
3668 * AMD-V and conclude that NMI inhibition is active when we have not even delivered the NMI.
3669 *
3670 * With VT-x, this is handled by the Guest interruptibility information VMCS field which will set the
3671 * VMCS field after actually delivering the NMI which we read on VM-exit to determine the state.
3672 */
3673 if (pVCpu->hm.s.Event.fPending)
3674 {
3675 SVMEVENT Event;
3676 Event.u = pVCpu->hm.s.Event.u64IntInfo;
3677 if ( Event.n.u1Valid
3678 && Event.n.u3Type == SVM_EVENT_NMI
3679 && Event.n.u8Vector == X86_XCPT_NMI
3680 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
3681 {
3682 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
3683 }
3684 }
3685
3686 return VINF_SUCCESS;
3687}
3688#endif
3689
3690
3691/**
3692 * Does the preparations before executing guest code in AMD-V.
3693 *
3694 * This may cause longjmps to ring-3 and may even result in rescheduling to the
3695 * recompiler. We must be cautious what we do here regarding committing
3696 * guest-state information into the VMCB assuming we assuredly execute the guest
3697 * in AMD-V. If we fall back to the recompiler after updating the VMCB and
3698 * clearing the common-state (TRPM/forceflags), we must undo those changes so
3699 * that the recompiler can (and should) use them when it resumes guest
3700 * execution. Otherwise such operations must be done when we can no longer
3701 * exit to ring-3.
3702 *
3703 * @returns VBox status code (informational status codes included).
3704 * @retval VINF_SUCCESS if we can proceed with running the guest.
3705 * @retval VINF_* scheduling changes, we have to go back to ring-3.
3706 *
3707 * @param pVM The cross context VM structure.
3708 * @param pVCpu The cross context virtual CPU structure.
3709 * @param pCtx Pointer to the guest-CPU context.
3710 * @param pSvmTransient Pointer to the SVM transient structure.
3711 */
3712static int hmR0SvmPreRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
3713{
3714 HMSVM_ASSERT_PREEMPT_SAFE();
3715 Assert(!CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
3716
3717#if defined(VBOX_WITH_NESTED_HWVIRT) && defined(VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM)
3718
3719 /* IEM only for executing nested guest, we shouldn't get here. */
3720 if (CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
3721 {
3722 Log2(("hmR0SvmPreRunGuest: Rescheduling to IEM due to nested-hwvirt or forced IEM exec -> VINF_EM_RESCHEDULE_REM\n"));
3723 return VINF_EM_RESCHEDULE_REM;
3724 }
3725#endif
3726
3727 /* Check force flag actions that might require us to go back to ring-3. */
3728 int rc = hmR0SvmCheckForceFlags(pVM, pVCpu, pCtx);
3729 if (rc != VINF_SUCCESS)
3730 return rc;
3731
3732 if (TRPMHasTrap(pVCpu))
3733 hmR0SvmTrpmTrapToPendingEvent(pVCpu);
3734 else if (!pVCpu->hm.s.Event.fPending)
3735 hmR0SvmEvaluatePendingEvent(pVCpu, pCtx);
3736
3737 /*
3738 * On the oldest AMD-V systems, we may not get enough information to reinject an NMI.
3739 * Just do it in software, see @bugref{8411}.
3740 * NB: If we could continue a task switch exit we wouldn't need to do this.
3741 */
3742 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending && (((pVCpu->hm.s.Event.u64IntInfo >> 8) & 7) == SVM_EVENT_NMI)))
3743 if (RT_UNLIKELY(!pVM->hm.s.svm.u32Features))
3744 return VINF_EM_RAW_INJECT_TRPM_EVENT;
3745
3746#ifdef HMSVM_SYNC_FULL_GUEST_STATE
3747 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
3748#endif
3749
3750 /* Load the guest bits that are not shared with the host in any way since we can longjmp or get preempted. */
3751 rc = hmR0SvmLoadGuestState(pVM, pVCpu, pCtx);
3752 AssertRCReturn(rc, rc);
3753 STAM_COUNTER_INC(&pVCpu->hm.s.StatLoadFull);
3754
3755 /*
3756 * If we're not intercepting TPR changes in the guest, save the guest TPR before the world-switch
3757 * so we can update it on the way back if the guest changed the TPR.
3758 */
3759 if (pVCpu->hm.s.svm.fSyncVTpr)
3760 {
3761 if (pVM->hm.s.fTPRPatchingActive)
3762 pSvmTransient->u8GuestTpr = pCtx->msrLSTAR;
3763 else
3764 {
3765 PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
3766 pSvmTransient->u8GuestTpr = pVmcb->ctrl.IntCtrl.n.u8VTPR;
3767 }
3768 }
3769
3770 /*
3771 * No longjmps to ring-3 from this point on!!!
3772 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
3773 * This also disables flushing of the R0-logger instance (if any).
3774 */
3775 VMMRZCallRing3Disable(pVCpu);
3776
3777 /*
3778 * We disable interrupts so that we don't miss any interrupts that would flag preemption (IPI/timers etc.)
3779 * when thread-context hooks aren't used and we've been running with preemption disabled for a while.
3780 *
3781 * We need to check for force-flags that could've possible been altered since we last checked them (e.g.
3782 * by PDMGetInterrupt() leaving the PDM critical section, see @bugref{6398}).
3783 *
3784 * We also check a couple of other force-flags as a last opportunity to get the EMT back to ring-3 before
3785 * executing guest code.
3786 */
3787 pSvmTransient->fEFlags = ASMIntDisableFlags();
3788 if ( VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
3789 || VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
3790 {
3791 ASMSetFlags(pSvmTransient->fEFlags);
3792 VMMRZCallRing3Enable(pVCpu);
3793 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHmToR3FF);
3794 return VINF_EM_RAW_TO_R3;
3795 }
3796 if (RTThreadPreemptIsPending(NIL_RTTHREAD))
3797 {
3798 ASMSetFlags(pSvmTransient->fEFlags);
3799 VMMRZCallRing3Enable(pVCpu);
3800 STAM_COUNTER_INC(&pVCpu->hm.s.StatPendingHostIrq);
3801 return VINF_EM_RAW_INTERRUPT;
3802 }
3803
3804 /*
3805 * If we are injecting an NMI, we must set VMCPU_FF_BLOCK_NMIS only when we are going to execute
3806 * guest code for certain (no exits to ring-3). Otherwise, we could re-read the flag on re-entry into
3807 * AMD-V and conclude that NMI inhibition is active when we have not even delivered the NMI.
3808 *
3809 * With VT-x, this is handled by the Guest interruptibility information VMCS field which will set the
3810 * VMCS field after actually delivering the NMI which we read on VM-exit to determine the state.
3811 */
3812 if (pVCpu->hm.s.Event.fPending)
3813 {
3814 SVMEVENT Event;
3815 Event.u = pVCpu->hm.s.Event.u64IntInfo;
3816 if ( Event.n.u1Valid
3817 && Event.n.u3Type == SVM_EVENT_NMI
3818 && Event.n.u8Vector == X86_XCPT_NMI
3819 && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_BLOCK_NMIS))
3820 {
3821 VMCPU_FF_SET(pVCpu, VMCPU_FF_BLOCK_NMIS);
3822 }
3823 }
3824
3825 return VINF_SUCCESS;
3826}
3827
3828
3829#ifdef VBOX_WITH_NESTED_HWVIRT
3830/**
3831 * Prepares to run nested-guest code in AMD-V and we've committed to doing so. This
3832 * means there is no backing out to ring-3 or anywhere else at this point.
3833 *
3834 * @param pVM The cross context VM structure.
3835 * @param pVCpu The cross context virtual CPU structure.
3836 * @param pCtx Pointer to the guest-CPU context.
3837 * @param pSvmTransient Pointer to the SVM transient structure.
3838 *
3839 * @remarks Called with preemption disabled.
3840 * @remarks No-long-jump zone!!!
3841 */
3842static void hmR0SvmPreRunGuestCommittedNested(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
3843{
3844 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
3845 Assert(VMMR0IsLogFlushDisabled(pVCpu));
3846 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
3847
3848 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
3849 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC); /* Indicate the start of guest execution. */
3850
3851 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
3852 hmR0SvmInjectPendingEvent(pVCpu, pCtx, pVmcbNstGst);
3853
3854 if ( pVCpu->hm.s.fPreloadGuestFpu
3855 && !CPUMIsGuestFPUStateActive(pVCpu))
3856 {
3857 CPUMR0LoadGuestFPU(pVM, pVCpu); /* (Ignore rc, no need to set HM_CHANGED_HOST_CONTEXT for SVM.) */
3858 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
3859 }
3860
3861 /* Load the state shared between host and nested-guest (FPU, debug). */
3862 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE))
3863 hmR0SvmLoadSharedState(pVCpu, pVmcbNstGst, pCtx);
3864
3865 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_HOST_CONTEXT); /* Preemption might set this, nothing to do on AMD-V. */
3866 AssertMsg(!HMCPU_CF_VALUE(pVCpu), ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
3867
3868 /* Setup TSC offsetting. */
3869 RTCPUID idCurrentCpu = hmR0GetCurrentCpu()->idCpu;
3870 if ( pSvmTransient->fUpdateTscOffsetting
3871 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
3872 {
3873 hmR0SvmUpdateTscOffsetting(pVM, pVCpu, pVmcbNstGst);
3874 pSvmTransient->fUpdateTscOffsetting = false;
3875 }
3876
3877 /* If we've migrating CPUs, mark the VMCB Clean bits as dirty. */
3878 if (idCurrentCpu != pVCpu->hm.s.idLastCpu)
3879 pVmcbNstGst->ctrl.u64VmcbCleanBits = 0;
3880
3881 /* Store status of the shared guest-host state at the time of VMRUN. */
3882#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
3883 if (CPUMIsGuestInLongModeEx(pCtx))
3884 {
3885 pSvmTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActivePending(pVCpu);
3886 pSvmTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActivePending(pVCpu);
3887 }
3888 else
3889#endif
3890 {
3891 pSvmTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
3892 pSvmTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
3893 }
3894 pSvmTransient->fWasGuestFPUStateActive = CPUMIsGuestFPUStateActive(pVCpu);
3895
3896 /* The TLB flushing would've already been setup by the nested-hypervisor. */
3897 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
3898 hmR0SvmFlushTaggedTlb(pVCpu, pCtx, pVmcbNstGst);
3899 Assert(hmR0GetCurrentCpu()->idCpu == pVCpu->hm.s.idLastCpu);
3900
3901 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
3902
3903 TMNotifyStartOfExecution(pVCpu); /* Finally, notify TM to resume its clocks as we're about
3904 to start executing. */
3905
3906 /*
3907 * Save the current Host TSC_AUX and write the guest TSC_AUX to the host, so that
3908 * RDTSCPs (that don't cause exits) reads the guest MSR. See @bugref{3324}.
3909 *
3910 * This should be done -after- any RDTSCPs for obtaining the host timestamp (TM, STAM etc).
3911 */
3912 uint8_t *pbMsrBitmap = (uint8_t *)pCtx->hwvirt.svm.CTX_SUFF(pvMsrBitmap);
3913 if ( (pVM->hm.s.cpuid.u32AMDFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_RDTSCP)
3914 && !(pVmcbNstGst->ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDTSCP))
3915 {
3916 hmR0SvmSetMsrPermission(pVmcbNstGst, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
3917 pVCpu->hm.s.u64HostTscAux = ASMRdMsr(MSR_K8_TSC_AUX);
3918 uint64_t u64GuestTscAux = CPUMR0GetGuestTscAux(pVCpu);
3919 if (u64GuestTscAux != pVCpu->hm.s.u64HostTscAux)
3920 ASMWrMsr(MSR_K8_TSC_AUX, u64GuestTscAux);
3921 pSvmTransient->fRestoreTscAuxMsr = true;
3922 }
3923 else
3924 {
3925 hmR0SvmSetMsrPermission(pVmcbNstGst, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_INTERCEPT_READ, SVMMSREXIT_INTERCEPT_WRITE);
3926 pSvmTransient->fRestoreTscAuxMsr = false;
3927 }
3928
3929 /*
3930 * If VMCB Clean bits isn't supported by the CPU or exposed by the guest,
3931 * mark all state-bits as dirty indicating to the CPU to re-load from VMCB.
3932 */
3933 if ( !(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_VMCB_CLEAN)
3934 || !(pVM->cpum.ro.GuestFeatures.fSvmVmcbClean))
3935 pVmcbNstGst->ctrl.u64VmcbCleanBits = 0;
3936}
3937#endif
3938
3939
3940/**
3941 * Prepares to run guest code in AMD-V and we've committed to doing so. This
3942 * means there is no backing out to ring-3 or anywhere else at this
3943 * point.
3944 *
3945 * @param pVM The cross context VM structure.
3946 * @param pVCpu The cross context virtual CPU structure.
3947 * @param pCtx Pointer to the guest-CPU context.
3948 * @param pSvmTransient Pointer to the SVM transient structure.
3949 *
3950 * @remarks Called with preemption disabled.
3951 * @remarks No-long-jump zone!!!
3952 */
3953static void hmR0SvmPreRunGuestCommitted(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
3954{
3955 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
3956 Assert(VMMR0IsLogFlushDisabled(pVCpu));
3957 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
3958
3959 VMCPU_ASSERT_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
3960 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC); /* Indicate the start of guest execution. */
3961
3962 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
3963 hmR0SvmInjectPendingEvent(pVCpu, pCtx, pVmcb);
3964
3965 if ( pVCpu->hm.s.fPreloadGuestFpu
3966 && !CPUMIsGuestFPUStateActive(pVCpu))
3967 {
3968 CPUMR0LoadGuestFPU(pVM, pVCpu); /* (Ignore rc, no need to set HM_CHANGED_HOST_CONTEXT for SVM.) */
3969 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
3970 }
3971
3972 /* Load the state shared between host and guest (FPU, debug). */
3973 if (HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE))
3974 hmR0SvmLoadSharedState(pVCpu, pVmcb, pCtx);
3975
3976 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_HOST_CONTEXT); /* Preemption might set this, nothing to do on AMD-V. */
3977 AssertMsg(!HMCPU_CF_VALUE(pVCpu), ("fContextUseFlags=%#RX32\n", HMCPU_CF_VALUE(pVCpu)));
3978
3979 /* Setup TSC offsetting. */
3980 RTCPUID idCurrentCpu = hmR0GetCurrentCpu()->idCpu;
3981 if ( pSvmTransient->fUpdateTscOffsetting
3982 || idCurrentCpu != pVCpu->hm.s.idLastCpu)
3983 {
3984 hmR0SvmUpdateTscOffsetting(pVM, pVCpu, pVmcb);
3985 pSvmTransient->fUpdateTscOffsetting = false;
3986 }
3987
3988 /* If we've migrating CPUs, mark the VMCB Clean bits as dirty. */
3989 if (idCurrentCpu != pVCpu->hm.s.idLastCpu)
3990 pVmcb->ctrl.u64VmcbCleanBits = 0;
3991
3992 /* Store status of the shared guest-host state at the time of VMRUN. */
3993#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
3994 if (CPUMIsGuestInLongModeEx(pCtx))
3995 {
3996 pSvmTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActivePending(pVCpu);
3997 pSvmTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActivePending(pVCpu);
3998 }
3999 else
4000#endif
4001 {
4002 pSvmTransient->fWasGuestDebugStateActive = CPUMIsGuestDebugStateActive(pVCpu);
4003 pSvmTransient->fWasHyperDebugStateActive = CPUMIsHyperDebugStateActive(pVCpu);
4004 }
4005 pSvmTransient->fWasGuestFPUStateActive = CPUMIsGuestFPUStateActive(pVCpu);
4006
4007 /* Flush the appropriate tagged-TLB entries. */
4008 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true); /* Used for TLB flushing, set this across the world switch. */
4009 hmR0SvmFlushTaggedTlb(pVCpu, pCtx, pVmcb);
4010 Assert(hmR0GetCurrentCpu()->idCpu == pVCpu->hm.s.idLastCpu);
4011
4012 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatEntry, &pVCpu->hm.s.StatInGC, x);
4013
4014 TMNotifyStartOfExecution(pVCpu); /* Finally, notify TM to resume its clocks as we're about
4015 to start executing. */
4016
4017 /*
4018 * Save the current Host TSC_AUX and write the guest TSC_AUX to the host, so that
4019 * RDTSCPs (that don't cause exits) reads the guest MSR. See @bugref{3324}.
4020 *
4021 * This should be done -after- any RDTSCPs for obtaining the host timestamp (TM, STAM etc).
4022 */
4023 uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.svm.pvMsrBitmap;
4024 if ( (pVM->hm.s.cpuid.u32AMDFeatureEDX & X86_CPUID_EXT_FEATURE_EDX_RDTSCP)
4025 && !(pVmcb->ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDTSCP))
4026 {
4027 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
4028 pVCpu->hm.s.u64HostTscAux = ASMRdMsr(MSR_K8_TSC_AUX);
4029 uint64_t u64GuestTscAux = CPUMR0GetGuestTscAux(pVCpu);
4030 if (u64GuestTscAux != pVCpu->hm.s.u64HostTscAux)
4031 ASMWrMsr(MSR_K8_TSC_AUX, u64GuestTscAux);
4032 pSvmTransient->fRestoreTscAuxMsr = true;
4033 }
4034 else
4035 {
4036 hmR0SvmSetMsrPermission(pVmcb, pbMsrBitmap, MSR_K8_TSC_AUX, SVMMSREXIT_INTERCEPT_READ, SVMMSREXIT_INTERCEPT_WRITE);
4037 pSvmTransient->fRestoreTscAuxMsr = false;
4038 }
4039
4040 /* If VMCB Clean bits isn't supported by the CPU, simply mark all state-bits as dirty, indicating (re)load-from-VMCB. */
4041 if (!(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_VMCB_CLEAN))
4042 pVmcb->ctrl.u64VmcbCleanBits = 0;
4043}
4044
4045
4046/**
4047 * Wrapper for running the guest code in AMD-V.
4048 *
4049 * @returns VBox strict status code.
4050 * @param pVM The cross context VM structure.
4051 * @param pVCpu The cross context virtual CPU structure.
4052 * @param pCtx Pointer to the guest-CPU context.
4053 *
4054 * @remarks No-long-jump zone!!!
4055 */
4056DECLINLINE(int) hmR0SvmRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4057{
4058 /*
4059 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses floating-point operations
4060 * using SSE instructions. Some XMM registers (XMM6-XMM15) are callee-saved and thus the need for this XMM wrapper.
4061 * Refer MSDN docs. "Configuring Programs for 64-bit / x64 Software Conventions / Register Usage" for details.
4062 */
4063#ifdef VBOX_WITH_KERNEL_USING_XMM
4064 return hmR0SVMRunWrapXMM(pVCpu->hm.s.svm.HCPhysVmcbHost, pVCpu->hm.s.svm.HCPhysVmcb, pCtx, pVM, pVCpu,
4065 pVCpu->hm.s.svm.pfnVMRun);
4066#else
4067 return pVCpu->hm.s.svm.pfnVMRun(pVCpu->hm.s.svm.HCPhysVmcbHost, pVCpu->hm.s.svm.HCPhysVmcb, pCtx, pVM, pVCpu);
4068#endif
4069}
4070
4071
4072#ifdef VBOX_WITH_NESTED_HWVIRT
4073/**
4074 * Wrapper for running the nested-guest code in AMD-V.
4075 *
4076 * @returns VBox strict status code.
4077 * @param pVM The cross context VM structure.
4078 * @param pVCpu The cross context virtual CPU structure.
4079 * @param pCtx Pointer to the guest-CPU context.
4080 *
4081 * @remarks No-long-jump zone!!!
4082 */
4083DECLINLINE(int) hmR0SvmRunGuestNested(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4084{
4085 /*
4086 * 64-bit Windows uses XMM registers in the kernel as the Microsoft compiler expresses floating-point operations
4087 * using SSE instructions. Some XMM registers (XMM6-XMM15) are callee-saved and thus the need for this XMM wrapper.
4088 * Refer MSDN docs. "Configuring Programs for 64-bit / x64 Software Conventions / Register Usage" for details.
4089 */
4090#ifdef VBOX_WITH_KERNEL_USING_XMM
4091 return hmR0SVMRunWrapXMM(pVCpu->hm.s.svm.HCPhysVmcbHost, pCtx->hwvirt.svm.HCPhysVmcb, pCtx, pVM, pVCpu,
4092 pVCpu->hm.s.svm.pfnVMRun);
4093#else
4094 return pVCpu->hm.s.svm.pfnVMRun(pVCpu->hm.s.svm.HCPhysVmcbHost, pCtx->hwvirt.svm.HCPhysVmcb, pCtx, pVM, pVCpu);
4095#endif
4096}
4097
4098
4099/**
4100 * Performs some essential restoration of state after running nested-guest code in
4101 * AMD-V.
4102 *
4103 * @param pVM The cross context VM structure.
4104 * @param pVCpu The cross context virtual CPU structure.
4105 * @param pMixedCtx Pointer to the nested-guest-CPU context. The data maybe
4106 * out-of-sync. Make sure to update the required fields
4107 * before using them.
4108 * @param pSvmTransient Pointer to the SVM transient structure.
4109 * @param rcVMRun Return code of VMRUN.
4110 *
4111 * @remarks Called with interrupts disabled.
4112 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
4113 * unconditionally when it is safe to do so.
4114 */
4115static void hmR0SvmPostRunGuestNested(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PSVMTRANSIENT pSvmTransient, int rcVMRun)
4116{
4117 RT_NOREF(pVM);
4118 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
4119
4120 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
4121 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
4122
4123 /* TSC read must be done early for maximum accuracy. */
4124 PSVMVMCB pVmcbNstGst = pMixedCtx->hwvirt.svm.CTX_SUFF(pVmcb);
4125 PSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
4126 if (!(pVmcbNstGstCtrl->u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDTSC))
4127 TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVmcbNstGstCtrl->u64TSCOffset);
4128
4129 if (pSvmTransient->fRestoreTscAuxMsr)
4130 {
4131 uint64_t u64GuestTscAuxMsr = ASMRdMsr(MSR_K8_TSC_AUX);
4132 CPUMR0SetGuestTscAux(pVCpu, u64GuestTscAuxMsr);
4133 if (u64GuestTscAuxMsr != pVCpu->hm.s.u64HostTscAux)
4134 ASMWrMsr(MSR_K8_TSC_AUX, pVCpu->hm.s.u64HostTscAux);
4135 }
4136
4137 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatExit1, x);
4138 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
4139 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
4140
4141 Assert(!(ASMGetFlags() & X86_EFL_IF));
4142 ASMSetFlags(pSvmTransient->fEFlags); /* Enable interrupts. */
4143 VMMRZCallRing3Enable(pVCpu); /* It is now safe to do longjmps to ring-3!!! */
4144
4145 /* Mark the VMCB-state cache as unmodified by VMM. */
4146 pVmcbNstGstCtrl->u64VmcbCleanBits = HMSVM_VMCB_CLEAN_ALL;
4147
4148 /* If VMRUN failed, we can bail out early. This does -not- cover SVM_EXIT_INVALID. */
4149 if (RT_UNLIKELY(rcVMRun != VINF_SUCCESS))
4150 {
4151 Log4(("VMRUN failure: rcVMRun=%Rrc\n", rcVMRun));
4152 return;
4153 }
4154
4155 pSvmTransient->u64ExitCode = pVmcbNstGstCtrl->u64ExitCode; /* Save the #VMEXIT reason. */
4156 HMCPU_EXIT_HISTORY_ADD(pVCpu, pVmcbNstGstCtrl->u64ExitCode);/* Update the #VMEXIT history array. */
4157 pSvmTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
4158 pSvmTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
4159
4160 Assert(!pVCpu->hm.s.svm.fSyncVTpr);
4161 hmR0SvmSaveGuestState(pVCpu, pMixedCtx, pVmcbNstGst); /* Save the nested-guest state from the VMCB to the
4162 guest-CPU context. */
4163}
4164#endif
4165
4166/**
4167 * Performs some essential restoration of state after running guest code in
4168 * AMD-V.
4169 *
4170 * @param pVM The cross context VM structure.
4171 * @param pVCpu The cross context virtual CPU structure.
4172 * @param pMixedCtx Pointer to the guest-CPU context. The data maybe
4173 * out-of-sync. Make sure to update the required fields
4174 * before using them.
4175 * @param pSvmTransient Pointer to the SVM transient structure.
4176 * @param rcVMRun Return code of VMRUN.
4177 *
4178 * @remarks Called with interrupts disabled.
4179 * @remarks No-long-jump zone!!! This function will however re-enable longjmps
4180 * unconditionally when it is safe to do so.
4181 */
4182static void hmR0SvmPostRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PSVMTRANSIENT pSvmTransient, int rcVMRun)
4183{
4184 Assert(!VMMRZCallRing3IsEnabled(pVCpu));
4185
4186 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, false); /* See HMInvalidatePageOnAllVCpus(): used for TLB flushing. */
4187 ASMAtomicIncU32(&pVCpu->hm.s.cWorldSwitchExits); /* Initialized in vmR3CreateUVM(): used for EMT poking. */
4188
4189 PSVMVMCB pVmcb =pVCpu->hm.s.svm.pVmcb;
4190 pVmcb->ctrl.u64VmcbCleanBits = HMSVM_VMCB_CLEAN_ALL; /* Mark the VMCB-state cache as unmodified by VMM. */
4191
4192 /* TSC read must be done early for maximum accuracy. */
4193 if (!(pVmcb->ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDTSC))
4194 TMCpuTickSetLastSeen(pVCpu, ASMReadTSC() + pVmcb->ctrl.u64TSCOffset);
4195
4196 if (pSvmTransient->fRestoreTscAuxMsr)
4197 {
4198 uint64_t u64GuestTscAuxMsr = ASMRdMsr(MSR_K8_TSC_AUX);
4199 CPUMR0SetGuestTscAux(pVCpu, u64GuestTscAuxMsr);
4200 if (u64GuestTscAuxMsr != pVCpu->hm.s.u64HostTscAux)
4201 ASMWrMsr(MSR_K8_TSC_AUX, pVCpu->hm.s.u64HostTscAux);
4202 }
4203
4204 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatInGC, &pVCpu->hm.s.StatExit1, x);
4205 TMNotifyEndOfExecution(pVCpu); /* Notify TM that the guest is no longer running. */
4206 VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_HM);
4207
4208 Assert(!(ASMGetFlags() & X86_EFL_IF));
4209 ASMSetFlags(pSvmTransient->fEFlags); /* Enable interrupts. */
4210 VMMRZCallRing3Enable(pVCpu); /* It is now safe to do longjmps to ring-3!!! */
4211
4212 /* If VMRUN failed, we can bail out early. This does -not- cover SVM_EXIT_INVALID. */
4213 if (RT_UNLIKELY(rcVMRun != VINF_SUCCESS))
4214 {
4215 Log4(("VMRUN failure: rcVMRun=%Rrc\n", rcVMRun));
4216 return;
4217 }
4218
4219 pSvmTransient->u64ExitCode = pVmcb->ctrl.u64ExitCode; /* Save the #VMEXIT reason. */
4220 HMCPU_EXIT_HISTORY_ADD(pVCpu, pVmcb->ctrl.u64ExitCode); /* Update the #VMEXIT history array. */
4221 pSvmTransient->fVectoringDoublePF = false; /* Vectoring double page-fault needs to be determined later. */
4222 pSvmTransient->fVectoringPF = false; /* Vectoring page-fault needs to be determined later. */
4223
4224 hmR0SvmSaveGuestState(pVCpu, pMixedCtx, pVmcb); /* Save the guest state from the VMCB to the guest-CPU context. */
4225
4226 if (RT_LIKELY(pSvmTransient->u64ExitCode != SVM_EXIT_INVALID))
4227 {
4228 if (pVCpu->hm.s.svm.fSyncVTpr)
4229 {
4230 /* TPR patching (for 32-bit guests) uses LSTAR MSR for holding the TPR value, otherwise uses the VTPR. */
4231 if ( pVM->hm.s.fTPRPatchingActive
4232 && (pMixedCtx->msrLSTAR & 0xff) != pSvmTransient->u8GuestTpr)
4233 {
4234 int rc = APICSetTpr(pVCpu, pMixedCtx->msrLSTAR & 0xff);
4235 AssertRC(rc);
4236 HMCPU_CF_SET(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE);
4237 }
4238 else if (pSvmTransient->u8GuestTpr != pVmcb->ctrl.IntCtrl.n.u8VTPR)
4239 {
4240 int rc = APICSetTpr(pVCpu, pVmcb->ctrl.IntCtrl.n.u8VTPR << 4);
4241 AssertRC(rc);
4242 HMCPU_CF_SET(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE);
4243 }
4244 }
4245 }
4246}
4247
4248
4249/**
4250 * Runs the guest code using AMD-V.
4251 *
4252 * @returns VBox status code.
4253 * @param pVM The cross context VM structure.
4254 * @param pVCpu The cross context virtual CPU structure.
4255 * @param pCtx Pointer to the guest-CPU context.
4256 * @param pcLoops Pointer to the number of executed loops.
4257 */
4258static int hmR0SvmRunGuestCodeNormal(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t *pcLoops)
4259{
4260 uint32_t const cMaxResumeLoops = pVM->hm.s.cMaxResumeLoops;
4261 Assert(pcLoops);
4262 Assert(*pcLoops <= cMaxResumeLoops);
4263
4264 SVMTRANSIENT SvmTransient;
4265 SvmTransient.fUpdateTscOffsetting = true;
4266
4267 int rc = VERR_INTERNAL_ERROR_5;
4268 for (;;)
4269 {
4270 Assert(!HMR0SuspendPending());
4271 HMSVM_ASSERT_CPU_SAFE();
4272
4273 /* Preparatory work for running guest code, this may force us to return
4274 to ring-3. This bugger disables interrupts on VINF_SUCCESS! */
4275 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
4276 rc = hmR0SvmPreRunGuest(pVM, pVCpu, pCtx, &SvmTransient);
4277 if (rc != VINF_SUCCESS)
4278 break;
4279
4280 /*
4281 * No longjmps to ring-3 from this point on!!!
4282 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
4283 * This also disables flushing of the R0-logger instance (if any).
4284 */
4285 hmR0SvmPreRunGuestCommitted(pVM, pVCpu, pCtx, &SvmTransient);
4286 rc = hmR0SvmRunGuest(pVM, pVCpu, pCtx);
4287
4288 /* Restore any residual host-state and save any bits shared between host
4289 and guest into the guest-CPU state. Re-enables interrupts! */
4290 hmR0SvmPostRunGuest(pVM, pVCpu, pCtx, &SvmTransient, rc);
4291
4292 if (RT_UNLIKELY( rc != VINF_SUCCESS /* Check for VMRUN errors. */
4293 || SvmTransient.u64ExitCode == SVM_EXIT_INVALID)) /* Check for invalid guest-state errors. */
4294 {
4295 if (rc == VINF_SUCCESS)
4296 rc = VERR_SVM_INVALID_GUEST_STATE;
4297 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
4298 hmR0SvmReportWorldSwitchError(pVM, pVCpu, rc, pCtx);
4299 break;
4300 }
4301
4302 /* Handle the #VMEXIT. */
4303 HMSVM_EXITCODE_STAM_COUNTER_INC(SvmTransient.u64ExitCode);
4304 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
4305 VBOXVMM_R0_HMSVM_VMEXIT(pVCpu, pCtx, SvmTransient.u64ExitCode, pVCpu->hm.s.svm.pVmcb);
4306 rc = hmR0SvmHandleExit(pVCpu, pCtx, &SvmTransient);
4307 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
4308 if (rc != VINF_SUCCESS)
4309 break;
4310 if (++(*pcLoops) >= cMaxResumeLoops)
4311 {
4312 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
4313 rc = VINF_EM_RAW_INTERRUPT;
4314 break;
4315 }
4316 }
4317
4318 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
4319 return rc;
4320}
4321
4322
4323/**
4324 * Runs the guest code using AMD-V in single step mode.
4325 *
4326 * @returns VBox status code.
4327 * @param pVM The cross context VM structure.
4328 * @param pVCpu The cross context virtual CPU structure.
4329 * @param pCtx Pointer to the guest-CPU context.
4330 * @param pcLoops Pointer to the number of executed loops.
4331 */
4332static int hmR0SvmRunGuestCodeStep(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t *pcLoops)
4333{
4334 uint32_t const cMaxResumeLoops = pVM->hm.s.cMaxResumeLoops;
4335 Assert(pcLoops);
4336 Assert(*pcLoops <= cMaxResumeLoops);
4337
4338 SVMTRANSIENT SvmTransient;
4339 SvmTransient.fUpdateTscOffsetting = true;
4340
4341 uint16_t uCsStart = pCtx->cs.Sel;
4342 uint64_t uRipStart = pCtx->rip;
4343
4344 int rc = VERR_INTERNAL_ERROR_5;
4345 for (;;)
4346 {
4347 Assert(!HMR0SuspendPending());
4348 AssertMsg(pVCpu->hm.s.idEnteredCpu == RTMpCpuId(),
4349 ("Illegal migration! Entered on CPU %u Current %u cLoops=%u\n", (unsigned)pVCpu->hm.s.idEnteredCpu,
4350 (unsigned)RTMpCpuId(), *pcLoops));
4351
4352 /* Preparatory work for running guest code, this may force us to return
4353 to ring-3. This bugger disables interrupts on VINF_SUCCESS! */
4354 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
4355 rc = hmR0SvmPreRunGuest(pVM, pVCpu, pCtx, &SvmTransient);
4356 if (rc != VINF_SUCCESS)
4357 break;
4358
4359 /*
4360 * No longjmps to ring-3 from this point on!!!
4361 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
4362 * This also disables flushing of the R0-logger instance (if any).
4363 */
4364 VMMRZCallRing3Disable(pVCpu);
4365 VMMRZCallRing3RemoveNotification(pVCpu);
4366 hmR0SvmPreRunGuestCommitted(pVM, pVCpu, pCtx, &SvmTransient);
4367
4368 rc = hmR0SvmRunGuest(pVM, pVCpu, pCtx);
4369
4370 /*
4371 * Restore any residual host-state and save any bits shared between host and guest into the guest-CPU state.
4372 * This will also re-enable longjmps to ring-3 when it has reached a safe point!!!
4373 */
4374 hmR0SvmPostRunGuest(pVM, pVCpu, pCtx, &SvmTransient, rc);
4375 if (RT_UNLIKELY( rc != VINF_SUCCESS /* Check for VMRUN errors. */
4376 || SvmTransient.u64ExitCode == SVM_EXIT_INVALID)) /* Check for invalid guest-state errors. */
4377 {
4378 if (rc == VINF_SUCCESS)
4379 rc = VERR_SVM_INVALID_GUEST_STATE;
4380 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
4381 hmR0SvmReportWorldSwitchError(pVM, pVCpu, rc, pCtx);
4382 return rc;
4383 }
4384
4385 /* Handle the #VMEXIT. */
4386 HMSVM_EXITCODE_STAM_COUNTER_INC(SvmTransient.u64ExitCode);
4387 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
4388 VBOXVMM_R0_HMSVM_VMEXIT(pVCpu, pCtx, SvmTransient.u64ExitCode, pVCpu->hm.s.svm.pVmcb);
4389 rc = hmR0SvmHandleExit(pVCpu, pCtx, &SvmTransient);
4390 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
4391 if (rc != VINF_SUCCESS)
4392 break;
4393 if (++(*pcLoops) >= cMaxResumeLoops)
4394 {
4395 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
4396 rc = VINF_EM_RAW_INTERRUPT;
4397 break;
4398 }
4399
4400 /*
4401 * Did the RIP change, if so, consider it a single step.
4402 * Otherwise, make sure one of the TFs gets set.
4403 */
4404 if ( pCtx->rip != uRipStart
4405 || pCtx->cs.Sel != uCsStart)
4406 {
4407 rc = VINF_EM_DBG_STEPPED;
4408 break;
4409 }
4410 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_DEBUG;
4411 }
4412
4413 /*
4414 * Clear the X86_EFL_TF if necessary.
4415 */
4416 if (pVCpu->hm.s.fClearTrapFlag)
4417 {
4418 pVCpu->hm.s.fClearTrapFlag = false;
4419 pCtx->eflags.Bits.u1TF = 0;
4420 }
4421
4422 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
4423 return rc;
4424}
4425
4426#ifdef VBOX_WITH_NESTED_HWVIRT
4427/**
4428 * Runs the nested-guest code using AMD-V.
4429 *
4430 * @returns VBox status code.
4431 * @param pVM The cross context VM structure.
4432 * @param pVCpu The cross context virtual CPU structure.
4433 * @param pCtx Pointer to the guest-CPU context.
4434 * @param pcLoops Pointer to the number of executed loops. If we're switching
4435 * from the guest-code execution loop to this nested-guest
4436 * execution loop pass the remainder value, else pass 0.
4437 */
4438static int hmR0SvmRunGuestCodeNested(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t *pcLoops)
4439{
4440 Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
4441 Assert(pcLoops);
4442 Assert(*pcLoops <= pVM->hm.s.cMaxResumeLoops);
4443
4444 SVMTRANSIENT SvmTransient;
4445 SvmTransient.fUpdateTscOffsetting = true;
4446
4447 int rc = VERR_INTERNAL_ERROR_4;
4448 for (;;)
4449 {
4450 Assert(!HMR0SuspendPending());
4451 HMSVM_ASSERT_CPU_SAFE();
4452
4453 /* Preparatory work for running nested-guest code, this may force us to return
4454 to ring-3. This bugger disables interrupts on VINF_SUCCESS! */
4455 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatEntry, x);
4456 rc = hmR0SvmPreRunGuestNested(pVM, pVCpu, pCtx, &SvmTransient);
4457 if (rc != VINF_SUCCESS)
4458 break;
4459
4460 /*
4461 * No longjmps to ring-3 from this point on!!!
4462 * Asserts() will still longjmp to ring-3 (but won't return), which is intentional, better than a kernel panic.
4463 * This also disables flushing of the R0-logger instance (if any).
4464 */
4465 hmR0SvmPreRunGuestCommittedNested(pVM, pVCpu, pCtx, &SvmTransient);
4466
4467 rc = hmR0SvmRunGuestNested(pVM, pVCpu, pCtx);
4468
4469 /* Restore any residual host-state and save any bits shared between host
4470 and guest into the guest-CPU state. Re-enables interrupts! */
4471 hmR0SvmPostRunGuestNested(pVM, pVCpu, pCtx, &SvmTransient, rc);
4472
4473 /** @todo This needs some work... we probably should cause a \#VMEXIT on
4474 * SVM_EXIT_INVALID and handle rc != VINF_SUCCESS differently. */
4475 if (RT_UNLIKELY( rc != VINF_SUCCESS /* Check for VMRUN errors. */
4476 || SvmTransient.u64ExitCode == SVM_EXIT_INVALID)) /* Check for invalid guest-state errors. */
4477 {
4478 if (rc == VINF_SUCCESS)
4479 rc = VERR_SVM_INVALID_GUEST_STATE;
4480 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit1, x);
4481 hmR0SvmReportWorldSwitchError(pVM, pVCpu, rc, pCtx);
4482 break;
4483 }
4484
4485 /* Handle the #VMEXIT. */
4486 HMSVM_EXITCODE_STAM_COUNTER_INC(SvmTransient.u64ExitCode);
4487 STAM_PROFILE_ADV_STOP_START(&pVCpu->hm.s.StatExit1, &pVCpu->hm.s.StatExit2, x);
4488 VBOXVMM_R0_HMSVM_VMEXIT(pVCpu, pCtx, SvmTransient.u64ExitCode, pVCpu->hm.s.svm.pVmcb);
4489 rc = hmR0SvmHandleExitNested(pVCpu, pCtx, &SvmTransient);
4490 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExit2, x);
4491 if (rc != VINF_SUCCESS)
4492 break;
4493 if (++(*pcLoops) >= pVM->hm.s.cMaxResumeLoops)
4494 {
4495 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchMaxResumeLoops);
4496 rc = VINF_EM_RAW_INTERRUPT;
4497 break;
4498 }
4499
4500 /** @todo handle single-stepping */
4501 }
4502
4503 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatEntry, x);
4504 return rc;
4505}
4506#endif
4507
4508
4509/**
4510 * Runs the guest code using AMD-V.
4511 *
4512 * @returns Strict VBox status code.
4513 * @param pVM The cross context VM structure.
4514 * @param pVCpu The cross context virtual CPU structure.
4515 * @param pCtx Pointer to the guest-CPU context.
4516 */
4517VMMR0DECL(VBOXSTRICTRC) SVMR0RunGuestCode(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
4518{
4519 Assert(VMMRZCallRing3IsEnabled(pVCpu));
4520 HMSVM_ASSERT_PREEMPT_SAFE();
4521 VMMRZCallRing3SetNotification(pVCpu, hmR0SvmCallRing3Callback, pCtx);
4522
4523 uint32_t cLoops = 0;
4524 int rc;
4525#ifdef VBOX_WITH_NESTED_HWVIRT
4526 if (!CPUMIsGuestInSvmNestedHwVirtMode(pCtx))
4527#endif
4528 {
4529 if (!pVCpu->hm.s.fSingleInstruction)
4530 rc = hmR0SvmRunGuestCodeNormal(pVM, pVCpu, pCtx, &cLoops);
4531 else
4532 rc = hmR0SvmRunGuestCodeStep(pVM, pVCpu, pCtx, &cLoops);
4533 }
4534#ifdef VBOX_WITH_NESTED_HWVIRT
4535 else
4536 {
4537 rc = VINF_SVM_VMRUN;
4538 }
4539
4540 /* Re-check the nested-guest condition here as we may be transitioning from the normal
4541 execution loop into the nested-guest, hence this is not placed in the 'else' part above. */
4542 if (rc == VINF_SVM_VMRUN)
4543 {
4544 rc = hmR0SvmRunGuestCodeNested(pVM, pVCpu, pCtx, &cLoops);
4545 if (rc == VINF_SVM_VMEXIT)
4546 rc = VINF_SUCCESS;
4547 }
4548#endif
4549
4550 /* Fixup error codes. */
4551 if (rc == VERR_EM_INTERPRETER)
4552 rc = VINF_EM_RAW_EMULATE_INSTR;
4553 else if (rc == VINF_EM_RESET)
4554 rc = VINF_EM_TRIPLE_FAULT;
4555
4556 /* Prepare to return to ring-3. This will remove longjmp notifications. */
4557 rc = hmR0SvmExitToRing3(pVM, pVCpu, pCtx, rc);
4558 Assert(!VMMRZCallRing3IsNotificationSet(pVCpu));
4559 return rc;
4560}
4561
4562
4563#ifdef VBOX_WITH_NESTED_HWVIRT
4564/**
4565 * Determines whether an IOIO intercept is active for the nested-guest or not.
4566 *
4567 * @param pvIoBitmap Pointer to the nested-guest IO bitmap.
4568 * @param pIoExitInfo Pointer to the SVMIOIOEXITINFO.
4569 */
4570static bool hmR0SvmIsIoInterceptActive(void *pvIoBitmap, PSVMIOIOEXITINFO pIoExitInfo)
4571{
4572 const uint16_t u16Port = pIoExitInfo->n.u16Port;
4573 const SVMIOIOTYPE enmIoType = (SVMIOIOTYPE)pIoExitInfo->n.u1Type;
4574 const uint8_t cbReg = (pIoExitInfo->u >> SVM_IOIO_OP_SIZE_SHIFT) & 7;
4575 const uint8_t cAddrSizeBits = (pIoExitInfo->u >> SVM_IOIO_ADDR_SIZE_SHIFT) << 4;
4576 const uint8_t iEffSeg = pIoExitInfo->n.u3SEG;
4577 const bool fRep = pIoExitInfo->n.u1REP;
4578 const bool fStrIo = pIoExitInfo->n.u1STR;
4579
4580 return HMSvmIsIOInterceptActive(pvIoBitmap, u16Port, enmIoType, cbReg, cAddrSizeBits, iEffSeg, fRep, fStrIo,
4581 NULL /* pIoExitInfo */);
4582}
4583
4584
4585/**
4586 * Handles a nested-guest \#VMEXIT (for all EXITCODE values except
4587 * SVM_EXIT_INVALID).
4588 *
4589 * @returns VBox status code (informational status codes included).
4590 * @param pVCpu The cross context virtual CPU structure.
4591 * @param pCtx Pointer to the guest-CPU context.
4592 * @param pSvmTransient Pointer to the SVM transient structure.
4593 */
4594static int hmR0SvmHandleExitNested(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
4595{
4596 Assert(pSvmTransient->u64ExitCode != SVM_EXIT_INVALID);
4597 Assert(pSvmTransient->u64ExitCode <= SVM_EXIT_MAX);
4598
4599#define HM_SVM_HANDLE_XCPT_EXIT_NESTED(a_uXcpt, a_XcptExitFn) \
4600 do \
4601 { \
4602 if (pVmcbNstGstCache->u32InterceptXcpt & RT_BIT(a_uXcpt)) \
4603 return hmR0SvmExecVmexit(pVCpu, pCtx); \
4604 return a_XcptExitFn(pVCpu, pCtx, pSvmTransient); \
4605 } while (0) \
4606
4607 /*
4608 * For all the #VMEXITs here we primarily figure out if the #VMEXIT is expected
4609 * by the nested-guest. If it isn't, it should be handled by the (outer) guest.
4610 */
4611 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
4612 PSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
4613 PSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
4614 switch (pSvmTransient->u64ExitCode)
4615 {
4616 case SVM_EXIT_CPUID:
4617 {
4618 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_CPUID)
4619 return hmR0SvmExecVmexit(pVCpu, pCtx);
4620 return hmR0SvmExitCpuid(pVCpu, pCtx, pSvmTransient);
4621 }
4622
4623 case SVM_EXIT_RDTSC:
4624 {
4625 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDTSC)
4626 return hmR0SvmExecVmexit(pVCpu, pCtx);
4627 return hmR0SvmExitRdtsc(pVCpu, pCtx, pSvmTransient);
4628 }
4629
4630 case SVM_EXIT_RDTSCP:
4631 {
4632 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDTSCP)
4633 return hmR0SvmExecVmexit(pVCpu, pCtx);
4634 return hmR0SvmExitRdtscp(pVCpu, pCtx, pSvmTransient);
4635 }
4636
4637
4638 case SVM_EXIT_MONITOR:
4639 {
4640 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_MONITOR)
4641 return hmR0SvmExecVmexit(pVCpu, pCtx);
4642 return hmR0SvmExitMonitor(pVCpu, pCtx, pSvmTransient);
4643 }
4644
4645 case SVM_EXIT_MWAIT:
4646 {
4647 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_MWAIT)
4648 return hmR0SvmExecVmexit(pVCpu, pCtx);
4649 return hmR0SvmExitMwait(pVCpu, pCtx, pSvmTransient);
4650 }
4651
4652 case SVM_EXIT_HLT:
4653 {
4654 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_HLT)
4655 return hmR0SvmExecVmexit(pVCpu, pCtx);
4656 return hmR0SvmExitHlt(pVCpu, pCtx, pSvmTransient);
4657 }
4658
4659 case SVM_EXIT_MSR:
4660 {
4661 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_MSR_PROT)
4662 {
4663 uint32_t const idMsr = pCtx->ecx;
4664 uint16_t offMsrpm;
4665 uint32_t uMsrpmBit;
4666 int rc = HMSvmGetMsrpmOffsetAndBit(idMsr, &offMsrpm, &uMsrpmBit);
4667 if (RT_SUCCESS(rc))
4668 {
4669 void const *pvMsrBitmap = pCtx->hwvirt.svm.CTX_SUFF(pvMsrBitmap);
4670 bool const fInterceptRead = ASMBitTest(pvMsrBitmap, (offMsrpm << 3) + uMsrpmBit);
4671 bool const fInterceptWrite = ASMBitTest(pvMsrBitmap, (offMsrpm << 3) + uMsrpmBit + 1);
4672
4673 if ( (fInterceptWrite && pVmcbNstGstCtrl->u64ExitInfo1 == SVM_EXIT1_MSR_WRITE)
4674 || (fInterceptRead && pVmcbNstGstCtrl->u64ExitInfo1 == SVM_EXIT1_MSR_READ))
4675 {
4676 return hmR0SvmExecVmexit(pVCpu, pCtx);
4677 }
4678 }
4679 else
4680 {
4681 /*
4682 * MSRs not covered by the MSRPM automatically cause an #VMEXIT.
4683 * See AMD-V spec. "15.11 MSR Intercepts".
4684 */
4685 Assert(rc == VERR_OUT_OF_RANGE);
4686 return hmR0SvmExecVmexit(pVCpu, pCtx);
4687 }
4688 }
4689 return hmR0SvmExitMsr(pVCpu, pCtx, pSvmTransient);
4690 }
4691
4692 case SVM_EXIT_IOIO:
4693 {
4694 /*
4695 * Figure out if the IO port access is intercepted by the nested-guest.
4696 */
4697 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_IOIO_PROT)
4698 {
4699 void *pvIoBitmap = pCtx->hwvirt.svm.CTX_SUFF(pvIoBitmap);
4700 SVMIOIOEXITINFO IoExitInfo;
4701 IoExitInfo.u = pVmcbNstGst->ctrl.u64ExitInfo1;
4702 bool const fIntercept = hmR0SvmIsIoInterceptActive(pvIoBitmap, &IoExitInfo);
4703 if (fIntercept)
4704 return hmR0SvmExecVmexit(pVCpu, pCtx);
4705 }
4706 return hmR0SvmExitIOInstr(pVCpu, pCtx, pSvmTransient);
4707 }
4708
4709 case SVM_EXIT_EXCEPTION_14: /* X86_XCPT_PF */
4710 {
4711 Assert(!pVmcbNstGstCtrl->NestedPaging.n.u1NestedPaging);
4712 if (pVmcbNstGstCache->u32InterceptXcpt & RT_BIT(X86_XCPT_PF))
4713 return hmR0SvmExecVmexit(pVCpu, pCtx);
4714
4715 /* If the nested-guest isn't for intercepting #PFs, simply forward the #PF to the guest. */
4716 uint32_t const u32ErrCode = pVmcbNstGstCtrl->u64ExitInfo1;
4717 RTGCUINTPTR const uFaultAddress = pVmcbNstGstCtrl->u64ExitInfo2;
4718 hmR0SvmSetPendingXcptPF(pVCpu, pCtx, u32ErrCode, uFaultAddress);
4719 return VINF_SUCCESS;
4720 }
4721
4722 case SVM_EXIT_EXCEPTION_7: /* X86_XCPT_NM */
4723 HM_SVM_HANDLE_XCPT_EXIT_NESTED(X86_XCPT_NM, hmR0SvmExitXcptNM);
4724
4725 case SVM_EXIT_EXCEPTION_6: /* X86_XCPT_UD */
4726 HM_SVM_HANDLE_XCPT_EXIT_NESTED(X86_XCPT_UD, hmR0SvmExitXcptUD);
4727
4728 case SVM_EXIT_EXCEPTION_16: /* X86_XCPT_MF */
4729 HM_SVM_HANDLE_XCPT_EXIT_NESTED(X86_XCPT_MF, hmR0SvmExitXcptMF);
4730
4731 case SVM_EXIT_EXCEPTION_1: /* X86_XCPT_DB */
4732 HM_SVM_HANDLE_XCPT_EXIT_NESTED(X86_XCPT_DB, hmR0SvmExitXcptDB);
4733
4734 case SVM_EXIT_EXCEPTION_17: /* X86_XCPT_AC */
4735 HM_SVM_HANDLE_XCPT_EXIT_NESTED(X86_XCPT_AC, hmR0SvmExitXcptAC);
4736
4737 case SVM_EXIT_EXCEPTION_3: /* X86_XCPT_BP */
4738 HM_SVM_HANDLE_XCPT_EXIT_NESTED(X86_XCPT_BP, hmR0SvmExitXcptBP);
4739
4740 case SVM_EXIT_READ_CR0:
4741 case SVM_EXIT_READ_CR3:
4742 case SVM_EXIT_READ_CR4:
4743 {
4744 if (pVmcbNstGstCache->u16InterceptRdCRx & (1U << (uint16_t)(pSvmTransient->u64ExitCode - SVM_EXIT_READ_CR0)))
4745 return hmR0SvmExecVmexit(pVCpu, pCtx);
4746 return hmR0SvmExitReadCRx(pVCpu, pCtx, pSvmTransient);
4747 }
4748
4749 case SVM_EXIT_WRITE_CR0:
4750 case SVM_EXIT_WRITE_CR3:
4751 case SVM_EXIT_WRITE_CR4:
4752 case SVM_EXIT_WRITE_CR8:
4753 {
4754 if (pVmcbNstGstCache->u16InterceptWrCRx & (1U << (uint16_t)(pSvmTransient->u64ExitCode - SVM_EXIT_WRITE_CR0)))
4755 return hmR0SvmExecVmexit(pVCpu, pCtx);
4756 return hmR0SvmExitWriteCRx(pVCpu, pCtx, pSvmTransient);
4757 }
4758
4759 case SVM_EXIT_PAUSE:
4760 {
4761 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_PAUSE)
4762 return hmR0SvmExecVmexit(pVCpu, pCtx);
4763 return hmR0SvmExitPause(pVCpu, pCtx, pSvmTransient);
4764 }
4765
4766 case SVM_EXIT_VINTR:
4767 {
4768 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_VINTR)
4769 return hmR0SvmExecVmexit(pVCpu, pCtx);
4770 return hmR0SvmNestedExitVIntr(pVCpu, pCtx, pSvmTransient);
4771 }
4772
4773 case SVM_EXIT_INTR:
4774 {
4775 /* We shouldn't direct physical interrupts to the nested-guest. */
4776 return hmR0SvmExitIntr(pVCpu, pCtx, pSvmTransient);
4777 }
4778
4779 case SVM_EXIT_FERR_FREEZE:
4780 {
4781 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_FERR_FREEZE)
4782 return hmR0SvmExecVmexit(pVCpu, pCtx);
4783 return hmR0SvmExitIntr(pVCpu, pCtx, pSvmTransient);
4784 }
4785
4786 case SVM_EXIT_NMI:
4787 {
4788 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_NMI)
4789 return hmR0SvmExecVmexit(pVCpu, pCtx);
4790 return hmR0SvmExitIntr(pVCpu, pCtx, pSvmTransient);
4791 }
4792
4793 case SVM_EXIT_INVLPG:
4794 {
4795 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_INVLPG)
4796 return hmR0SvmExecVmexit(pVCpu, pCtx);
4797 return hmR0SvmExitInvlpg(pVCpu, pCtx, pSvmTransient);
4798 }
4799
4800 case SVM_EXIT_WBINVD:
4801 {
4802 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_WBINVD)
4803 return hmR0SvmExecVmexit(pVCpu, pCtx);
4804 return hmR0SvmExitWbinvd(pVCpu, pCtx, pSvmTransient);
4805 }
4806
4807 case SVM_EXIT_INVD:
4808 {
4809 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_INVD)
4810 return hmR0SvmExecVmexit(pVCpu, pCtx);
4811 return hmR0SvmExitInvd(pVCpu, pCtx, pSvmTransient);
4812 }
4813
4814 case SVM_EXIT_RDPMC:
4815 {
4816 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_RDPMC)
4817 return hmR0SvmExecVmexit(pVCpu, pCtx);
4818 return hmR0SvmExitRdpmc(pVCpu, pCtx, pSvmTransient);
4819 }
4820
4821 default:
4822 {
4823 switch (pSvmTransient->u64ExitCode)
4824 {
4825 case SVM_EXIT_READ_DR0: case SVM_EXIT_READ_DR1: case SVM_EXIT_READ_DR2: case SVM_EXIT_READ_DR3:
4826 case SVM_EXIT_READ_DR6: case SVM_EXIT_READ_DR7: case SVM_EXIT_READ_DR8: case SVM_EXIT_READ_DR9:
4827 case SVM_EXIT_READ_DR10: case SVM_EXIT_READ_DR11: case SVM_EXIT_READ_DR12: case SVM_EXIT_READ_DR13:
4828 case SVM_EXIT_READ_DR14: case SVM_EXIT_READ_DR15:
4829 {
4830 if (pVmcbNstGstCache->u16InterceptRdDRx & (1U << (uint16_t)(pSvmTransient->u64ExitCode - SVM_EXIT_READ_DR0)))
4831 return hmR0SvmExecVmexit(pVCpu, pCtx);
4832 return hmR0SvmExitReadDRx(pVCpu, pCtx, pSvmTransient);
4833 }
4834
4835 case SVM_EXIT_WRITE_DR0: case SVM_EXIT_WRITE_DR1: case SVM_EXIT_WRITE_DR2: case SVM_EXIT_WRITE_DR3:
4836 case SVM_EXIT_WRITE_DR6: case SVM_EXIT_WRITE_DR7: case SVM_EXIT_WRITE_DR8: case SVM_EXIT_WRITE_DR9:
4837 case SVM_EXIT_WRITE_DR10: case SVM_EXIT_WRITE_DR11: case SVM_EXIT_WRITE_DR12: case SVM_EXIT_WRITE_DR13:
4838 case SVM_EXIT_WRITE_DR14: case SVM_EXIT_WRITE_DR15:
4839 {
4840 if (pVmcbNstGstCache->u16InterceptWrDRx & (1U << (uint16_t)(pSvmTransient->u64ExitCode - SVM_EXIT_WRITE_DR0)))
4841 return hmR0SvmExecVmexit(pVCpu, pCtx);
4842 return hmR0SvmExitWriteDRx(pVCpu, pCtx, pSvmTransient);
4843 }
4844
4845 /* The exceptions not handled here are already handled individually above (as they occur more frequently). */
4846 case SVM_EXIT_EXCEPTION_0: /*case SVM_EXIT_EXCEPTION_1:*/ case SVM_EXIT_EXCEPTION_2:
4847 /*case SVM_EXIT_EXCEPTION_3:*/ case SVM_EXIT_EXCEPTION_4: case SVM_EXIT_EXCEPTION_5:
4848 /*case SVM_EXIT_EXCEPTION_6:*/ /*case SVM_EXIT_EXCEPTION_7:*/ case SVM_EXIT_EXCEPTION_8:
4849 case SVM_EXIT_EXCEPTION_9: case SVM_EXIT_EXCEPTION_10: case SVM_EXIT_EXCEPTION_11:
4850 case SVM_EXIT_EXCEPTION_12: case SVM_EXIT_EXCEPTION_13: /*case SVM_EXIT_EXCEPTION_14:*/
4851 case SVM_EXIT_EXCEPTION_15: case SVM_EXIT_EXCEPTION_16: /*case SVM_EXIT_EXCEPTION_17:*/
4852 case SVM_EXIT_EXCEPTION_18: case SVM_EXIT_EXCEPTION_19: case SVM_EXIT_EXCEPTION_20:
4853 case SVM_EXIT_EXCEPTION_21: case SVM_EXIT_EXCEPTION_22: case SVM_EXIT_EXCEPTION_23:
4854 case SVM_EXIT_EXCEPTION_24: case SVM_EXIT_EXCEPTION_25: case SVM_EXIT_EXCEPTION_26:
4855 case SVM_EXIT_EXCEPTION_27: case SVM_EXIT_EXCEPTION_28: case SVM_EXIT_EXCEPTION_29:
4856 case SVM_EXIT_EXCEPTION_30: case SVM_EXIT_EXCEPTION_31:
4857 {
4858 if (pVmcbNstGstCache->u32InterceptXcpt & (1U << (uint32_t)(pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0)))
4859 return hmR0SvmExecVmexit(pVCpu, pCtx);
4860 /** @todo Write hmR0SvmExitXcptGeneric! */
4861 return VERR_NOT_IMPLEMENTED;
4862 }
4863
4864 case SVM_EXIT_XSETBV:
4865 {
4866 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_XSETBV)
4867 return hmR0SvmExecVmexit(pVCpu, pCtx);
4868 return hmR0SvmExitXsetbv(pVCpu, pCtx, pSvmTransient);
4869 }
4870
4871 case SVM_EXIT_TASK_SWITCH:
4872 {
4873 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_TASK_SWITCH)
4874 return hmR0SvmExecVmexit(pVCpu, pCtx);
4875 return hmR0SvmExitTaskSwitch(pVCpu, pCtx, pSvmTransient);
4876 }
4877
4878 case SVM_EXIT_IRET:
4879 {
4880 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_IRET)
4881 return hmR0SvmExecVmexit(pVCpu, pCtx);
4882 return hmR0SvmNestedExitIret(pVCpu, pCtx, pSvmTransient);
4883 }
4884
4885 case SVM_EXIT_SHUTDOWN:
4886 {
4887 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_SHUTDOWN)
4888 return hmR0SvmExecVmexit(pVCpu, pCtx);
4889 return hmR0SvmExitShutdown(pVCpu, pCtx, pSvmTransient);
4890 }
4891
4892 case SVM_EXIT_SMI:
4893 {
4894 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_SMI)
4895 return hmR0SvmExecVmexit(pVCpu, pCtx);
4896 return hmR0SvmExitUnexpected(pVCpu, pCtx, pSvmTransient);
4897 }
4898
4899 case SVM_EXIT_INIT:
4900 {
4901 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_INIT)
4902 return hmR0SvmExecVmexit(pVCpu, pCtx);
4903 return hmR0SvmExitUnexpected(pVCpu, pCtx, pSvmTransient);
4904 }
4905
4906 case SVM_EXIT_VMMCALL:
4907 {
4908 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMMCALL)
4909 hmR0SvmExecVmexit(pVCpu, pCtx);
4910 return hmR0SvmExitVmmCall(pVCpu, pCtx, pSvmTransient);
4911 }
4912
4913 case SVM_EXIT_CLGI:
4914 {
4915 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_CLGI)
4916 hmR0SvmExecVmexit(pVCpu, pCtx);
4917 return hmR0SvmExitClgi(pVCpu, pCtx, pSvmTransient);
4918 }
4919
4920 case SVM_EXIT_STGI:
4921 {
4922 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_STGI)
4923 hmR0SvmExecVmexit(pVCpu, pCtx);
4924 return hmR0SvmExitStgi(pVCpu, pCtx, pSvmTransient);
4925 }
4926
4927 case SVM_EXIT_VMLOAD:
4928 {
4929 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMLOAD)
4930 hmR0SvmExecVmexit(pVCpu, pCtx);
4931 return hmR0SvmExitVmload(pVCpu, pCtx, pSvmTransient);
4932 }
4933
4934 case SVM_EXIT_VMSAVE:
4935 {
4936 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMSAVE)
4937 hmR0SvmExecVmexit(pVCpu, pCtx);
4938 return hmR0SvmExitVmsave(pVCpu, pCtx, pSvmTransient);
4939 }
4940
4941 case SVM_EXIT_INVLPGA:
4942 {
4943 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_INVLPGA)
4944 hmR0SvmExecVmexit(pVCpu, pCtx);
4945 return hmR0SvmExitInvlpga(pVCpu, pCtx, pSvmTransient);
4946 }
4947
4948 case SVM_EXIT_VMRUN:
4949 {
4950 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN)
4951 hmR0SvmExecVmexit(pVCpu, pCtx);
4952 return hmR0SvmExitVmrun(pVCpu, pCtx, pSvmTransient);
4953 }
4954
4955 case SVM_EXIT_RSM:
4956 {
4957 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_RSM)
4958 hmR0SvmExecVmexit(pVCpu, pCtx);
4959 return hmR0SvmExitSetPendingXcptUD(pVCpu, pCtx, pSvmTransient);
4960 }
4961
4962 case SVM_EXIT_SKINIT:
4963 {
4964 if (pVmcbNstGstCache->u64InterceptCtrl & SVM_CTRL_INTERCEPT_SKINIT)
4965 hmR0SvmExecVmexit(pVCpu, pCtx);
4966 return hmR0SvmExitSetPendingXcptUD(pVCpu, pCtx, pSvmTransient);
4967 }
4968
4969 case SVM_EXIT_NPF:
4970 {
4971 /* We don't yet support nested-paging for nested-guests, so this should never really happen. */
4972 Assert(!pVmcbNstGstCtrl->NestedPaging.n.u1NestedPaging);
4973 return hmR0SvmExitUnexpected(pVCpu, pCtx, pSvmTransient);
4974 }
4975
4976 default:
4977 {
4978 AssertMsgFailed(("hmR0SvmHandleExitNested: Unknown exit code %#x\n", pSvmTransient->u64ExitCode));
4979 pVCpu->hm.s.u32HMError = pSvmTransient->u64ExitCode;
4980 return VERR_SVM_UNKNOWN_EXIT;
4981 }
4982 }
4983 }
4984 }
4985 /* not reached */
4986
4987#undef HM_SVM_HANDLE_XCPT_EXIT_NESTED
4988}
4989#endif
4990
4991
4992/**
4993 * Handles a guest \#VMEXIT (for all EXITCODE values except SVM_EXIT_INVALID).
4994 *
4995 * @returns VBox status code (informational status codes included).
4996 * @param pVCpu The cross context virtual CPU structure.
4997 * @param pCtx Pointer to the guest-CPU context.
4998 * @param pSvmTransient Pointer to the SVM transient structure.
4999 */
5000static int hmR0SvmHandleExit(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
5001{
5002 Assert(pSvmTransient->u64ExitCode != SVM_EXIT_INVALID);
5003 Assert(pSvmTransient->u64ExitCode <= SVM_EXIT_MAX);
5004
5005 /*
5006 * The ordering of the case labels is based on most-frequently-occurring #VMEXITs for most guests under
5007 * normal workloads (for some definition of "normal").
5008 */
5009 uint32_t u32ExitCode = pSvmTransient->u64ExitCode;
5010 switch (pSvmTransient->u64ExitCode)
5011 {
5012 case SVM_EXIT_NPF:
5013 return hmR0SvmExitNestedPF(pVCpu, pCtx, pSvmTransient);
5014
5015 case SVM_EXIT_IOIO:
5016 return hmR0SvmExitIOInstr(pVCpu, pCtx, pSvmTransient);
5017
5018 case SVM_EXIT_RDTSC:
5019 return hmR0SvmExitRdtsc(pVCpu, pCtx, pSvmTransient);
5020
5021 case SVM_EXIT_RDTSCP:
5022 return hmR0SvmExitRdtscp(pVCpu, pCtx, pSvmTransient);
5023
5024 case SVM_EXIT_CPUID:
5025 return hmR0SvmExitCpuid(pVCpu, pCtx, pSvmTransient);
5026
5027 case SVM_EXIT_EXCEPTION_14: /* X86_XCPT_PF */
5028 return hmR0SvmExitXcptPF(pVCpu, pCtx, pSvmTransient);
5029
5030 case SVM_EXIT_EXCEPTION_7: /* X86_XCPT_NM */
5031 return hmR0SvmExitXcptNM(pVCpu, pCtx, pSvmTransient);
5032
5033 case SVM_EXIT_EXCEPTION_6: /* X86_XCPT_UD */
5034 return hmR0SvmExitXcptUD(pVCpu, pCtx, pSvmTransient);
5035
5036 case SVM_EXIT_EXCEPTION_16: /* X86_XCPT_MF */
5037 return hmR0SvmExitXcptMF(pVCpu, pCtx, pSvmTransient);
5038
5039 case SVM_EXIT_EXCEPTION_1: /* X86_XCPT_DB */
5040 return hmR0SvmExitXcptDB(pVCpu, pCtx, pSvmTransient);
5041
5042 case SVM_EXIT_EXCEPTION_17: /* X86_XCPT_AC */
5043 return hmR0SvmExitXcptAC(pVCpu, pCtx, pSvmTransient);
5044
5045 case SVM_EXIT_EXCEPTION_3: /* X86_XCPT_BP */
5046 return hmR0SvmExitXcptBP(pVCpu, pCtx, pSvmTransient);
5047
5048 case SVM_EXIT_MONITOR:
5049 return hmR0SvmExitMonitor(pVCpu, pCtx, pSvmTransient);
5050
5051 case SVM_EXIT_MWAIT:
5052 return hmR0SvmExitMwait(pVCpu, pCtx, pSvmTransient);
5053
5054 case SVM_EXIT_HLT:
5055 return hmR0SvmExitHlt(pVCpu, pCtx, pSvmTransient);
5056
5057 case SVM_EXIT_READ_CR0:
5058 case SVM_EXIT_READ_CR3:
5059 case SVM_EXIT_READ_CR4:
5060 return hmR0SvmExitReadCRx(pVCpu, pCtx, pSvmTransient);
5061
5062 case SVM_EXIT_WRITE_CR0:
5063 case SVM_EXIT_WRITE_CR3:
5064 case SVM_EXIT_WRITE_CR4:
5065 case SVM_EXIT_WRITE_CR8:
5066 return hmR0SvmExitWriteCRx(pVCpu, pCtx, pSvmTransient);
5067
5068 case SVM_EXIT_PAUSE:
5069 return hmR0SvmExitPause(pVCpu, pCtx, pSvmTransient);
5070
5071 case SVM_EXIT_VMMCALL:
5072 return hmR0SvmExitVmmCall(pVCpu, pCtx, pSvmTransient);
5073
5074 case SVM_EXIT_VINTR:
5075 return hmR0SvmExitVIntr(pVCpu, pCtx, pSvmTransient);
5076
5077 case SVM_EXIT_INTR:
5078 case SVM_EXIT_FERR_FREEZE:
5079 case SVM_EXIT_NMI:
5080 return hmR0SvmExitIntr(pVCpu, pCtx, pSvmTransient);
5081
5082 case SVM_EXIT_MSR:
5083 return hmR0SvmExitMsr(pVCpu, pCtx, pSvmTransient);
5084
5085 case SVM_EXIT_INVLPG:
5086 return hmR0SvmExitInvlpg(pVCpu, pCtx, pSvmTransient);
5087
5088 case SVM_EXIT_WBINVD:
5089 return hmR0SvmExitWbinvd(pVCpu, pCtx, pSvmTransient);
5090
5091 case SVM_EXIT_INVD:
5092 return hmR0SvmExitInvd(pVCpu, pCtx, pSvmTransient);
5093
5094 case SVM_EXIT_RDPMC:
5095 return hmR0SvmExitRdpmc(pVCpu, pCtx, pSvmTransient);
5096
5097 default:
5098 {
5099 switch (pSvmTransient->u64ExitCode)
5100 {
5101 case SVM_EXIT_READ_DR0: case SVM_EXIT_READ_DR1: case SVM_EXIT_READ_DR2: case SVM_EXIT_READ_DR3:
5102 case SVM_EXIT_READ_DR6: case SVM_EXIT_READ_DR7: case SVM_EXIT_READ_DR8: case SVM_EXIT_READ_DR9:
5103 case SVM_EXIT_READ_DR10: case SVM_EXIT_READ_DR11: case SVM_EXIT_READ_DR12: case SVM_EXIT_READ_DR13:
5104 case SVM_EXIT_READ_DR14: case SVM_EXIT_READ_DR15:
5105 return hmR0SvmExitReadDRx(pVCpu, pCtx, pSvmTransient);
5106
5107 case SVM_EXIT_WRITE_DR0: case SVM_EXIT_WRITE_DR1: case SVM_EXIT_WRITE_DR2: case SVM_EXIT_WRITE_DR3:
5108 case SVM_EXIT_WRITE_DR6: case SVM_EXIT_WRITE_DR7: case SVM_EXIT_WRITE_DR8: case SVM_EXIT_WRITE_DR9:
5109 case SVM_EXIT_WRITE_DR10: case SVM_EXIT_WRITE_DR11: case SVM_EXIT_WRITE_DR12: case SVM_EXIT_WRITE_DR13:
5110 case SVM_EXIT_WRITE_DR14: case SVM_EXIT_WRITE_DR15:
5111 return hmR0SvmExitWriteDRx(pVCpu, pCtx, pSvmTransient);
5112
5113 case SVM_EXIT_XSETBV:
5114 return hmR0SvmExitXsetbv(pVCpu, pCtx, pSvmTransient);
5115
5116 case SVM_EXIT_TASK_SWITCH:
5117 return hmR0SvmExitTaskSwitch(pVCpu, pCtx, pSvmTransient);
5118
5119 case SVM_EXIT_IRET:
5120 return hmR0SvmExitIret(pVCpu, pCtx, pSvmTransient);
5121
5122 case SVM_EXIT_SHUTDOWN:
5123 return hmR0SvmExitShutdown(pVCpu, pCtx, pSvmTransient);
5124
5125 case SVM_EXIT_SMI:
5126 case SVM_EXIT_INIT:
5127 {
5128 /*
5129 * We don't intercept SMIs. As for INIT signals, it really shouldn't ever happen here.
5130 * If it ever does, we want to know about it so log the exit code and bail.
5131 */
5132 return hmR0SvmExitUnexpected(pVCpu, pCtx, pSvmTransient);
5133 }
5134
5135#ifdef VBOX_WITH_NESTED_HWVIRT
5136 case SVM_EXIT_CLGI: return hmR0SvmExitClgi(pVCpu, pCtx, pSvmTransient);
5137 case SVM_EXIT_STGI: return hmR0SvmExitStgi(pVCpu, pCtx, pSvmTransient);
5138 case SVM_EXIT_VMLOAD: return hmR0SvmExitVmload(pVCpu, pCtx, pSvmTransient);
5139 case SVM_EXIT_VMSAVE: return hmR0SvmExitVmsave(pVCpu, pCtx, pSvmTransient);
5140 case SVM_EXIT_INVLPGA: return hmR0SvmExitInvlpga(pVCpu, pCtx, pSvmTransient);
5141 case SVM_EXIT_VMRUN: return hmR0SvmExitVmrun(pVCpu, pCtx, pSvmTransient);
5142#else
5143 case SVM_EXIT_CLGI:
5144 case SVM_EXIT_STGI:
5145 case SVM_EXIT_VMLOAD:
5146 case SVM_EXIT_VMSAVE:
5147 case SVM_EXIT_INVLPGA:
5148 case SVM_EXIT_VMRUN:
5149#endif
5150 case SVM_EXIT_RSM:
5151 case SVM_EXIT_SKINIT:
5152 return hmR0SvmExitSetPendingXcptUD(pVCpu, pCtx, pSvmTransient);
5153
5154#ifdef HMSVM_ALWAYS_TRAP_ALL_XCPTS
5155 case SVM_EXIT_EXCEPTION_0: /* X86_XCPT_DE */
5156 /* SVM_EXIT_EXCEPTION_1: */ /* X86_XCPT_DB - Handled above. */
5157 case SVM_EXIT_EXCEPTION_2: /* X86_XCPT_NMI */
5158 /* SVM_EXIT_EXCEPTION_3: */ /* X86_XCPT_BP - Handled above. */
5159 case SVM_EXIT_EXCEPTION_4: /* X86_XCPT_OF */
5160 case SVM_EXIT_EXCEPTION_5: /* X86_XCPT_BR */
5161 /* SVM_EXIT_EXCEPTION_6: */ /* X86_XCPT_UD - Handled above. */
5162 /* SVM_EXIT_EXCEPTION_7: */ /* X86_XCPT_NM - Handled above. */
5163 case SVM_EXIT_EXCEPTION_8: /* X86_XCPT_DF */
5164 case SVM_EXIT_EXCEPTION_9: /* X86_XCPT_CO_SEG_OVERRUN */
5165 case SVM_EXIT_EXCEPTION_10: /* X86_XCPT_TS */
5166 case SVM_EXIT_EXCEPTION_11: /* X86_XCPT_NP */
5167 case SVM_EXIT_EXCEPTION_12: /* X86_XCPT_SS */
5168 case SVM_EXIT_EXCEPTION_13: /* X86_XCPT_GP */
5169 /* SVM_EXIT_EXCEPTION_14: */ /* X86_XCPT_PF - Handled above. */
5170 case SVM_EXIT_EXCEPTION_15: /* Reserved. */
5171 /* SVM_EXIT_EXCEPTION_16: */ /* X86_XCPT_MF - Handled above. */
5172 /* SVM_EXIT_EXCEPTION_17: */ /* X86_XCPT_AC - Handled above. */
5173 case SVM_EXIT_EXCEPTION_18: /* X86_XCPT_MC */
5174 case SVM_EXIT_EXCEPTION_19: /* X86_XCPT_XF */
5175 case SVM_EXIT_EXCEPTION_20: case SVM_EXIT_EXCEPTION_21: case SVM_EXIT_EXCEPTION_22:
5176 case SVM_EXIT_EXCEPTION_23: case SVM_EXIT_EXCEPTION_24: case SVM_EXIT_EXCEPTION_25:
5177 case SVM_EXIT_EXCEPTION_26: case SVM_EXIT_EXCEPTION_27: case SVM_EXIT_EXCEPTION_28:
5178 case SVM_EXIT_EXCEPTION_29: case SVM_EXIT_EXCEPTION_30: case SVM_EXIT_EXCEPTION_31:
5179 {
5180 /** @todo r=ramshankar; We should be doing
5181 * HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY here! */
5182
5183 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
5184 SVMEVENT Event;
5185 Event.u = 0;
5186 Event.n.u1Valid = 1;
5187 Event.n.u3Type = SVM_EVENT_EXCEPTION;
5188 Event.n.u8Vector = pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0;
5189
5190 switch (Event.n.u8Vector)
5191 {
5192 case X86_XCPT_DE:
5193 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDE);
5194 break;
5195
5196 case X86_XCPT_NP:
5197 Event.n.u1ErrorCodeValid = 1;
5198 Event.n.u32ErrorCode = pVmcb->ctrl.u64ExitInfo1;
5199 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNP);
5200 break;
5201
5202 case X86_XCPT_SS:
5203 Event.n.u1ErrorCodeValid = 1;
5204 Event.n.u32ErrorCode = pVmcb->ctrl.u64ExitInfo1;
5205 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestSS);
5206 break;
5207
5208 case X86_XCPT_GP:
5209 Event.n.u1ErrorCodeValid = 1;
5210 Event.n.u32ErrorCode = pVmcb->ctrl.u64ExitInfo1;
5211 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestGP);
5212 break;
5213
5214 default:
5215 AssertMsgFailed(("hmR0SvmHandleExit: Unexpected exit caused by exception %#x\n", Event.n.u8Vector));
5216 pVCpu->hm.s.u32HMError = Event.n.u8Vector;
5217 return VERR_SVM_UNEXPECTED_XCPT_EXIT;
5218 }
5219
5220 Log4(("#Xcpt: Vector=%#x at CS:RIP=%04x:%RGv\n", Event.n.u8Vector, pCtx->cs.Sel, (RTGCPTR)pCtx->rip));
5221 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
5222 return VINF_SUCCESS;
5223 }
5224#endif /* HMSVM_ALWAYS_TRAP_ALL_XCPTS */
5225
5226 default:
5227 {
5228 AssertMsgFailed(("hmR0SvmHandleExit: Unknown exit code %#x\n", u32ExitCode));
5229 pVCpu->hm.s.u32HMError = u32ExitCode;
5230 return VERR_SVM_UNKNOWN_EXIT;
5231 }
5232 }
5233 }
5234 }
5235 /* not reached */
5236}
5237
5238
5239#ifdef DEBUG
5240/* Is there some generic IPRT define for this that are not in Runtime/internal/\* ?? */
5241# define HMSVM_ASSERT_PREEMPT_CPUID_VAR() \
5242 RTCPUID const idAssertCpu = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId()
5243
5244# define HMSVM_ASSERT_PREEMPT_CPUID() \
5245 do \
5246 { \
5247 RTCPUID const idAssertCpuNow = RTThreadPreemptIsEnabled(NIL_RTTHREAD) ? NIL_RTCPUID : RTMpCpuId(); \
5248 AssertMsg(idAssertCpu == idAssertCpuNow, ("SVM %#x, %#x\n", idAssertCpu, idAssertCpuNow)); \
5249 } while (0)
5250
5251# define HMSVM_VALIDATE_EXIT_HANDLER_PARAMS() \
5252 do { \
5253 AssertPtr(pVCpu); \
5254 AssertPtr(pCtx); \
5255 AssertPtr(pSvmTransient); \
5256 Assert(ASMIntAreEnabled()); \
5257 HMSVM_ASSERT_PREEMPT_SAFE(); \
5258 HMSVM_ASSERT_PREEMPT_CPUID_VAR(); \
5259 Log4Func(("vcpu[%u] -v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-v-\n", (uint32_t)pVCpu->idCpu)); \
5260 HMSVM_ASSERT_PREEMPT_SAFE(); \
5261 if (VMMR0IsLogFlushDisabled(pVCpu)) \
5262 HMSVM_ASSERT_PREEMPT_CPUID(); \
5263 } while (0)
5264#else /* Release builds */
5265# define HMSVM_VALIDATE_EXIT_HANDLER_PARAMS() do { NOREF(pVCpu); NOREF(pCtx); NOREF(pSvmTransient); } while (0)
5266#endif
5267
5268
5269/**
5270 * Worker for hmR0SvmInterpretInvlpg().
5271 *
5272 * @return VBox status code.
5273 * @param pVCpu The cross context virtual CPU structure.
5274 * @param pCpu Pointer to the disassembler state.
5275 * @param pCtx The guest CPU context.
5276 */
5277static int hmR0SvmInterpretInvlPgEx(PVMCPU pVCpu, PDISCPUSTATE pCpu, PCPUMCTX pCtx)
5278{
5279 DISQPVPARAMVAL Param1;
5280 RTGCPTR GCPtrPage;
5281
5282 int rc = DISQueryParamVal(CPUMCTX2CORE(pCtx), pCpu, &pCpu->Param1, &Param1, DISQPVWHICH_SRC);
5283 if (RT_FAILURE(rc))
5284 return VERR_EM_INTERPRETER;
5285
5286 if ( Param1.type == DISQPV_TYPE_IMMEDIATE
5287 || Param1.type == DISQPV_TYPE_ADDRESS)
5288 {
5289 if (!(Param1.flags & (DISQPV_FLAG_32 | DISQPV_FLAG_64)))
5290 return VERR_EM_INTERPRETER;
5291
5292 GCPtrPage = Param1.val.val64;
5293 VBOXSTRICTRC rc2 = EMInterpretInvlpg(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx), GCPtrPage);
5294 rc = VBOXSTRICTRC_VAL(rc2);
5295 }
5296 else
5297 {
5298 Log4(("hmR0SvmInterpretInvlPgEx invalid parameter type %#x\n", Param1.type));
5299 rc = VERR_EM_INTERPRETER;
5300 }
5301
5302 return rc;
5303}
5304
5305
5306/**
5307 * Interprets INVLPG.
5308 *
5309 * @returns VBox status code.
5310 * @retval VINF_* Scheduling instructions.
5311 * @retval VERR_EM_INTERPRETER Something we can't cope with.
5312 * @retval VERR_* Fatal errors.
5313 *
5314 * @param pVM The cross context VM structure.
5315 * @param pVCpu The cross context virtual CPU structure.
5316 * @param pCtx The guest CPU context.
5317 *
5318 * @remarks Updates the RIP if the instruction was executed successfully.
5319 */
5320static int hmR0SvmInterpretInvlpg(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
5321{
5322 /* Only allow 32 & 64 bit code. */
5323 if (CPUMGetGuestCodeBits(pVCpu) != 16)
5324 {
5325 PDISSTATE pDis = &pVCpu->hm.s.DisState;
5326 int rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL /* pcbInstr */);
5327 if ( RT_SUCCESS(rc)
5328 && pDis->pCurInstr->uOpcode == OP_INVLPG)
5329 {
5330 rc = hmR0SvmInterpretInvlPgEx(pVCpu, pDis, pCtx);
5331 if (RT_SUCCESS(rc))
5332 pCtx->rip += pDis->cbInstr;
5333 return rc;
5334 }
5335 else
5336 Log4(("hmR0SvmInterpretInvlpg: EMInterpretDisasCurrent returned %Rrc uOpCode=%#x\n", rc, pDis->pCurInstr->uOpcode));
5337 }
5338 return VERR_EM_INTERPRETER;
5339}
5340
5341
5342#ifdef HMSVM_USE_IEM_EVENT_REFLECTION
5343/**
5344 * Gets the IEM exception flags for the specified SVM event.
5345 *
5346 * @returns The IEM exception flags.
5347 * @param pEvent Pointer to the SVM event.
5348 *
5349 * @remarks This function currently only constructs flags required for
5350 * IEMEvaluateRecursiveXcpt and not the complete flags (e.g. error-code
5351 * and CR2 aspects of an exception are not included).
5352 */
5353static uint32_t hmR0SvmGetIemXcptFlags(PCSVMEVENT pEvent)
5354{
5355 uint8_t const uEventType = pEvent->n.u3Type;
5356 uint32_t fIemXcptFlags;
5357 switch (uEventType)
5358 {
5359 case SVM_EVENT_EXCEPTION:
5360 /*
5361 * Only INT3 and INTO instructions can raise #BP and #OF exceptions.
5362 * See AMD spec. Table 8-1. "Interrupt Vector Source and Cause".
5363 */
5364 if (pEvent->n.u8Vector == X86_XCPT_BP)
5365 {
5366 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_BP_INSTR;
5367 break;
5368 }
5369 if (pEvent->n.u8Vector == X86_XCPT_OF)
5370 {
5371 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT | IEM_XCPT_FLAGS_OF_INSTR;
5372 break;
5373 }
5374 /** @todo How do we distinguish ICEBP \#DB from the regular one? */
5375 /* fall thru */
5376 case SVM_EVENT_NMI:
5377 fIemXcptFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
5378 break;
5379
5380 case SVM_EVENT_EXTERNAL_IRQ:
5381 fIemXcptFlags = IEM_XCPT_FLAGS_T_EXT_INT;
5382 break;
5383
5384 case SVM_EVENT_SOFTWARE_INT:
5385 fIemXcptFlags = IEM_XCPT_FLAGS_T_SOFT_INT;
5386 break;
5387
5388 default:
5389 fIemXcptFlags = 0;
5390 AssertMsgFailed(("Unexpected event type! uEventType=%#x uVector=%#x", uEventType, pEvent->n.u8Vector));
5391 break;
5392 }
5393 return fIemXcptFlags;
5394}
5395
5396#else
5397/**
5398 * Determines if an exception is a contributory exception.
5399 *
5400 * Contributory exceptions are ones which can cause double-faults unless the
5401 * original exception was a benign exception. Page-fault is intentionally not
5402 * included here as it's a conditional contributory exception.
5403 *
5404 * @returns true if the exception is contributory, false otherwise.
5405 * @param uVector The exception vector.
5406 */
5407DECLINLINE(bool) hmR0SvmIsContributoryXcpt(const uint32_t uVector)
5408{
5409 switch (uVector)
5410 {
5411 case X86_XCPT_GP:
5412 case X86_XCPT_SS:
5413 case X86_XCPT_NP:
5414 case X86_XCPT_TS:
5415 case X86_XCPT_DE:
5416 return true;
5417 default:
5418 break;
5419 }
5420 return false;
5421}
5422#endif /* HMSVM_USE_IEM_EVENT_REFLECTION */
5423
5424
5425/**
5426 * Handle a condition that occurred while delivering an event through the guest
5427 * IDT.
5428 *
5429 * @returns VBox status code (informational error codes included).
5430 * @retval VINF_SUCCESS if we should continue handling the \#VMEXIT.
5431 * @retval VINF_HM_DOUBLE_FAULT if a \#DF condition was detected and we ought to
5432 * continue execution of the guest which will delivery the \#DF.
5433 * @retval VINF_EM_RESET if we detected a triple-fault condition.
5434 * @retval VERR_EM_GUEST_CPU_HANG if we detected a guest CPU hang.
5435 *
5436 * @param pVCpu The cross context virtual CPU structure.
5437 * @param pCtx Pointer to the guest-CPU context.
5438 * @param pSvmTransient Pointer to the SVM transient structure.
5439 *
5440 * @remarks No-long-jump zone!!!
5441 */
5442static int hmR0SvmCheckExitDueToEventDelivery(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
5443{
5444 int rc = VINF_SUCCESS;
5445 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
5446
5447 Log4(("EXITINTINFO: Pending vectoring event %#RX64 Valid=%RTbool ErrValid=%RTbool Err=%#RX32 Type=%u Vector=%u\n",
5448 pVmcb->ctrl.ExitIntInfo.u, !!pVmcb->ctrl.ExitIntInfo.n.u1Valid, !!pVmcb->ctrl.ExitIntInfo.n.u1ErrorCodeValid,
5449 pVmcb->ctrl.ExitIntInfo.n.u32ErrorCode, pVmcb->ctrl.ExitIntInfo.n.u3Type, pVmcb->ctrl.ExitIntInfo.n.u8Vector));
5450
5451 /* See AMD spec. 15.7.3 "EXITINFO Pseudo-Code". The EXITINTINFO (if valid) contains the prior exception (IDT vector)
5452 * that was trying to be delivered to the guest which caused a #VMEXIT which was intercepted (Exit vector). */
5453 if (pVmcb->ctrl.ExitIntInfo.n.u1Valid)
5454 {
5455#ifdef HMSVM_USE_IEM_EVENT_REFLECTION
5456 IEMXCPTRAISE enmRaise;
5457 IEMXCPTRAISEINFO fRaiseInfo;
5458 bool const fExitIsHwXcpt = pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0 <= SVM_EXIT_EXCEPTION_31;
5459 uint8_t const uIdtVector = pVmcb->ctrl.ExitIntInfo.n.u8Vector;
5460 if (fExitIsHwXcpt)
5461 {
5462 uint8_t const uExitVector = pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0;
5463 uint32_t const fIdtVectorFlags = hmR0SvmGetIemXcptFlags(&pVmcb->ctrl.ExitIntInfo);
5464 uint32_t const fExitVectorFlags = IEM_XCPT_FLAGS_T_CPU_XCPT;
5465 enmRaise = IEMEvaluateRecursiveXcpt(pVCpu, fIdtVectorFlags, uIdtVector, fExitVectorFlags, uExitVector, &fRaiseInfo);
5466 }
5467 else
5468 {
5469 /*
5470 * If delivery of an event caused a #VMEXIT that is not an exception (e.g. #NPF) then we
5471 * end up here.
5472 *
5473 * If the event was:
5474 * - a software interrupt, we can re-execute the instruction which will regenerate
5475 * the event.
5476 * - an NMI, we need to clear NMI blocking and re-inject the NMI.
5477 * - a hardware exception or external interrupt, we re-inject it.
5478 */
5479 fRaiseInfo = IEMXCPTRAISEINFO_NONE;
5480 if (pVmcb->ctrl.ExitIntInfo.n.u3Type == SVM_EVENT_SOFTWARE_INT)
5481 enmRaise = IEMXCPTRAISE_REEXEC_INSTR;
5482 else
5483 enmRaise = IEMXCPTRAISE_PREV_EVENT;
5484 }
5485
5486 switch (enmRaise)
5487 {
5488 case IEMXCPTRAISE_CURRENT_XCPT:
5489 case IEMXCPTRAISE_PREV_EVENT:
5490 {
5491 /* For software interrupts, we shall re-execute the instruction. */
5492 if (!(fRaiseInfo & IEMXCPTRAISEINFO_SOFT_INT_XCPT))
5493 {
5494 RTGCUINTPTR GCPtrFaultAddress = 0;
5495
5496 /* If we are re-injecting an NMI, clear NMI blocking. */
5497 if (pVmcb->ctrl.ExitIntInfo.n.u3Type == SVM_EVENT_NMI)
5498 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
5499
5500 /* Determine a vectoring #PF condition, see comment in hmR0SvmExitXcptPF(). */
5501 if (fRaiseInfo & (IEMXCPTRAISEINFO_EXT_INT_PF | IEMXCPTRAISEINFO_NMI_PF))
5502 pSvmTransient->fVectoringPF = true;
5503 else if ( pVmcb->ctrl.ExitIntInfo.n.u3Type == SVM_EVENT_EXCEPTION
5504 && uIdtVector == X86_XCPT_PF)
5505 {
5506 /*
5507 * If the previous exception was a #PF, we need to recover the CR2 value.
5508 * This can't happen with shadow paging.
5509 */
5510 GCPtrFaultAddress = pCtx->cr2;
5511 }
5512
5513 /*
5514 * Without nested paging, when uExitVector is #PF, CR2 value will be updated from the VMCB's
5515 * exit info. fields, if it's a guest #PF, see hmR0SvmExitXcptPF().
5516 */
5517 Assert(pVmcb->ctrl.ExitIntInfo.n.u3Type != SVM_EVENT_SOFTWARE_INT);
5518 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5519 hmR0SvmSetPendingEvent(pVCpu, &pVmcb->ctrl.ExitIntInfo, GCPtrFaultAddress);
5520
5521 Log4(("IDT: Pending vectoring event %#RX64 ErrValid=%RTbool Err=%#RX32 GCPtrFaultAddress=%#RX64\n",
5522 pVmcb->ctrl.ExitIntInfo.u, RT_BOOL(pVmcb->ctrl.ExitIntInfo.n.u1ErrorCodeValid),
5523 pVmcb->ctrl.ExitIntInfo.n.u32ErrorCode, GCPtrFaultAddress));
5524 }
5525 break;
5526 }
5527
5528 case IEMXCPTRAISE_REEXEC_INSTR:
5529 {
5530 Assert(rc == VINF_SUCCESS);
5531 break;
5532 }
5533
5534 case IEMXCPTRAISE_DOUBLE_FAULT:
5535 {
5536 /*
5537 * Determing a vectoring double #PF condition. Used later, when PGM evaluates the
5538 * second #PF as a guest #PF (and not a shadow #PF) and needs to be converted into a #DF.
5539 */
5540 if (fRaiseInfo & IEMXCPTRAISEINFO_PF_PF)
5541 {
5542 pSvmTransient->fVectoringDoublePF = true;
5543 Assert(rc == VINF_SUCCESS);
5544 }
5545 else
5546 {
5547 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5548 hmR0SvmSetPendingXcptDF(pVCpu);
5549 rc = VINF_HM_DOUBLE_FAULT;
5550 }
5551 break;
5552 }
5553
5554 case IEMXCPTRAISE_TRIPLE_FAULT:
5555 {
5556 rc = VINF_EM_RESET;
5557 break;
5558 }
5559
5560 case IEMXCPTRAISE_CPU_HANG:
5561 {
5562 rc = VERR_EM_GUEST_CPU_HANG;
5563 break;
5564 }
5565
5566 default:
5567 {
5568 AssertMsgFailed(("hmR0SvmExitCpuid: EMInterpretCpuId failed with %Rrc\n", rc));
5569 rc = VERR_SVM_IPE_2;
5570 break;
5571 }
5572 }
5573#else
5574 uint8_t uIdtVector = pVmcb->ctrl.ExitIntInfo.n.u8Vector;
5575
5576 typedef enum
5577 {
5578 SVMREFLECTXCPT_XCPT, /* Reflect the exception to the guest or for further evaluation by VMM. */
5579 SVMREFLECTXCPT_DF, /* Reflect the exception as a double-fault to the guest. */
5580 SVMREFLECTXCPT_TF, /* Indicate a triple faulted state to the VMM. */
5581 SVMREFLECTXCPT_HANG, /* Indicate bad VM trying to deadlock the CPU. */
5582 SVMREFLECTXCPT_NONE /* Nothing to reflect. */
5583 } SVMREFLECTXCPT;
5584
5585 SVMREFLECTXCPT enmReflect = SVMREFLECTXCPT_NONE;
5586 bool fReflectingNmi = false;
5587 if (pVmcb->ctrl.ExitIntInfo.n.u3Type == SVM_EVENT_EXCEPTION)
5588 {
5589 if (pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0 <= SVM_EXIT_EXCEPTION_31)
5590 {
5591 uint8_t uExitVector = (uint8_t)(pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0);
5592
5593#ifdef VBOX_STRICT
5594 if ( hmR0SvmIsContributoryXcpt(uIdtVector)
5595 && uExitVector == X86_XCPT_PF)
5596 {
5597 Log4(("IDT: Contributory #PF idCpu=%u uCR2=%#RX64\n", pVCpu->idCpu, pCtx->cr2));
5598 }
5599#endif
5600
5601 if ( uIdtVector == X86_XCPT_BP
5602 || uIdtVector == X86_XCPT_OF)
5603 {
5604 /* Ignore INT3/INTO, just re-execute. See @bugref{8357}. */
5605 }
5606 else if ( uExitVector == X86_XCPT_PF
5607 && uIdtVector == X86_XCPT_PF)
5608 {
5609 pSvmTransient->fVectoringDoublePF = true;
5610 Log4(("IDT: Vectoring double #PF uCR2=%#RX64\n", pCtx->cr2));
5611 }
5612 else if ( uExitVector == X86_XCPT_AC
5613 && uIdtVector == X86_XCPT_AC)
5614 {
5615 enmReflect = SVMREFLECTXCPT_HANG;
5616 Log4(("IDT: Nested #AC - Bad guest\n"));
5617 }
5618 else if ( (pVmcb->ctrl.u32InterceptXcpt & HMSVM_CONTRIBUTORY_XCPT_MASK)
5619 && hmR0SvmIsContributoryXcpt(uExitVector)
5620 && ( hmR0SvmIsContributoryXcpt(uIdtVector)
5621 || uIdtVector == X86_XCPT_PF))
5622 {
5623 enmReflect = SVMREFLECTXCPT_DF;
5624 Log4(("IDT: Pending vectoring #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntInfo,
5625 uIdtVector, uExitVector));
5626 }
5627 else if (uIdtVector == X86_XCPT_DF)
5628 {
5629 enmReflect = SVMREFLECTXCPT_TF;
5630 Log4(("IDT: Pending vectoring triple-fault %#RX64 uIdtVector=%#x uExitVector=%#x\n",
5631 pVCpu->hm.s.Event.u64IntInfo, uIdtVector, uExitVector));
5632 }
5633 else
5634 enmReflect = SVMREFLECTXCPT_XCPT;
5635 }
5636 else
5637 {
5638 /*
5639 * If event delivery caused an #VMEXIT that is not an exception (e.g. #NPF) then reflect the original
5640 * exception to the guest after handling the #VMEXIT.
5641 */
5642 enmReflect = SVMREFLECTXCPT_XCPT;
5643 }
5644 }
5645 else if ( pVmcb->ctrl.ExitIntInfo.n.u3Type == SVM_EVENT_EXTERNAL_IRQ
5646 || pVmcb->ctrl.ExitIntInfo.n.u3Type == SVM_EVENT_NMI)
5647 {
5648 enmReflect = SVMREFLECTXCPT_XCPT;
5649 fReflectingNmi = RT_BOOL(pVmcb->ctrl.ExitIntInfo.n.u3Type == SVM_EVENT_NMI);
5650
5651 if (pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0 <= SVM_EXIT_EXCEPTION_31)
5652 {
5653 uint8_t uExitVector = (uint8_t)(pSvmTransient->u64ExitCode - SVM_EXIT_EXCEPTION_0);
5654 if (uExitVector == X86_XCPT_PF)
5655 {
5656 pSvmTransient->fVectoringPF = true;
5657 Log4(("IDT: Vectoring #PF due to Ext-Int/NMI. uCR2=%#RX64\n", pCtx->cr2));
5658 }
5659 }
5660 }
5661 /* else: Ignore software interrupts (INT n) as they reoccur when restarting the instruction. */
5662
5663 switch (enmReflect)
5664 {
5665 case SVMREFLECTXCPT_XCPT:
5666 {
5667 /* If we are re-injecting the NMI, clear NMI blocking. */
5668 if (fReflectingNmi)
5669 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
5670
5671 Assert(pVmcb->ctrl.ExitIntInfo.n.u3Type != SVM_EVENT_SOFTWARE_INT);
5672 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5673 hmR0SvmSetPendingEvent(pVCpu, &pVmcb->ctrl.ExitIntInfo, 0 /* GCPtrFaultAddress */);
5674
5675 /* If uExitVector is #PF, CR2 value will be updated from the VMCB if it's a guest #PF. See hmR0SvmExitXcptPF(). */
5676 Log4(("IDT: Pending vectoring event %#RX64 ErrValid=%RTbool Err=%#RX32\n", pVmcb->ctrl.ExitIntInfo.u,
5677 !!pVmcb->ctrl.ExitIntInfo.n.u1ErrorCodeValid, pVmcb->ctrl.ExitIntInfo.n.u32ErrorCode));
5678 break;
5679 }
5680
5681 case SVMREFLECTXCPT_DF:
5682 {
5683 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingReflect);
5684 hmR0SvmSetPendingXcptDF(pVCpu);
5685 rc = VINF_HM_DOUBLE_FAULT;
5686 break;
5687 }
5688
5689 case SVMREFLECTXCPT_TF:
5690 {
5691 rc = VINF_EM_RESET;
5692 break;
5693 }
5694
5695 case SVMREFLECTXCPT_HANG:
5696 {
5697 rc = VERR_EM_GUEST_CPU_HANG;
5698 break;
5699 }
5700
5701 default:
5702 Assert(rc == VINF_SUCCESS);
5703 break;
5704 }
5705#endif /* HMSVM_USE_IEM_EVENT_REFLECTION */
5706 }
5707 Assert(rc == VINF_SUCCESS || rc == VINF_HM_DOUBLE_FAULT || rc == VINF_EM_RESET || rc == VERR_EM_GUEST_CPU_HANG);
5708 NOREF(pCtx);
5709 return rc;
5710}
5711
5712
5713/**
5714 * Updates interrupt shadow for the current RIP.
5715 */
5716#define HMSVM_UPDATE_INTR_SHADOW(pVCpu, pCtx) \
5717 do { \
5718 /* Update interrupt shadow. */ \
5719 if ( VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS) \
5720 && pCtx->rip != EMGetInhibitInterruptsPC(pVCpu)) \
5721 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS); \
5722 } while (0)
5723
5724
5725/**
5726 * Advances the guest RIP making use of the CPU's NRIP_SAVE feature if
5727 * supported, otherwise advances the RIP by the number of bytes specified in
5728 * @a cb.
5729 *
5730 * @param pVCpu The cross context virtual CPU structure.
5731 * @param pCtx Pointer to the guest-CPU context.
5732 * @param cb RIP increment value in bytes.
5733 *
5734 * @remarks Use this function only from \#VMEXIT's where the NRIP value is valid
5735 * when NRIP_SAVE is supported by the CPU, otherwise use
5736 * hmR0SvmAdvanceRipDumb!
5737 */
5738DECLINLINE(void) hmR0SvmAdvanceRipHwAssist(PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t cb)
5739{
5740 if (pVCpu->CTX_SUFF(pVM)->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
5741 {
5742 PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
5743 Assert(pVmcb->ctrl.u64NextRIP);
5744 AssertRelease(pVmcb->ctrl.u64NextRIP - pCtx->rip == cb); /* temporary, remove later */
5745 pCtx->rip = pVmcb->ctrl.u64NextRIP;
5746 }
5747 else
5748 pCtx->rip += cb;
5749
5750 HMSVM_UPDATE_INTR_SHADOW(pVCpu, pCtx);
5751}
5752
5753
5754#ifdef VBOX_WITH_NESTED_HWVIRT
5755/**
5756 * Gets the length of the current instruction if the CPU supports the NRIP_SAVE
5757 * feature. Otherwise, returns the value in @a cbLikely.
5758 *
5759 * @param pVCpu The cross context virtual CPU structure.
5760 * @param pCtx Pointer to the guest-CPU context.
5761 * @param cbLikely The likely instruction length.
5762 */
5763DECLINLINE(uint8_t) hmR0SvmGetInstrLengthHwAssist(PVMCPU pVCpu, PCPUMCTX pCtx, uint8_t cbLikely)
5764{
5765 Assert(cbLikely <= 15); /* See Intel spec. 2.3.11 "AVX Instruction Length" */
5766 if (pVCpu->CTX_SUFF(pVM)->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
5767 {
5768 PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
5769 uint8_t const cbInstr = pVmcb->ctrl.u64NextRIP - pCtx->rip;
5770 Assert(cbInstr == cbLikely);
5771 return cbInstr;
5772 }
5773 return cbLikely;
5774}
5775#endif
5776
5777
5778/**
5779 * Advances the guest RIP by the number of bytes specified in @a cb. This does
5780 * not make use of any hardware features to determine the instruction length.
5781 *
5782 * @param pVCpu The cross context virtual CPU structure.
5783 * @param pCtx Pointer to the guest-CPU context.
5784 * @param cb RIP increment value in bytes.
5785 */
5786DECLINLINE(void) hmR0SvmAdvanceRipDumb(PVMCPU pVCpu, PCPUMCTX pCtx, uint32_t cb)
5787{
5788 pCtx->rip += cb;
5789 HMSVM_UPDATE_INTR_SHADOW(pVCpu, pCtx);
5790}
5791#undef HMSVM_UPDATE_INTR_SHADOW
5792
5793
5794#if defined(VBOX_WITH_NESTED_HWVIRT) && !defined(VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM)
5795/**
5796 * Performs an SVM world-switch (VMRUN, \#VMEXIT) updating PGM and HM internals.
5797 *
5798 * @returns VBox status code.
5799 * @param pVCpu The cross context virtual CPU structure.
5800 * @param pCtx The guest-CPU context.
5801 */
5802static int hmR0SvmNstGstWorldSwitch(PVMCPU pVCpu, PCPUMCTX pCtx)
5803{
5804 /** @todo What about informing PGM about CR0.WP? */
5805 PGMFlushTLB(pVCpu, pCtx->cr3, true /* fGlobal */);
5806
5807 /* Inform CPUM (recompiler), can later be removed. */
5808 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_ALL);
5809
5810 /*
5811 * Inform PGM about paging mode changes.
5812 * We include X86_CR0_PE because PGM doesn't handle paged-real mode yet.
5813 */
5814 return PGMChangeMode(pVCpu, pCtx->cr0 | X86_CR0_PE, pCtx->cr4, pCtx->msrEFER);
5815}
5816
5817
5818/**
5819 * Performs a \#VMEXIT when the VMRUN was emulating using hmR0SvmExecVmrun and
5820 * optionally went ahead with hardware-assisted SVM execution.
5821 *
5822 * @returns VBox status code.
5823 * @param pVCpu The cross context virtual CPU structure.
5824 * @param pCtx Pointer to the guest-CPU context.
5825 */
5826static int hmR0SvmExecVmexit(PVMCPU pVCpu, PCPUMCTX pCtx)
5827{
5828 /*
5829 * Restore the modifications we did to the nested-guest VMCB in order
5830 * to executing the nested-guesting using hardware-assisted SVM.
5831 */
5832 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
5833 HMSvmNstGstVmExitNotify(pVCpu, pVmcbNstGst);
5834
5835 Log4(("hmR0SvmExecVmexit: uExitCode=%#RX64 uExitInfo1=%#RX64 uExitInfo2=%#RX64\n", pVmcbNstGst->ctrl.u64ExitCode,
5836 pVmcbNstGst->ctrl.u64ExitInfo1, pVmcbNstGst->ctrl.u64ExitInfo2));
5837
5838 /*
5839 * Write the nested-guest VMCB back to guest memory.
5840 */
5841 RTGCPHYS const GCPhysVmcb = pCtx->hwvirt.svm.GCPhysVmcb;
5842 int rc = PGMPhysSimpleWriteGCPhys(pVCpu->CTX_SUFF(pVM), GCPhysVmcb, pVmcbNstGst, sizeof(*pVmcbNstGst));
5843
5844 /*
5845 * Clear our cache of the nested-guest VMCB controls.
5846 */
5847 PSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
5848 memset(pVmcbNstGstCtrl, 0, sizeof(*pVmcbNstGstCtrl));
5849 Assert(!CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
5850
5851 /*
5852 * Disable the global interrupt flag to not cause any interrupts or NMIs
5853 * in the guest.
5854 */
5855 pCtx->hwvirt.svm.fGif = 0;
5856
5857 /*
5858 * Restore the guest's "host" state.
5859 */
5860 CPUMSvmVmExitRestoreHostState(pCtx);
5861
5862 /*
5863 * Restore the guest's force-flags.
5864 */
5865 if (pCtx->hwvirt.fLocalForcedActions)
5866 {
5867 VMCPU_FF_SET(pVCpu, pCtx->hwvirt.fLocalForcedActions);
5868 pCtx->hwvirt.fLocalForcedActions = 0;
5869 }
5870
5871 /*
5872 * Make sure if VMRUN happens outside this SVM R0 code, we don't skip setting
5873 * things up that are required for executing the nested-guest using hardware-assisted SVM.
5874 */
5875 pVCpu->hm.s.svm.NstGstVmcbCache.fVmrunEmulatedInR0 = false;
5876 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
5877
5878 if (RT_SUCCESS(rc))
5879 {
5880 rc = hmR0SvmNstGstWorldSwitch(pVCpu, pCtx);
5881 if (rc == VINF_SUCCESS)
5882 rc = VINF_SVM_VMEXIT;
5883
5884 Log4(("hmR0SvmExecVmexit: #VMEXIT success! rc=%d\n", rc));
5885 }
5886 else
5887 Log(("hmR0SvmExecVmexit: Failed to write guest-VMCB at %#RGp, rc=%d\n", GCPhysVmcb, rc));
5888
5889 return rc;
5890}
5891
5892
5893/**
5894 * Setup the nested-guest for hardware-assisted SVM execution.
5895 *
5896 * @returns VBox status code.
5897 * @param pVCpu The cross context virtual CPU structure.
5898 * @param pCtx Pointer to the guest-CPU context.
5899 * @param GCPhysVmcb The nested-guest physical address of its VMCB.
5900 * @param cbInstr Length of the VMRUN instruction in bytes.
5901 */
5902static int hmR0SvmExecVmrun(PVMCPU pVCpu, PCPUMCTX pCtx, RTGCPHYS GCPhysVmcb, uint8_t cbInstr)
5903{
5904 Assert(CPUMGetGuestCPL(pVCpu) == 0);
5905 Assert(!pVCpu->hm.s.svm.NstGstVmcbCache.fVmrunEmulatedInR0);
5906
5907 /*
5908 * Cache the physical address of the VMCB for #VMEXIT exceptions.
5909 */
5910 pCtx->hwvirt.svm.GCPhysVmcb = GCPhysVmcb;
5911
5912 /*
5913 * Save the "host" (guest-state) so that when we do a #VMEXIT we can restore the guest-state.
5914 *
5915 * The real host-state shall be saved/restored by the physical CPU once it executes VMRUN
5916 * with the nested-guest VMCB.
5917 */
5918 CPUMSvmVmRunSaveHostState(pCtx, cbInstr);
5919
5920 /*
5921 * Read the nested-guest VMCB state.
5922 */
5923 PVM pVM = pVCpu->CTX_SUFF(pVM);
5924 int rc = PGMPhysSimpleReadGCPhys(pVM, pCtx->hwvirt.svm.CTX_SUFF(pVmcb), GCPhysVmcb, sizeof(SVMVMCB));
5925 if (RT_SUCCESS(rc))
5926 {
5927 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
5928 PSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
5929 PSVMVMCBSTATESAVE pVmcbNstGstState = &pVmcbNstGst->guest;
5930
5931 /*
5932 * Validate nested-guest state and controls.
5933 * The rest shall be done by the physical CPU.
5934 */
5935 /* VMRUN must always be intercepted. */
5936 if (!CPUMIsGuestSvmCtrlInterceptSet(pCtx, SVM_CTRL_INTERCEPT_VMRUN))
5937 {
5938 Log(("hmR0SvmExecVmrun: VMRUN instruction not intercepted -> #VMEXIT\n"));
5939 pVmcbNstGstCtrl->u64ExitCode = SVM_EXIT_INVALID;
5940 return hmR0SvmExecVmexit(pVCpu, pCtx);
5941 }
5942
5943 /* Nested paging. */
5944 if ( pVmcbNstGstCtrl->NestedPaging.n.u1NestedPaging
5945 && !pVM->cpum.ro.GuestFeatures.fSvmNestedPaging)
5946 {
5947 Log(("hmR0SvmExecVmrun: Nested paging not supported -> #VMEXIT\n"));
5948 pVmcbNstGstCtrl->u64ExitCode = SVM_EXIT_INVALID;
5949 return hmR0SvmExecVmexit(pVCpu, pCtx);
5950 }
5951 /** @todo When implementing nested-paging for the nested-guest don't forget to
5952 * adjust/check PAT MSR. */
5953
5954 /* AVIC. */
5955 if ( pVmcbNstGstCtrl->IntCtrl.n.u1AvicEnable
5956 && !pVM->cpum.ro.GuestFeatures.fSvmAvic)
5957 {
5958 Log(("hmR0SvmExecVmrun: AVIC not supported -> #VMEXIT\n"));
5959 pVmcbNstGstCtrl->u64ExitCode = SVM_EXIT_INVALID;
5960 return hmR0SvmExecVmexit(pVCpu, pCtx);
5961 }
5962
5963 /* Last branch record (LBR) virtualization. */
5964 if ( (pVmcbNstGstCtrl->u64LBRVirt & SVM_LBR_VIRT_ENABLE)
5965 && !pVM->cpum.ro.GuestFeatures.fSvmLbrVirt)
5966 {
5967 Log(("hmR0SvmExecVmrun: LBR virtualization not supported -> #VMEXIT\n"));
5968 pVmcbNstGstCtrl->u64ExitCode = SVM_EXIT_INVALID;
5969 return hmR0SvmExecVmexit(pVCpu, pCtx);
5970 }
5971
5972 /*
5973 * MSR permission bitmap (MSRPM).
5974 */
5975 RTGCPHYS const GCPhysMsrBitmap = pVmcbNstGstCtrl->u64MSRPMPhysAddr;
5976 Assert(pCtx->hwvirt.svm.CTX_SUFF(pvMsrBitmap));
5977 rc = PGMPhysSimpleReadGCPhys(pVM, pCtx->hwvirt.svm.CTX_SUFF(pvMsrBitmap), GCPhysMsrBitmap,
5978 SVM_MSRPM_PAGES * X86_PAGE_4K_SIZE);
5979 if (RT_FAILURE(rc))
5980 {
5981 Log(("hmR0SvmExecVmrun: Failed reading the MSR permission bitmap at %#RGp. rc=%Rrc\n", GCPhysMsrBitmap, rc));
5982 pVmcbNstGstCtrl->u64ExitCode = SVM_EXIT_INVALID;
5983 return hmR0SvmExecVmexit(pVCpu, pCtx);
5984 }
5985
5986 /*
5987 * IO permission bitmap (IOPM).
5988 */
5989 RTGCPHYS const GCPhysIOBitmap = pVmcbNstGstCtrl->u64MSRPMPhysAddr;
5990 rc = PGMPhysSimpleReadGCPhys(pVM, pCtx->hwvirt.svm.CTX_SUFF(pvIoBitmap), GCPhysIOBitmap,
5991 SVM_IOPM_PAGES * X86_PAGE_4K_SIZE);
5992 if (RT_FAILURE(rc))
5993 {
5994 Log(("hmR0SvmExecVmrun: Failed reading the IO permission bitmap at %#RGp. rc=%Rrc\n", GCPhysIOBitmap, rc));
5995 pVmcbNstGstCtrl->u64ExitCode = SVM_EXIT_INVALID;
5996 return hmR0SvmExecVmexit(pVCpu, pCtx);
5997 }
5998
5999 /*
6000 * EFER MSR.
6001 */
6002 uint64_t uValidEfer;
6003 rc = CPUMQueryValidatedGuestEfer(pVM, pVmcbNstGstState->u64CR0, pVmcbNstGstState->u64EFER, pVmcbNstGstState->u64EFER,
6004 &uValidEfer);
6005 if (RT_FAILURE(rc))
6006 {
6007 Log(("hmR0SvmExecVmrun: EFER invalid uOldEfer=%#RX64 -> #VMEXIT\n", pVmcbNstGstState->u64EFER));
6008 pVmcbNstGstCtrl->u64ExitCode = SVM_EXIT_INVALID;
6009 return hmR0SvmExecVmexit(pVCpu, pCtx);
6010 }
6011 bool const fLongModeEnabled = RT_BOOL(uValidEfer & MSR_K6_EFER_LME);
6012 bool const fPaging = RT_BOOL(pVmcbNstGstState->u64CR0 & X86_CR0_PG);
6013 bool const fLongModeWithPaging = fLongModeEnabled && fPaging;
6014 /* Adjust EFER.LMA (this is normally done by the CPU when system software writes CR0) and update it. */
6015 if (fLongModeWithPaging)
6016 uValidEfer |= MSR_K6_EFER_LMA;
6017
6018 /*
6019 * Check for pending virtual interrupts.
6020 */
6021 if (pVmcbNstGstCtrl->IntCtrl.n.u1VIrqPending)
6022 VMCPU_FF_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
6023 else
6024 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST));
6025
6026 /*
6027 * Preserve the required force-flags.
6028 *
6029 * We only preserve the force-flags that would affect the execution of the
6030 * nested-guest (or the guest).
6031 *
6032 * - VMCPU_FF_INHIBIT_INTERRUPTS need -not- be preserved as it's for a single
6033 * instruction which is this VMRUN instruction itself.
6034 *
6035 * - VMCPU_FF_BLOCK_NMIS needs to be preserved as it blocks NMI until the
6036 * execution of a subsequent IRET instruction in the guest.
6037 *
6038 * - The remaining FFs (e.g. timers) can stay in place so that we will be
6039 * able to generate interrupts that should cause #VMEXITs for the
6040 * nested-guest.
6041 */
6042 pCtx->hwvirt.fLocalForcedActions = pVCpu->fLocalForcedActions & VMCPU_FF_BLOCK_NMIS;
6043
6044 /*
6045 * Interrupt shadow.
6046 */
6047 if (pVmcbNstGstCtrl->u64IntShadow & SVM_INTERRUPT_SHADOW_ACTIVE)
6048 {
6049 LogFlow(("hmR0SvmExecVmrun: setting interrupt shadow. inhibit PC=%#RX64\n", pVmcbNstGstState->u64RIP));
6050 /** @todo will this cause trouble if the nested-guest is 64-bit but the guest is 32-bit? */
6051 EMSetInhibitInterruptsPC(pVCpu, pVmcbNstGstState->u64RIP);
6052 }
6053
6054 /*
6055 * Load the guest-CPU state.
6056 * Skip CPL adjustments (will be done by the hardware).
6057 */
6058 HMSVM_SEG_REG_COPY_FROM_VMCB(pCtx, pVmcbNstGstState, ES, es);
6059 HMSVM_SEG_REG_COPY_FROM_VMCB(pCtx, pVmcbNstGstState, CS, cs);
6060 HMSVM_SEG_REG_COPY_FROM_VMCB(pCtx, pVmcbNstGstState, SS, ss);
6061 HMSVM_SEG_REG_COPY_FROM_VMCB(pCtx, pVmcbNstGstState, DS, ds);
6062 pCtx->gdtr.cbGdt = pVmcbNstGstState->GDTR.u32Limit;
6063 pCtx->gdtr.pGdt = pVmcbNstGstState->GDTR.u64Base;
6064 pCtx->idtr.cbIdt = pVmcbNstGstState->IDTR.u32Limit;
6065 pCtx->idtr.pIdt = pVmcbNstGstState->IDTR.u64Base;
6066 pCtx->cr0 = pVmcbNstGstState->u64CR0;
6067 pCtx->cr4 = pVmcbNstGstState->u64CR4;
6068 pCtx->cr3 = pVmcbNstGstState->u64CR3;
6069 pCtx->cr2 = pVmcbNstGstState->u64CR2;
6070 pCtx->dr[6] = pVmcbNstGstState->u64DR6;
6071 pCtx->dr[7] = pVmcbNstGstState->u64DR7;
6072 pCtx->rflags.u64 = pVmcbNstGstState->u64RFlags;
6073 pCtx->rax = pVmcbNstGstState->u64RAX;
6074 pCtx->rsp = pVmcbNstGstState->u64RSP;
6075 pCtx->rip = pVmcbNstGstState->u64RIP;
6076 pCtx->msrEFER = uValidEfer;
6077
6078 /* Mask DR6, DR7 bits mandatory set/clear bits. */
6079 pCtx->dr[6] &= ~(X86_DR6_RAZ_MASK | X86_DR6_MBZ_MASK);
6080 pCtx->dr[6] |= X86_DR6_RA1_MASK;
6081 pCtx->dr[7] &= ~(X86_DR7_RAZ_MASK | X86_DR7_MBZ_MASK);
6082 pCtx->dr[7] |= X86_DR7_RA1_MASK;
6083
6084 /*
6085 * Set up the nested-guest for executing it using hardware-assisted SVM.
6086 */
6087 hmR0SvmVmRunSetupVmcb(pVCpu, pCtx);
6088
6089 /*
6090 * VMRUN loads a subset of the guest-CPU state (see above) and nothing else. Ensure
6091 * hmR0SvmLoadGuestStateNested doesn't need to load anything back to the VMCB cache
6092 * as we go straight into executing the nested-guest.
6093 *
6094 * If we fall back to ring-3 we would have to re-load things from the guest-CPU
6095 * state into the VMCB as we are unsure what state we're in (e.g., VMRUN ends up
6096 * getting executed in IEM along with a handful of nested-guest instructions and
6097 * we have to continue executing the nested-guest in R0 since IEM doesn't know
6098 * about this VMCB cache which is in HM).
6099 */
6100 PSVMNESTEDVMCBCACHE pNstGstVmcbCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
6101 pNstGstVmcbCache->fVmrunEmulatedInR0 = true;
6102
6103 /*
6104 * We flag a CR3 change to ensure loading the host-physical address of CR3 into
6105 * the nested-guest VMCB in hmR0SvmLoadGuestControlRegsNested.
6106 */
6107 HMCPU_CF_CLEAR(pVCpu, HM_CHANGED_ALL_GUEST);
6108 HMCPU_CF_SET(pVCpu, HM_CHANGED_HOST_GUEST_SHARED_STATE | HM_CHANGED_GUEST_CR3);
6109
6110 /*
6111 * Clear global interrupt flags to allow interrupts and NMIs in the guest.
6112 */
6113 pCtx->hwvirt.svm.fGif = 1;
6114
6115 Log4(("hmR0SvmExecVmrun: CR0=%#RX32 CR3=%#RX64 CR4=%#RX32\n", pCtx->cr0, pCtx->cr3, pCtx->cr4));
6116 return hmR0SvmNstGstWorldSwitch(pVCpu, pCtx);
6117 }
6118
6119 return rc;
6120}
6121#endif /* VBOX_WITH_NESTED_HWVIRT && !VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM */
6122
6123
6124/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
6125/* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #VMEXIT handlers -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- */
6126/* -=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
6127
6128/** @name \#VMEXIT handlers.
6129 * @{
6130 */
6131
6132/**
6133 * \#VMEXIT handler for external interrupts, NMIs, FPU assertion freeze and INIT
6134 * signals (SVM_EXIT_INTR, SVM_EXIT_NMI, SVM_EXIT_FERR_FREEZE, SVM_EXIT_INIT).
6135 */
6136HMSVM_EXIT_DECL hmR0SvmExitIntr(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6137{
6138 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6139
6140 if (pSvmTransient->u64ExitCode == SVM_EXIT_NMI)
6141 STAM_REL_COUNTER_INC(&pVCpu->hm.s.StatExitHostNmiInGC);
6142 else if (pSvmTransient->u64ExitCode == SVM_EXIT_INTR)
6143 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitExtInt);
6144
6145 /*
6146 * AMD-V has no preemption timer and the generic periodic preemption timer has no way to signal -before- the timer
6147 * fires if the current interrupt is our own timer or a some other host interrupt. We also cannot examine what
6148 * interrupt it is until the host actually take the interrupt.
6149 *
6150 * Going back to executing guest code here unconditionally causes random scheduling problems (observed on an
6151 * AMD Phenom 9850 Quad-Core on Windows 64-bit host).
6152 */
6153 return VINF_EM_RAW_INTERRUPT;
6154}
6155
6156
6157/**
6158 * \#VMEXIT handler for WBINVD (SVM_EXIT_WBINVD). Conditional \#VMEXIT.
6159 */
6160HMSVM_EXIT_DECL hmR0SvmExitWbinvd(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6161{
6162 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6163
6164 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 2);
6165 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWbinvd);
6166 int rc = VINF_SUCCESS;
6167 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6168 return rc;
6169}
6170
6171
6172/**
6173 * \#VMEXIT handler for INVD (SVM_EXIT_INVD). Unconditional \#VMEXIT.
6174 */
6175HMSVM_EXIT_DECL hmR0SvmExitInvd(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6176{
6177 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6178
6179 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 2);
6180 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvd);
6181 int rc = VINF_SUCCESS;
6182 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6183 return rc;
6184}
6185
6186
6187/**
6188 * \#VMEXIT handler for INVD (SVM_EXIT_CPUID). Conditional \#VMEXIT.
6189 */
6190HMSVM_EXIT_DECL hmR0SvmExitCpuid(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6191{
6192 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6193 PVM pVM = pVCpu->CTX_SUFF(pVM);
6194 int rc = EMInterpretCpuId(pVM, pVCpu, CPUMCTX2CORE(pCtx));
6195 if (RT_LIKELY(rc == VINF_SUCCESS))
6196 {
6197 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 2);
6198 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6199 }
6200 else
6201 {
6202 AssertMsgFailed(("hmR0SvmExitCpuid: EMInterpretCpuId failed with %Rrc\n", rc));
6203 rc = VERR_EM_INTERPRETER;
6204 }
6205 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCpuid);
6206 return rc;
6207}
6208
6209
6210/**
6211 * \#VMEXIT handler for RDTSC (SVM_EXIT_RDTSC). Conditional \#VMEXIT.
6212 */
6213HMSVM_EXIT_DECL hmR0SvmExitRdtsc(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6214{
6215 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6216 PVM pVM = pVCpu->CTX_SUFF(pVM);
6217 int rc = EMInterpretRdtsc(pVM, pVCpu, CPUMCTX2CORE(pCtx));
6218 if (RT_LIKELY(rc == VINF_SUCCESS))
6219 {
6220 pSvmTransient->fUpdateTscOffsetting = true;
6221 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 2);
6222 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6223 }
6224 else
6225 {
6226 AssertMsgFailed(("hmR0SvmExitRdtsc: EMInterpretRdtsc failed with %Rrc\n", rc));
6227 rc = VERR_EM_INTERPRETER;
6228 }
6229 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtsc);
6230 return rc;
6231}
6232
6233
6234/**
6235 * \#VMEXIT handler for RDTSCP (SVM_EXIT_RDTSCP). Conditional \#VMEXIT.
6236 */
6237HMSVM_EXIT_DECL hmR0SvmExitRdtscp(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6238{
6239 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6240 int rc = EMInterpretRdtscp(pVCpu->CTX_SUFF(pVM), pVCpu, pCtx);
6241 if (RT_LIKELY(rc == VINF_SUCCESS))
6242 {
6243 pSvmTransient->fUpdateTscOffsetting = true;
6244 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 3);
6245 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6246 }
6247 else
6248 {
6249 AssertMsgFailed(("hmR0SvmExitRdtsc: EMInterpretRdtscp failed with %Rrc\n", rc));
6250 rc = VERR_EM_INTERPRETER;
6251 }
6252 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdtscp);
6253 return rc;
6254}
6255
6256
6257/**
6258 * \#VMEXIT handler for RDPMC (SVM_EXIT_RDPMC). Conditional \#VMEXIT.
6259 */
6260HMSVM_EXIT_DECL hmR0SvmExitRdpmc(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6261{
6262 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6263 int rc = EMInterpretRdpmc(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
6264 if (RT_LIKELY(rc == VINF_SUCCESS))
6265 {
6266 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 2);
6267 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6268 }
6269 else
6270 {
6271 AssertMsgFailed(("hmR0SvmExitRdpmc: EMInterpretRdpmc failed with %Rrc\n", rc));
6272 rc = VERR_EM_INTERPRETER;
6273 }
6274 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdpmc);
6275 return rc;
6276}
6277
6278
6279/**
6280 * \#VMEXIT handler for INVLPG (SVM_EXIT_INVLPG). Conditional \#VMEXIT.
6281 */
6282HMSVM_EXIT_DECL hmR0SvmExitInvlpg(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6283{
6284 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6285 PVM pVM = pVCpu->CTX_SUFF(pVM);
6286 Assert(!pVM->hm.s.fNestedPaging);
6287 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvlpg);
6288
6289 if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST)
6290 {
6291 Assert(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE);
6292 PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
6293 uint8_t const cbInstr = pVmcb->ctrl.u64NextRIP - pCtx->rip;
6294 RTGCPTR const GCPtrPage = pVmcb->ctrl.u64ExitInfo1;
6295 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpg(pVCpu, cbInstr, GCPtrPage);
6296 HMSVM_CHECK_SINGLE_STEP(pVCpu, rcStrict);
6297 return VBOXSTRICTRC_VAL(rcStrict);
6298 }
6299
6300 int rc = hmR0SvmInterpretInvlpg(pVM, pVCpu, pCtx); /* Updates RIP if successful. */
6301 Assert(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER);
6302 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6303 return rc;
6304}
6305
6306
6307/**
6308 * \#VMEXIT handler for HLT (SVM_EXIT_HLT). Conditional \#VMEXIT.
6309 */
6310HMSVM_EXIT_DECL hmR0SvmExitHlt(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6311{
6312 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6313
6314 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 1);
6315 int rc = EMShouldContinueAfterHalt(pVCpu, pCtx) ? VINF_SUCCESS : VINF_EM_HALT;
6316 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6317 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
6318 if (rc != VINF_SUCCESS)
6319 STAM_COUNTER_INC(&pVCpu->hm.s.StatSwitchHltToR3);
6320 return rc;
6321}
6322
6323
6324/**
6325 * \#VMEXIT handler for MONITOR (SVM_EXIT_MONITOR). Conditional \#VMEXIT.
6326 */
6327HMSVM_EXIT_DECL hmR0SvmExitMonitor(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6328{
6329 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6330 int rc = EMInterpretMonitor(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
6331 if (RT_LIKELY(rc == VINF_SUCCESS))
6332 {
6333 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 3);
6334 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6335 }
6336 else
6337 {
6338 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0SvmExitMonitor: EMInterpretMonitor failed with %Rrc\n", rc));
6339 rc = VERR_EM_INTERPRETER;
6340 }
6341 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMonitor);
6342 return rc;
6343}
6344
6345
6346/**
6347 * \#VMEXIT handler for MWAIT (SVM_EXIT_MWAIT). Conditional \#VMEXIT.
6348 */
6349HMSVM_EXIT_DECL hmR0SvmExitMwait(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6350{
6351 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6352 VBOXSTRICTRC rc2 = EMInterpretMWait(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
6353 int rc = VBOXSTRICTRC_VAL(rc2);
6354 if ( rc == VINF_EM_HALT
6355 || rc == VINF_SUCCESS)
6356 {
6357 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 3);
6358
6359 if ( rc == VINF_EM_HALT
6360 && EMMonitorWaitShouldContinue(pVCpu, pCtx))
6361 {
6362 rc = VINF_SUCCESS;
6363 }
6364 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6365 }
6366 else
6367 {
6368 AssertMsg(rc == VERR_EM_INTERPRETER, ("hmR0SvmExitMwait: EMInterpretMWait failed with %Rrc\n", rc));
6369 rc = VERR_EM_INTERPRETER;
6370 }
6371 AssertMsg(rc == VINF_SUCCESS || rc == VINF_EM_HALT || rc == VERR_EM_INTERPRETER,
6372 ("hmR0SvmExitMwait: EMInterpretMWait failed rc=%Rrc\n", rc));
6373 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitMwait);
6374 return rc;
6375}
6376
6377
6378/**
6379 * \#VMEXIT handler for shutdown (triple-fault) (SVM_EXIT_SHUTDOWN). Conditional
6380 * \#VMEXIT.
6381 */
6382HMSVM_EXIT_DECL hmR0SvmExitShutdown(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6383{
6384 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6385 return VINF_EM_RESET;
6386}
6387
6388
6389/**
6390 * \#VMEXIT handler for unexpected exits. Conditional \#VMEXIT.
6391 */
6392HMSVM_EXIT_DECL hmR0SvmExitUnexpected(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6393{
6394 RT_NOREF(pCtx);
6395 AssertMsgFailed(("hmR0SvmExitUnexpected: ExitCode=%#RX64\n", pSvmTransient->u64ExitCode));
6396 pVCpu->hm.s.u32HMError = (uint32_t)pSvmTransient->u64ExitCode;
6397 return VERR_SVM_UNEXPECTED_EXIT;
6398}
6399
6400
6401/**
6402 * \#VMEXIT handler for CRx reads (SVM_EXIT_READ_CR*). Conditional \#VMEXIT.
6403 */
6404HMSVM_EXIT_DECL hmR0SvmExitReadCRx(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6405{
6406 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6407
6408 Log4(("hmR0SvmExitReadCRx: CS:RIP=%04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
6409 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitCRxRead[pSvmTransient->u64ExitCode - SVM_EXIT_READ_CR0]);
6410
6411 PVM pVM = pVCpu->CTX_SUFF(pVM);
6412 if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST)
6413 {
6414 Assert(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE);
6415 PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
6416 bool const fMovCRx = RT_BOOL(pVmcb->ctrl.u64ExitInfo1 & SVM_EXIT1_MOV_CRX_MASK);
6417 if (fMovCRx)
6418 {
6419 uint8_t const cbInstr = pVmcb->ctrl.u64NextRIP - pCtx->rip;
6420 uint8_t const iCrReg = pSvmTransient->u64ExitCode - SVM_EXIT_READ_CR0;
6421 uint8_t const iGReg = pVmcb->ctrl.u64ExitInfo1 & SVM_EXIT1_MOV_CRX_GPR_NUMBER;
6422 VBOXSTRICTRC rcStrict = IEMExecDecodedMovCRxRead(pVCpu, cbInstr, iGReg, iCrReg);
6423 HMSVM_CHECK_SINGLE_STEP(pVCpu, rcStrict);
6424 return VBOXSTRICTRC_VAL(rcStrict);
6425 }
6426 /* else: SMSW instruction, fall back below to IEM for this. */
6427 }
6428
6429 VBOXSTRICTRC rc2 = EMInterpretInstruction(pVCpu, CPUMCTX2CORE(pCtx), 0 /* pvFault */);
6430 int rc = VBOXSTRICTRC_VAL(rc2);
6431 AssertMsg(rc == VINF_SUCCESS || rc == VERR_EM_INTERPRETER || rc == VINF_PGM_CHANGE_MODE || rc == VINF_PGM_SYNC_CR3,
6432 ("hmR0SvmExitReadCRx: EMInterpretInstruction failed rc=%Rrc\n", rc));
6433 Assert((pSvmTransient->u64ExitCode - SVM_EXIT_READ_CR0) <= 15);
6434 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6435 return rc;
6436}
6437
6438
6439/**
6440 * \#VMEXIT handler for CRx writes (SVM_EXIT_WRITE_CR*). Conditional \#VMEXIT.
6441 */
6442HMSVM_EXIT_DECL hmR0SvmExitWriteCRx(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6443{
6444 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6445
6446 uint8_t const iCrReg = pSvmTransient->u64ExitCode - SVM_EXIT_WRITE_CR0;
6447 Assert(iCrReg <= 15);
6448
6449 VBOXSTRICTRC rcStrict = VERR_SVM_IPE_5;
6450 PVM pVM = pVCpu->CTX_SUFF(pVM);
6451 bool fDecodedInstr = false;
6452 if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_DECODE_ASSIST)
6453 {
6454 Assert(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE);
6455 PCSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
6456 bool const fMovCRx = RT_BOOL(pVmcb->ctrl.u64ExitInfo1 & SVM_EXIT1_MOV_CRX_MASK);
6457 if (fMovCRx)
6458 {
6459 uint8_t const cbInstr = pVmcb->ctrl.u64NextRIP - pCtx->rip;
6460 uint8_t const iGReg = pVmcb->ctrl.u64ExitInfo1 & SVM_EXIT1_MOV_CRX_GPR_NUMBER;
6461 rcStrict = IEMExecDecodedMovCRxWrite(pVCpu, cbInstr, iCrReg, iGReg);
6462 fDecodedInstr = true;
6463 }
6464 /* else: LMSW or CLTS instruction, fall back below to IEM for this. */
6465 }
6466
6467 if (!fDecodedInstr)
6468 {
6469 rcStrict = IEMExecOneBypassEx(pVCpu, CPUMCTX2CORE(pCtx), NULL);
6470 if (RT_UNLIKELY( rcStrict == VERR_IEM_ASPECT_NOT_IMPLEMENTED
6471 || rcStrict == VERR_IEM_INSTR_NOT_IMPLEMENTED))
6472 rcStrict = VERR_EM_INTERPRETER;
6473 }
6474
6475 if (rcStrict == VINF_SUCCESS)
6476 {
6477 switch (iCrReg)
6478 {
6479 case 0: /* CR0. */
6480 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
6481 break;
6482
6483 case 3: /* CR3. */
6484 Assert(!pVM->hm.s.fNestedPaging);
6485 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR3);
6486 break;
6487
6488 case 4: /* CR4. */
6489 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR4);
6490 break;
6491
6492 case 8: /* CR8 (TPR). */
6493 HMCPU_CF_SET(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE);
6494 break;
6495
6496 default:
6497 AssertMsgFailed(("hmR0SvmExitWriteCRx: Invalid/Unexpected Write-CRx exit. u64ExitCode=%#RX64 %#x\n",
6498 pSvmTransient->u64ExitCode, iCrReg));
6499 break;
6500 }
6501 HMSVM_CHECK_SINGLE_STEP(pVCpu, rcStrict);
6502 }
6503 else
6504 Assert(rcStrict == VERR_EM_INTERPRETER || rcStrict == VINF_PGM_CHANGE_MODE || rcStrict == VINF_PGM_SYNC_CR3);
6505 return VBOXSTRICTRC_TODO(rcStrict);
6506}
6507
6508
6509/**
6510 * \#VMEXIT handler for instructions that result in a \#UD exception delivered
6511 * to the guest.
6512 */
6513HMSVM_EXIT_DECL hmR0SvmExitSetPendingXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6514{
6515 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6516 hmR0SvmSetPendingXcptUD(pVCpu);
6517 return VINF_SUCCESS;
6518}
6519
6520
6521/**
6522 * \#VMEXIT handler for MSR read and writes (SVM_EXIT_MSR). Conditional
6523 * \#VMEXIT.
6524 */
6525HMSVM_EXIT_DECL hmR0SvmExitMsr(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6526{
6527 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6528 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
6529 PVM pVM = pVCpu->CTX_SUFF(pVM);
6530
6531 int rc;
6532 if (pVmcb->ctrl.u64ExitInfo1 == SVM_EXIT1_MSR_WRITE)
6533 {
6534 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitWrmsr);
6535
6536 /* Handle TPR patching; intercepted LSTAR write. */
6537 if ( pVM->hm.s.fTPRPatchingActive
6538 && pCtx->ecx == MSR_K8_LSTAR)
6539 {
6540 if ((pCtx->eax & 0xff) != pSvmTransient->u8GuestTpr)
6541 {
6542 /* Our patch code uses LSTAR for TPR caching for 32-bit guests. */
6543 int rc2 = APICSetTpr(pVCpu, pCtx->eax & 0xff);
6544 AssertRC(rc2);
6545 HMCPU_CF_SET(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE);
6546 }
6547 rc = VINF_SUCCESS;
6548 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 2);
6549 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6550 return rc;
6551 }
6552
6553 if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
6554 {
6555 rc = EMInterpretWrmsr(pVM, pVCpu, CPUMCTX2CORE(pCtx));
6556 if (RT_LIKELY(rc == VINF_SUCCESS))
6557 {
6558 pCtx->rip = pVmcb->ctrl.u64NextRIP;
6559 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6560 }
6561 else
6562 AssertMsg( rc == VERR_EM_INTERPRETER
6563 || rc == VINF_CPUM_R3_MSR_WRITE, ("hmR0SvmExitMsr: EMInterpretWrmsr failed rc=%Rrc\n", rc));
6564 }
6565 else
6566 {
6567 rc = VBOXSTRICTRC_TODO(EMInterpretInstruction(pVCpu, CPUMCTX2CORE(pCtx), 0 /* pvFault */));
6568 if (RT_LIKELY(rc == VINF_SUCCESS))
6569 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc); /* RIP updated by EMInterpretInstruction(). */
6570 else
6571 AssertMsg( rc == VERR_EM_INTERPRETER
6572 || rc == VINF_CPUM_R3_MSR_WRITE, ("hmR0SvmExitMsr: WrMsr. EMInterpretInstruction failed rc=%Rrc\n", rc));
6573 }
6574
6575 if (rc == VINF_SUCCESS)
6576 {
6577 /* If this is an X2APIC WRMSR access, update the APIC state as well. */
6578 if ( pCtx->ecx >= MSR_IA32_X2APIC_START
6579 && pCtx->ecx <= MSR_IA32_X2APIC_END)
6580 {
6581 /*
6582 * We've already saved the APIC related guest-state (TPR) in hmR0SvmPostRunGuest(). When full APIC register
6583 * virtualization is implemented we'll have to make sure APIC state is saved from the VMCB before
6584 * EMInterpretWrmsr() changes it.
6585 */
6586 HMCPU_CF_SET(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE);
6587 }
6588 else if (pCtx->ecx == MSR_K6_EFER)
6589 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_EFER_MSR);
6590 else if (pCtx->ecx == MSR_IA32_TSC)
6591 pSvmTransient->fUpdateTscOffsetting = true;
6592 }
6593 }
6594 else
6595 {
6596 /* MSR Read access. */
6597 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitRdmsr);
6598 Assert(pVmcb->ctrl.u64ExitInfo1 == SVM_EXIT1_MSR_READ);
6599
6600 if (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
6601 {
6602 rc = EMInterpretRdmsr(pVM, pVCpu, CPUMCTX2CORE(pCtx));
6603 if (RT_LIKELY(rc == VINF_SUCCESS))
6604 {
6605 pCtx->rip = pVmcb->ctrl.u64NextRIP;
6606 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6607 }
6608 else
6609 AssertMsg( rc == VERR_EM_INTERPRETER
6610 || rc == VINF_CPUM_R3_MSR_READ, ("hmR0SvmExitMsr: EMInterpretRdmsr failed rc=%Rrc\n", rc));
6611 }
6612 else
6613 {
6614 rc = VBOXSTRICTRC_TODO(EMInterpretInstruction(pVCpu, CPUMCTX2CORE(pCtx), 0));
6615 if (RT_UNLIKELY(rc != VINF_SUCCESS))
6616 {
6617 AssertMsg( rc == VERR_EM_INTERPRETER
6618 || rc == VINF_CPUM_R3_MSR_READ, ("hmR0SvmExitMsr: RdMsr. EMInterpretInstruction failed rc=%Rrc\n", rc));
6619 }
6620 /* RIP updated by EMInterpretInstruction(). */
6621 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6622 }
6623 }
6624
6625 /* RIP has been updated by EMInterpret[Rd|Wr]msr(). */
6626 return rc;
6627}
6628
6629
6630/**
6631 * \#VMEXIT handler for DRx read (SVM_EXIT_READ_DRx). Conditional \#VMEXIT.
6632 */
6633HMSVM_EXIT_DECL hmR0SvmExitReadDRx(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6634{
6635 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6636 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxRead);
6637
6638 /* We should -not- get this #VMEXIT if the guest's debug registers were active. */
6639 if (pSvmTransient->fWasGuestDebugStateActive)
6640 {
6641 AssertMsgFailed(("hmR0SvmExitReadDRx: Unexpected exit %#RX32\n", (uint32_t)pSvmTransient->u64ExitCode));
6642 pVCpu->hm.s.u32HMError = (uint32_t)pSvmTransient->u64ExitCode;
6643 return VERR_SVM_UNEXPECTED_EXIT;
6644 }
6645
6646 /*
6647 * Lazy DR0-3 loading.
6648 */
6649 if (!pSvmTransient->fWasHyperDebugStateActive)
6650 {
6651 Assert(!DBGFIsStepping(pVCpu)); Assert(!pVCpu->hm.s.fSingleInstruction);
6652 Log5(("hmR0SvmExitReadDRx: Lazy loading guest debug registers\n"));
6653
6654 /* Don't intercept DRx read and writes. */
6655 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
6656 pVmcb->ctrl.u16InterceptRdDRx = 0;
6657 pVmcb->ctrl.u16InterceptWrDRx = 0;
6658 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
6659
6660 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
6661 VMMRZCallRing3Disable(pVCpu);
6662 HM_DISABLE_PREEMPT();
6663
6664 /* Save the host & load the guest debug state, restart execution of the MOV DRx instruction. */
6665 CPUMR0LoadGuestDebugState(pVCpu, false /* include DR6 */);
6666 Assert(CPUMIsGuestDebugStateActive(pVCpu) || HC_ARCH_BITS == 32);
6667
6668 HM_RESTORE_PREEMPT();
6669 VMMRZCallRing3Enable(pVCpu);
6670
6671 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxContextSwitch);
6672 return VINF_SUCCESS;
6673 }
6674
6675 /*
6676 * Interpret the read/writing of DRx.
6677 */
6678 /** @todo Decode assist. */
6679 VBOXSTRICTRC rc = EMInterpretInstruction(pVCpu, CPUMCTX2CORE(pCtx), 0 /* pvFault */);
6680 Log5(("hmR0SvmExitReadDRx: Emulated DRx access: rc=%Rrc\n", VBOXSTRICTRC_VAL(rc)));
6681 if (RT_LIKELY(rc == VINF_SUCCESS))
6682 {
6683 /* Not necessary for read accesses but whatever doesn't hurt for now, will be fixed with decode assist. */
6684 /** @todo CPUM should set this flag! */
6685 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_DEBUG);
6686 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
6687 }
6688 else
6689 Assert(rc == VERR_EM_INTERPRETER);
6690 return VBOXSTRICTRC_TODO(rc);
6691}
6692
6693
6694/**
6695 * \#VMEXIT handler for DRx write (SVM_EXIT_WRITE_DRx). Conditional \#VMEXIT.
6696 */
6697HMSVM_EXIT_DECL hmR0SvmExitWriteDRx(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6698{
6699 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6700 /* For now it's the same since we interpret the instruction anyway. Will change when using of Decode Assist is implemented. */
6701 int rc = hmR0SvmExitReadDRx(pVCpu, pCtx, pSvmTransient);
6702 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitDRxWrite);
6703 STAM_COUNTER_DEC(&pVCpu->hm.s.StatExitDRxRead);
6704 return rc;
6705}
6706
6707
6708/**
6709 * \#VMEXIT handler for XCRx write (SVM_EXIT_XSETBV). Conditional \#VMEXIT.
6710 */
6711HMSVM_EXIT_DECL hmR0SvmExitXsetbv(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6712{
6713 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6714
6715 /** @todo decode assists... */
6716 VBOXSTRICTRC rcStrict = IEMExecOne(pVCpu);
6717 if (rcStrict == VINF_IEM_RAISED_XCPT)
6718 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
6719
6720 pVCpu->hm.s.fLoadSaveGuestXcr0 = (pCtx->cr4 & X86_CR4_OSXSAVE) && pCtx->aXcr[0] != ASMGetXcr0();
6721 Log4(("hmR0SvmExitXsetbv: New XCR0=%#RX64 fLoadSaveGuestXcr0=%d (cr4=%RX64) rcStrict=%Rrc\n",
6722 pCtx->aXcr[0], pVCpu->hm.s.fLoadSaveGuestXcr0, pCtx->cr4, VBOXSTRICTRC_VAL(rcStrict)));
6723
6724 HMSVM_CHECK_SINGLE_STEP(pVCpu, rcStrict);
6725 return VBOXSTRICTRC_TODO(rcStrict);
6726}
6727
6728
6729/**
6730 * \#VMEXIT handler for I/O instructions (SVM_EXIT_IOIO). Conditional \#VMEXIT.
6731 */
6732HMSVM_EXIT_DECL hmR0SvmExitIOInstr(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6733{
6734 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6735
6736 /* I/O operation lookup arrays. */
6737 static uint32_t const s_aIOSize[8] = { 0, 1, 2, 0, 4, 0, 0, 0 }; /* Size of the I/O accesses in bytes. */
6738 static uint32_t const s_aIOOpAnd[8] = { 0, 0xff, 0xffff, 0, 0xffffffff, 0, 0, 0 }; /* AND masks for saving
6739 the result (in AL/AX/EAX). */
6740 Log4(("hmR0SvmExitIOInstr: CS:RIP=%04x:%#RX64\n", pCtx->cs.Sel, pCtx->rip));
6741
6742 PVM pVM = pVCpu->CTX_SUFF(pVM);
6743 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
6744
6745 /* Refer AMD spec. 15.10.2 "IN and OUT Behaviour" and Figure 15-2. "EXITINFO1 for IOIO Intercept" for the format. */
6746 SVMIOIOEXITINFO IoExitInfo;
6747 IoExitInfo.u = (uint32_t)pVmcb->ctrl.u64ExitInfo1;
6748 uint32_t uIOWidth = (IoExitInfo.u >> 4) & 0x7;
6749 uint32_t cbValue = s_aIOSize[uIOWidth];
6750 uint32_t uAndVal = s_aIOOpAnd[uIOWidth];
6751
6752 if (RT_UNLIKELY(!cbValue))
6753 {
6754 AssertMsgFailed(("hmR0SvmExitIOInstr: Invalid IO operation. uIOWidth=%u\n", uIOWidth));
6755 return VERR_EM_INTERPRETER;
6756 }
6757
6758 VBOXSTRICTRC rcStrict;
6759 bool fUpdateRipAlready = false;
6760 if (IoExitInfo.n.u1STR)
6761 {
6762#ifdef VBOX_WITH_2ND_IEM_STEP
6763 /* INS/OUTS - I/O String instruction. */
6764 /** @todo Huh? why can't we use the segment prefix information given by AMD-V
6765 * in EXITINFO1? Investigate once this thing is up and running. */
6766 Log4(("CS:RIP=%04x:%08RX64 %#06x/%u %c str\n", pCtx->cs.Sel, pCtx->rip, IoExitInfo.n.u16Port, cbValue,
6767 IoExitInfo.n.u1Type == SVM_IOIO_WRITE ? 'w' : 'r'));
6768 AssertReturn(pCtx->dx == IoExitInfo.n.u16Port, VERR_SVM_IPE_2);
6769 static IEMMODE const s_aenmAddrMode[8] =
6770 {
6771 (IEMMODE)-1, IEMMODE_16BIT, IEMMODE_32BIT, (IEMMODE)-1, IEMMODE_64BIT, (IEMMODE)-1, (IEMMODE)-1, (IEMMODE)-1
6772 };
6773 IEMMODE enmAddrMode = s_aenmAddrMode[(IoExitInfo.u >> 7) & 0x7];
6774 if (enmAddrMode != (IEMMODE)-1)
6775 {
6776 uint64_t cbInstr = pVmcb->ctrl.u64ExitInfo2 - pCtx->rip;
6777 if (cbInstr <= 15 && cbInstr >= 1)
6778 {
6779 Assert(cbInstr >= 1U + IoExitInfo.n.u1REP);
6780 if (IoExitInfo.n.u1Type == SVM_IOIO_WRITE)
6781 {
6782 /* Don't know exactly how to detect whether u3SEG is valid, currently
6783 only enabling it for Bulldozer and later with NRIP. OS/2 broke on
6784 2384 Opterons when only checking NRIP. */
6785 if ( (pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_NRIP_SAVE)
6786 && pVM->cpum.ro.GuestFeatures.enmMicroarch >= kCpumMicroarch_AMD_15h_First)
6787 {
6788 AssertMsg(IoExitInfo.n.u3SEG == X86_SREG_DS || cbInstr > 1U + IoExitInfo.n.u1REP,
6789 ("u32Seg=%d cbInstr=%d u1REP=%d", IoExitInfo.n.u3SEG, cbInstr, IoExitInfo.n.u1REP));
6790 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, IoExitInfo.n.u1REP, (uint8_t)cbInstr,
6791 IoExitInfo.n.u3SEG, true /*fIoChecked*/);
6792 }
6793 else if (cbInstr == 1U + IoExitInfo.n.u1REP)
6794 rcStrict = IEMExecStringIoWrite(pVCpu, cbValue, enmAddrMode, IoExitInfo.n.u1REP, (uint8_t)cbInstr,
6795 X86_SREG_DS, true /*fIoChecked*/);
6796 else
6797 rcStrict = IEMExecOne(pVCpu);
6798 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringWrite);
6799 }
6800 else
6801 {
6802 AssertMsg(IoExitInfo.n.u3SEG == X86_SREG_ES /*=0*/, ("%#x\n", IoExitInfo.n.u3SEG));
6803 rcStrict = IEMExecStringIoRead(pVCpu, cbValue, enmAddrMode, IoExitInfo.n.u1REP, (uint8_t)cbInstr,
6804 true /*fIoChecked*/);
6805 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringRead);
6806 }
6807 }
6808 else
6809 {
6810 AssertMsgFailed(("rip=%RX64 nrip=%#RX64 cbInstr=%#RX64\n", pCtx->rip, pVmcb->ctrl.u64ExitInfo2, cbInstr));
6811 rcStrict = IEMExecOne(pVCpu);
6812 }
6813 }
6814 else
6815 {
6816 AssertMsgFailed(("IoExitInfo=%RX64\n", IoExitInfo.u));
6817 rcStrict = IEMExecOne(pVCpu);
6818 }
6819 fUpdateRipAlready = true;
6820
6821#else
6822 /* INS/OUTS - I/O String instruction. */
6823 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;
6824
6825 /** @todo Huh? why can't we use the segment prefix information given by AMD-V
6826 * in EXITINFO1? Investigate once this thing is up and running. */
6827
6828 rcStrict = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL);
6829 if (rcStrict == VINF_SUCCESS)
6830 {
6831 if (IoExitInfo.n.u1Type == SVM_IOIO_WRITE)
6832 {
6833 rcStrict = IOMInterpretOUTSEx(pVM, pVCpu, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, pDis->fPrefix,
6834 (DISCPUMODE)pDis->uAddrMode, cbValue);
6835 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringWrite);
6836 }
6837 else
6838 {
6839 rcStrict = IOMInterpretINSEx(pVM, pVCpu, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, pDis->fPrefix,
6840 (DISCPUMODE)pDis->uAddrMode, cbValue);
6841 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringRead);
6842 }
6843 }
6844 else
6845 rcStrict = VINF_EM_RAW_EMULATE_INSTR;
6846#endif
6847 }
6848 else
6849 {
6850 /* IN/OUT - I/O instruction. */
6851 Assert(!IoExitInfo.n.u1REP);
6852
6853 if (IoExitInfo.n.u1Type == SVM_IOIO_WRITE)
6854 {
6855 rcStrict = IOMIOPortWrite(pVM, pVCpu, IoExitInfo.n.u16Port, pCtx->eax & uAndVal, cbValue);
6856 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
6857 }
6858 else
6859 {
6860 uint32_t u32Val = 0;
6861 rcStrict = IOMIOPortRead(pVM, pVCpu, IoExitInfo.n.u16Port, &u32Val, cbValue);
6862 if (IOM_SUCCESS(rcStrict))
6863 {
6864 /* Save result of I/O IN instr. in AL/AX/EAX. */
6865 /** @todo r=bird: 32-bit op size should clear high bits of rax! */
6866 pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Val & uAndVal);
6867 }
6868 else if (rcStrict == VINF_IOM_R3_IOPORT_READ)
6869 HMR0SavePendingIOPortRead(pVCpu, pCtx->rip, pVmcb->ctrl.u64ExitInfo2, IoExitInfo.n.u16Port, uAndVal, cbValue);
6870
6871 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
6872 }
6873 }
6874
6875 if (IOM_SUCCESS(rcStrict))
6876 {
6877 /* AMD-V saves the RIP of the instruction following the IO instruction in EXITINFO2. */
6878 if (!fUpdateRipAlready)
6879 pCtx->rip = pVmcb->ctrl.u64ExitInfo2;
6880
6881 /*
6882 * If any I/O breakpoints are armed, we need to check if one triggered
6883 * and take appropriate action.
6884 * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
6885 */
6886 /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
6887 * execution engines about whether hyper BPs and such are pending. */
6888 uint32_t const uDr7 = pCtx->dr[7];
6889 if (RT_UNLIKELY( ( (uDr7 & X86_DR7_ENABLED_MASK)
6890 && X86_DR7_ANY_RW_IO(uDr7)
6891 && (pCtx->cr4 & X86_CR4_DE))
6892 || DBGFBpIsHwIoArmed(pVM)))
6893 {
6894 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
6895 VMMRZCallRing3Disable(pVCpu);
6896 HM_DISABLE_PREEMPT();
6897
6898 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
6899 CPUMR0DebugStateMaybeSaveGuest(pVCpu, false /*fDr6*/);
6900
6901 VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, IoExitInfo.n.u16Port, cbValue);
6902 if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
6903 {
6904 /* Raise #DB. */
6905 pVmcb->guest.u64DR6 = pCtx->dr[6];
6906 pVmcb->guest.u64DR7 = pCtx->dr[7];
6907 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DRX;
6908 hmR0SvmSetPendingXcptDB(pVCpu);
6909 }
6910 /* rcStrict is VINF_SUCCESS, VINF_IOM_R3_IOPORT_COMMIT_WRITE, or in [VINF_EM_FIRST..VINF_EM_LAST],
6911 however we can ditch VINF_IOM_R3_IOPORT_COMMIT_WRITE as it has VMCPU_FF_IOM as backup. */
6912 else if ( rcStrict2 != VINF_SUCCESS
6913 && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
6914 rcStrict = rcStrict2;
6915 AssertCompile(VINF_EM_LAST < VINF_IOM_R3_IOPORT_COMMIT_WRITE);
6916
6917 HM_RESTORE_PREEMPT();
6918 VMMRZCallRing3Enable(pVCpu);
6919 }
6920
6921 HMSVM_CHECK_SINGLE_STEP(pVCpu, rcStrict);
6922 }
6923
6924#ifdef VBOX_STRICT
6925 if (rcStrict == VINF_IOM_R3_IOPORT_READ)
6926 Assert(IoExitInfo.n.u1Type == SVM_IOIO_READ);
6927 else if (rcStrict == VINF_IOM_R3_IOPORT_WRITE || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE)
6928 Assert(IoExitInfo.n.u1Type == SVM_IOIO_WRITE);
6929 else
6930 {
6931 /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
6932 * statuses, that the VMM device and some others may return. See
6933 * IOM_SUCCESS() for guidance. */
6934 AssertMsg( RT_FAILURE(rcStrict)
6935 || rcStrict == VINF_SUCCESS
6936 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
6937 || rcStrict == VINF_EM_DBG_BREAKPOINT
6938 || rcStrict == VINF_EM_RAW_GUEST_TRAP
6939 || rcStrict == VINF_EM_RAW_TO_R3
6940 || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
6941 }
6942#endif
6943 return VBOXSTRICTRC_TODO(rcStrict);
6944}
6945
6946
6947/**
6948 * \#VMEXIT handler for Nested Page-faults (SVM_EXIT_NPF). Conditional \#VMEXIT.
6949 */
6950HMSVM_EXIT_DECL hmR0SvmExitNestedPF(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
6951{
6952 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
6953 PVM pVM = pVCpu->CTX_SUFF(pVM);
6954 Assert(pVM->hm.s.fNestedPaging);
6955
6956 HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
6957
6958 /* See AMD spec. 15.25.6 "Nested versus Guest Page Faults, Fault Ordering" for VMCB details for #NPF. */
6959 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
6960 uint32_t u32ErrCode = pVmcb->ctrl.u64ExitInfo1;
6961 RTGCPHYS GCPhysFaultAddr = pVmcb->ctrl.u64ExitInfo2;
6962
6963 Log4(("#NPF at CS:RIP=%04x:%#RX64 faultaddr=%RGp errcode=%#x \n", pCtx->cs.Sel, pCtx->rip, GCPhysFaultAddr, u32ErrCode));
6964
6965#ifdef VBOX_HM_WITH_GUEST_PATCHING
6966 /* TPR patching for 32-bit guests, using the reserved bit in the page tables for MMIO regions. */
6967 if ( pVM->hm.s.fTprPatchingAllowed
6968 && (GCPhysFaultAddr & PAGE_OFFSET_MASK) == XAPIC_OFF_TPR
6969 && ( !(u32ErrCode & X86_TRAP_PF_P) /* Not present */
6970 || (u32ErrCode & (X86_TRAP_PF_P | X86_TRAP_PF_RSVD)) == (X86_TRAP_PF_P | X86_TRAP_PF_RSVD)) /* MMIO page. */
6971 && !CPUMIsGuestInLongModeEx(pCtx)
6972 && !CPUMGetGuestCPL(pVCpu)
6973 && pVM->hm.s.cPatches < RT_ELEMENTS(pVM->hm.s.aPatches))
6974 {
6975 RTGCPHYS GCPhysApicBase = APICGetBaseMsrNoCheck(pVCpu);
6976 GCPhysApicBase &= PAGE_BASE_GC_MASK;
6977
6978 if (GCPhysFaultAddr == GCPhysApicBase + XAPIC_OFF_TPR)
6979 {
6980 /* Only attempt to patch the instruction once. */
6981 PHMTPRPATCH pPatch = (PHMTPRPATCH)RTAvloU32Get(&pVM->hm.s.PatchTree, (AVLOU32KEY)pCtx->eip);
6982 if (!pPatch)
6983 return VINF_EM_HM_PATCH_TPR_INSTR;
6984 }
6985 }
6986#endif
6987
6988 /*
6989 * Determine the nested paging mode.
6990 */
6991 PGMMODE enmNestedPagingMode;
6992#if HC_ARCH_BITS == 32
6993 if (CPUMIsGuestInLongModeEx(pCtx))
6994 enmNestedPagingMode = PGMMODE_AMD64_NX;
6995 else
6996#endif
6997 enmNestedPagingMode = PGMGetHostMode(pVM);
6998
6999 /*
7000 * MMIO optimization using the reserved (RSVD) bit in the guest page tables for MMIO pages.
7001 */
7002 int rc;
7003 Assert((u32ErrCode & (X86_TRAP_PF_RSVD | X86_TRAP_PF_P)) != X86_TRAP_PF_RSVD);
7004 if ((u32ErrCode & (X86_TRAP_PF_RSVD | X86_TRAP_PF_P)) == (X86_TRAP_PF_RSVD | X86_TRAP_PF_P))
7005 {
7006 /* If event delivery causes an MMIO #NPF, go back to instruction emulation as
7007 otherwise injecting the original pending event would most likely cause the same MMIO #NPF. */
7008 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
7009 return VINF_EM_RAW_INJECT_TRPM_EVENT;
7010
7011 VBOXSTRICTRC rc2 = PGMR0Trap0eHandlerNPMisconfig(pVM, pVCpu, enmNestedPagingMode, CPUMCTX2CORE(pCtx), GCPhysFaultAddr,
7012 u32ErrCode);
7013 rc = VBOXSTRICTRC_VAL(rc2);
7014
7015 /*
7016 * If we succeed, resume guest execution.
7017 * If we fail in interpreting the instruction because we couldn't get the guest physical address
7018 * of the page containing the instruction via the guest's page tables (we would invalidate the guest page
7019 * in the host TLB), resume execution which would cause a guest page fault to let the guest handle this
7020 * weird case. See @bugref{6043}.
7021 */
7022 if ( rc == VINF_SUCCESS
7023 || rc == VERR_PAGE_TABLE_NOT_PRESENT
7024 || rc == VERR_PAGE_NOT_PRESENT)
7025 {
7026 /* Successfully handled MMIO operation. */
7027 HMCPU_CF_SET(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE);
7028 rc = VINF_SUCCESS;
7029 }
7030 return rc;
7031 }
7032
7033 TRPMAssertXcptPF(pVCpu, GCPhysFaultAddr, u32ErrCode);
7034 rc = PGMR0Trap0eHandlerNestedPaging(pVM, pVCpu, enmNestedPagingMode, u32ErrCode, CPUMCTX2CORE(pCtx), GCPhysFaultAddr);
7035 TRPMResetTrap(pVCpu);
7036
7037 Log4(("#NPF: PGMR0Trap0eHandlerNestedPaging returned %Rrc CS:RIP=%04x:%#RX64\n", rc, pCtx->cs.Sel, pCtx->rip));
7038
7039 /*
7040 * Same case as PGMR0Trap0eHandlerNPMisconfig(). See comment above, @bugref{6043}.
7041 */
7042 if ( rc == VINF_SUCCESS
7043 || rc == VERR_PAGE_TABLE_NOT_PRESENT
7044 || rc == VERR_PAGE_NOT_PRESENT)
7045 {
7046 /* We've successfully synced our shadow page tables. */
7047 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
7048 rc = VINF_SUCCESS;
7049 }
7050
7051 return rc;
7052}
7053
7054
7055/**
7056 * \#VMEXIT handler for virtual interrupt (SVM_EXIT_VINTR). Conditional
7057 * \#VMEXIT.
7058 */
7059HMSVM_EXIT_DECL hmR0SvmExitVIntr(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7060{
7061 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7062
7063 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
7064 pVmcb->ctrl.IntCtrl.n.u1VIrqPending = 0; /* No virtual interrupts pending, we'll inject the current one/NMI before reentry. */
7065 pVmcb->ctrl.IntCtrl.n.u8VIntrVector = 0;
7066
7067 /* Indicate that we no longer need to #VMEXIT when the guest is ready to receive interrupts/NMIs, it is now ready. */
7068 pVmcb->ctrl.u64InterceptCtrl &= ~SVM_CTRL_INTERCEPT_VINTR;
7069 pVmcb->ctrl.u64VmcbCleanBits &= ~(HMSVM_VMCB_CLEAN_INTERCEPTS | HMSVM_VMCB_CLEAN_TPR);
7070
7071 /* Deliver the pending interrupt/NMI via hmR0SvmEvaluatePendingEvent() and resume guest execution. */
7072 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
7073 return VINF_SUCCESS;
7074}
7075
7076
7077/**
7078 * \#VMEXIT handler for task switches (SVM_EXIT_TASK_SWITCH). Conditional
7079 * \#VMEXIT.
7080 */
7081HMSVM_EXIT_DECL hmR0SvmExitTaskSwitch(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7082{
7083 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7084
7085 HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
7086
7087#ifndef HMSVM_ALWAYS_TRAP_TASK_SWITCH
7088 Assert(!pVCpu->CTX_SUFF(pVM)->hm.s.fNestedPaging);
7089#endif
7090
7091 /* Check if this task-switch occurred while delivering an event through the guest IDT. */
7092 if (pVCpu->hm.s.Event.fPending) /* Can happen with exceptions/NMI. See @bugref{8411}. */
7093 {
7094 /*
7095 * AMD-V provides us with the exception which caused the TS; we collect
7096 * the information in the call to hmR0SvmCheckExitDueToEventDelivery.
7097 */
7098 Log4(("hmR0SvmExitTaskSwitch: TS occurred during event delivery.\n"));
7099 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
7100 return VINF_EM_RAW_INJECT_TRPM_EVENT;
7101 }
7102
7103 /** @todo Emulate task switch someday, currently just going back to ring-3 for
7104 * emulation. */
7105 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitTaskSwitch);
7106 return VERR_EM_INTERPRETER;
7107}
7108
7109
7110/**
7111 * \#VMEXIT handler for VMMCALL (SVM_EXIT_VMMCALL). Conditional \#VMEXIT.
7112 */
7113HMSVM_EXIT_DECL hmR0SvmExitVmmCall(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7114{
7115 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7116 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmcall);
7117
7118 bool fRipUpdated;
7119 VBOXSTRICTRC rcStrict = HMSvmVmmcall(pVCpu, pCtx, &fRipUpdated);
7120 if (RT_SUCCESS(rcStrict))
7121 {
7122 /* Only update the RIP if we're continuing guest execution and not
7123 in the case of say VINF_GIM_R3_HYPERCALL. */
7124 if ( rcStrict == VINF_SUCCESS
7125 && !fRipUpdated)
7126 {
7127 hmR0SvmAdvanceRipHwAssist(pVCpu, pCtx, 3 /* cbInstr */);
7128 }
7129
7130 /* If the hypercall or TPR patching changes anything other than guest's general-purpose registers,
7131 we would need to reload the guest changed bits here before VM-entry. */
7132 return VBOXSTRICTRC_VAL(rcStrict);
7133 }
7134
7135 hmR0SvmSetPendingXcptUD(pVCpu);
7136 return VINF_SUCCESS;
7137}
7138
7139
7140/**
7141 * \#VMEXIT handler for VMMCALL (SVM_EXIT_VMMCALL). Conditional \#VMEXIT.
7142 */
7143HMSVM_EXIT_DECL hmR0SvmExitPause(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7144{
7145 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7146 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPause);
7147 return VINF_EM_RAW_INTERRUPT;
7148}
7149
7150
7151/**
7152 * \#VMEXIT handler for IRET (SVM_EXIT_IRET). Conditional \#VMEXIT.
7153 */
7154HMSVM_EXIT_DECL hmR0SvmExitIret(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7155{
7156 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7157
7158 /* Clear NMI blocking. */
7159 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
7160
7161 /* Indicate that we no longer need to #VMEXIT when the guest is ready to receive NMIs, it is now ready. */
7162 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
7163 hmR0SvmClearIretIntercept(pVmcb);
7164
7165 /* Deliver the pending NMI via hmR0SvmEvaluatePendingEvent() and resume guest execution. */
7166 return VINF_SUCCESS;
7167}
7168
7169
7170/**
7171 * \#VMEXIT handler for page-fault exceptions (SVM_EXIT_EXCEPTION_14).
7172 * Conditional \#VMEXIT.
7173 */
7174HMSVM_EXIT_DECL hmR0SvmExitXcptPF(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7175{
7176 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7177
7178 HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
7179
7180 /* See AMD spec. 15.12.15 "#PF (Page Fault)". */
7181 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
7182 uint32_t u32ErrCode = pVmcb->ctrl.u64ExitInfo1;
7183 RTGCUINTPTR uFaultAddress = pVmcb->ctrl.u64ExitInfo2;
7184 PVM pVM = pVCpu->CTX_SUFF(pVM);
7185
7186#if defined(HMSVM_ALWAYS_TRAP_ALL_XCPTS) || defined(HMSVM_ALWAYS_TRAP_PF)
7187 if (pVM->hm.s.fNestedPaging)
7188 {
7189 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
7190 if (!pSvmTransient->fVectoringDoublePF)
7191 {
7192 /* A genuine guest #PF, reflect it to the guest. */
7193 hmR0SvmSetPendingXcptPF(pVCpu, pCtx, u32ErrCode, uFaultAddress);
7194 Log4(("#PF: Guest page fault at %04X:%RGv FaultAddr=%RGv ErrCode=%#x\n", pCtx->cs.Sel, (RTGCPTR)pCtx->rip,
7195 uFaultAddress, u32ErrCode));
7196 }
7197 else
7198 {
7199 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
7200 hmR0SvmSetPendingXcptDF(pVCpu);
7201 Log4(("Pending #DF due to vectoring #PF. NP\n"));
7202 }
7203 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
7204 return VINF_SUCCESS;
7205 }
7206#endif
7207
7208 Assert(!pVM->hm.s.fNestedPaging);
7209
7210#ifdef VBOX_HM_WITH_GUEST_PATCHING
7211 /* Shortcut for APIC TPR reads and writes; only applicable to 32-bit guests. */
7212 if ( pVM->hm.s.fTprPatchingAllowed
7213 && (uFaultAddress & 0xfff) == XAPIC_OFF_TPR
7214 && !(u32ErrCode & X86_TRAP_PF_P) /* Not present. */
7215 && !CPUMIsGuestInLongModeEx(pCtx)
7216 && !CPUMGetGuestCPL(pVCpu)
7217 && pVM->hm.s.cPatches < RT_ELEMENTS(pVM->hm.s.aPatches))
7218 {
7219 RTGCPHYS GCPhysApicBase;
7220 GCPhysApicBase = APICGetBaseMsrNoCheck(pVCpu);
7221 GCPhysApicBase &= PAGE_BASE_GC_MASK;
7222
7223 /* Check if the page at the fault-address is the APIC base. */
7224 RTGCPHYS GCPhysPage;
7225 int rc2 = PGMGstGetPage(pVCpu, (RTGCPTR)uFaultAddress, NULL /* pfFlags */, &GCPhysPage);
7226 if ( rc2 == VINF_SUCCESS
7227 && GCPhysPage == GCPhysApicBase)
7228 {
7229 /* Only attempt to patch the instruction once. */
7230 PHMTPRPATCH pPatch = (PHMTPRPATCH)RTAvloU32Get(&pVM->hm.s.PatchTree, (AVLOU32KEY)pCtx->eip);
7231 if (!pPatch)
7232 return VINF_EM_HM_PATCH_TPR_INSTR;
7233 }
7234 }
7235#endif
7236
7237 Log4(("#PF: uFaultAddress=%#RX64 CS:RIP=%#04x:%#RX64 u32ErrCode %#RX32 cr3=%#RX64\n", uFaultAddress, pCtx->cs.Sel,
7238 pCtx->rip, u32ErrCode, pCtx->cr3));
7239
7240 /* If it's a vectoring #PF, emulate injecting the original event injection as PGMTrap0eHandler() is incapable
7241 of differentiating between instruction emulation and event injection that caused a #PF. See @bugref{6607}. */
7242 if (pSvmTransient->fVectoringPF)
7243 {
7244 Assert(pVCpu->hm.s.Event.fPending);
7245 return VINF_EM_RAW_INJECT_TRPM_EVENT;
7246 }
7247
7248 TRPMAssertXcptPF(pVCpu, uFaultAddress, u32ErrCode);
7249 int rc = PGMTrap0eHandler(pVCpu, u32ErrCode, CPUMCTX2CORE(pCtx), (RTGCPTR)uFaultAddress);
7250
7251 Log4(("#PF rc=%Rrc\n", rc));
7252
7253 if (rc == VINF_SUCCESS)
7254 {
7255 /* Successfully synced shadow pages tables or emulated an MMIO instruction. */
7256 TRPMResetTrap(pVCpu);
7257 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPF);
7258 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
7259 return rc;
7260 }
7261 else if (rc == VINF_EM_RAW_GUEST_TRAP)
7262 {
7263 pVCpu->hm.s.Event.fPending = false; /* In case it's a contributory or vectoring #PF. */
7264
7265 if (!pSvmTransient->fVectoringDoublePF)
7266 {
7267 /* It's a guest page fault and needs to be reflected to the guest. */
7268 u32ErrCode = TRPMGetErrorCode(pVCpu); /* The error code might have been changed. */
7269 TRPMResetTrap(pVCpu);
7270 hmR0SvmSetPendingXcptPF(pVCpu, pCtx, u32ErrCode, uFaultAddress);
7271 }
7272 else
7273 {
7274 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */
7275 TRPMResetTrap(pVCpu);
7276 hmR0SvmSetPendingXcptDF(pVCpu);
7277 Log4(("#PF: Pending #DF due to vectoring #PF\n"));
7278 }
7279
7280 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF);
7281 return VINF_SUCCESS;
7282 }
7283
7284 TRPMResetTrap(pVCpu);
7285 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowPFEM);
7286 return rc;
7287}
7288
7289
7290/**
7291 * \#VMEXIT handler for device-not-available exceptions (SVM_EXIT_EXCEPTION_7).
7292 * Conditional \#VMEXIT.
7293 */
7294HMSVM_EXIT_DECL hmR0SvmExitXcptNM(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7295{
7296 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7297
7298 /* Paranoia; Ensure we cannot be called as a result of event delivery. */
7299 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
7300 Assert(!pVmcb->ctrl.ExitIntInfo.n.u1Valid); NOREF(pVmcb);
7301
7302 /* We're playing with the host CPU state here, make sure we don't preempt or longjmp. */
7303 VMMRZCallRing3Disable(pVCpu);
7304 HM_DISABLE_PREEMPT();
7305
7306 int rc;
7307 /* If the guest FPU was active at the time of the #NM exit, then it's a guest fault. */
7308 if (pSvmTransient->fWasGuestFPUStateActive)
7309 {
7310 rc = VINF_EM_RAW_GUEST_TRAP;
7311 Assert(CPUMIsGuestFPUStateActive(pVCpu) || HMCPU_CF_IS_PENDING(pVCpu, HM_CHANGED_GUEST_CR0));
7312 }
7313 else
7314 {
7315#ifndef HMSVM_ALWAYS_TRAP_ALL_XCPTS
7316 Assert(!pSvmTransient->fWasGuestFPUStateActive);
7317#endif
7318 rc = CPUMR0Trap07Handler(pVCpu->CTX_SUFF(pVM), pVCpu); /* (No need to set HM_CHANGED_HOST_CONTEXT for SVM.) */
7319 Assert( rc == VINF_EM_RAW_GUEST_TRAP
7320 || ((rc == VINF_SUCCESS || rc == VINF_CPUM_HOST_CR0_MODIFIED) && CPUMIsGuestFPUStateActive(pVCpu)));
7321 }
7322
7323 HM_RESTORE_PREEMPT();
7324 VMMRZCallRing3Enable(pVCpu);
7325
7326 if (rc == VINF_SUCCESS || rc == VINF_CPUM_HOST_CR0_MODIFIED)
7327 {
7328 /* Guest FPU state was activated, we'll want to change CR0 FPU intercepts before the next VM-reentry. */
7329 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
7330 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitShadowNM);
7331 pVCpu->hm.s.fPreloadGuestFpu = true;
7332 }
7333 else
7334 {
7335 /* Forward #NM to the guest. */
7336 Assert(rc == VINF_EM_RAW_GUEST_TRAP);
7337 hmR0SvmSetPendingXcptNM(pVCpu);
7338 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestNM);
7339 }
7340 return VINF_SUCCESS;
7341}
7342
7343
7344/**
7345 * \#VMEXIT handler for undefined opcode (SVM_EXIT_EXCEPTION_6).
7346 * Conditional \#VMEXIT.
7347 */
7348HMSVM_EXIT_DECL hmR0SvmExitXcptUD(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7349{
7350 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7351
7352 /* Paranoia; Ensure we cannot be called as a result of event delivery. */
7353 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
7354 Assert(!pVmcb->ctrl.ExitIntInfo.n.u1Valid); NOREF(pVmcb);
7355
7356 int rc = VERR_SVM_UNEXPECTED_XCPT_EXIT;
7357 if (pVCpu->hm.s.fGIMTrapXcptUD)
7358 {
7359 uint8_t cbInstr = 0;
7360 VBOXSTRICTRC rcStrict = GIMXcptUD(pVCpu, pCtx, NULL /* pDis */, &cbInstr);
7361 if (rcStrict == VINF_SUCCESS)
7362 {
7363 /* #UD #VMEXIT does not have valid NRIP information, manually advance RIP. See @bugref{7270#c170}. */
7364 hmR0SvmAdvanceRipDumb(pVCpu, pCtx, cbInstr);
7365 rc = VINF_SUCCESS;
7366 HMSVM_CHECK_SINGLE_STEP(pVCpu, rc);
7367 }
7368 else if (rcStrict == VINF_GIM_HYPERCALL_CONTINUING)
7369 rc = VINF_SUCCESS;
7370 else if (rcStrict == VINF_GIM_R3_HYPERCALL)
7371 rc = VINF_GIM_R3_HYPERCALL;
7372 else
7373 Assert(RT_FAILURE(VBOXSTRICTRC_VAL(rcStrict)));
7374 }
7375
7376 /* If the GIM #UD exception handler didn't succeed for some reason or wasn't needed, raise #UD. */
7377 if (RT_FAILURE(rc))
7378 {
7379 hmR0SvmSetPendingXcptUD(pVCpu);
7380 rc = VINF_SUCCESS;
7381 }
7382
7383 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestUD);
7384 return rc;
7385}
7386
7387
7388/**
7389 * \#VMEXIT handler for math-fault exceptions (SVM_EXIT_EXCEPTION_16).
7390 * Conditional \#VMEXIT.
7391 */
7392HMSVM_EXIT_DECL hmR0SvmExitXcptMF(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7393{
7394 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7395
7396 /* Paranoia; Ensure we cannot be called as a result of event delivery. */
7397 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
7398 Assert(!pVmcb->ctrl.ExitIntInfo.n.u1Valid); NOREF(pVmcb);
7399
7400 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestMF);
7401
7402 if (!(pCtx->cr0 & X86_CR0_NE))
7403 {
7404 PVM pVM = pVCpu->CTX_SUFF(pVM);
7405 PDISSTATE pDis = &pVCpu->hm.s.DisState;
7406 unsigned cbOp;
7407 int rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, &cbOp);
7408 if (RT_SUCCESS(rc))
7409 {
7410 /* Convert a #MF into a FERR -> IRQ 13. See @bugref{6117}. */
7411 rc = PDMIsaSetIrq(pVCpu->CTX_SUFF(pVM), 13, 1, 0 /* uTagSrc */);
7412 if (RT_SUCCESS(rc))
7413 pCtx->rip += cbOp;
7414 }
7415 else
7416 Log4(("hmR0SvmExitXcptMF: EMInterpretDisasCurrent returned %Rrc uOpCode=%#x\n", rc, pDis->pCurInstr->uOpcode));
7417 return rc;
7418 }
7419
7420 hmR0SvmSetPendingXcptMF(pVCpu);
7421 return VINF_SUCCESS;
7422}
7423
7424
7425/**
7426 * \#VMEXIT handler for debug exceptions (SVM_EXIT_EXCEPTION_1). Conditional
7427 * \#VMEXIT.
7428 */
7429HMSVM_EXIT_DECL hmR0SvmExitXcptDB(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7430{
7431 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7432
7433 /* If this #DB is the result of delivering an event, go back to the interpreter. */
7434 HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
7435 if (RT_UNLIKELY(pVCpu->hm.s.Event.fPending))
7436 {
7437 STAM_COUNTER_INC(&pVCpu->hm.s.StatInjectPendingInterpret);
7438 return VINF_EM_RAW_INJECT_TRPM_EVENT;
7439 }
7440
7441 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestDB);
7442
7443 /* This can be a fault-type #DB (instruction breakpoint) or a trap-type #DB (data breakpoint). However, for both cases
7444 DR6 and DR7 are updated to what the exception handler expects. See AMD spec. 15.12.2 "#DB (Debug)". */
7445 PVM pVM = pVCpu->CTX_SUFF(pVM);
7446 PSVMVMCB pVmcb = pVCpu->hm.s.svm.pVmcb;
7447 int rc = DBGFRZTrap01Handler(pVM, pVCpu, CPUMCTX2CORE(pCtx), pVmcb->guest.u64DR6, pVCpu->hm.s.fSingleInstruction);
7448 if (rc == VINF_EM_RAW_GUEST_TRAP)
7449 {
7450 Log5(("hmR0SvmExitXcptDB: DR6=%#RX64 -> guest trap\n", pVmcb->guest.u64DR6));
7451 if (CPUMIsHyperDebugStateActive(pVCpu))
7452 CPUMSetGuestDR6(pVCpu, CPUMGetGuestDR6(pVCpu) | pVmcb->guest.u64DR6);
7453
7454 /* Reflect the exception back to the guest. */
7455 hmR0SvmSetPendingXcptDB(pVCpu);
7456 rc = VINF_SUCCESS;
7457 }
7458
7459 /*
7460 * Update DR6.
7461 */
7462 if (CPUMIsHyperDebugStateActive(pVCpu))
7463 {
7464 Log5(("hmR0SvmExitXcptDB: DR6=%#RX64 -> %Rrc\n", pVmcb->guest.u64DR6, rc));
7465 pVmcb->guest.u64DR6 = X86_DR6_INIT_VAL;
7466 pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DRX;
7467 }
7468 else
7469 {
7470 AssertMsg(rc == VINF_SUCCESS, ("rc=%Rrc\n", rc));
7471 Assert(!pVCpu->hm.s.fSingleInstruction && !DBGFIsStepping(pVCpu));
7472 }
7473
7474 return rc;
7475}
7476
7477
7478/**
7479 * \#VMEXIT handler for alignment check exceptions (SVM_EXIT_EXCEPTION_17).
7480 * Conditional \#VMEXIT.
7481 */
7482HMSVM_EXIT_DECL hmR0SvmExitXcptAC(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7483{
7484 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7485
7486 HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
7487
7488 SVMEVENT Event;
7489 Event.u = 0;
7490 Event.n.u1Valid = 1;
7491 Event.n.u3Type = SVM_EVENT_EXCEPTION;
7492 Event.n.u8Vector = X86_XCPT_AC;
7493 Event.n.u1ErrorCodeValid = 1;
7494 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
7495 return VINF_SUCCESS;
7496}
7497
7498
7499/**
7500 * \#VMEXIT handler for breakpoint exceptions (SVM_EXIT_EXCEPTION_3).
7501 * Conditional \#VMEXIT.
7502 */
7503HMSVM_EXIT_DECL hmR0SvmExitXcptBP(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7504{
7505 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7506
7507 HMSVM_CHECK_EXIT_DUE_TO_EVENT_DELIVERY();
7508
7509 int rc = DBGFRZTrap03Handler(pVCpu->CTX_SUFF(pVM), pVCpu, CPUMCTX2CORE(pCtx));
7510 if (rc == VINF_EM_RAW_GUEST_TRAP)
7511 {
7512 SVMEVENT Event;
7513 Event.u = 0;
7514 Event.n.u1Valid = 1;
7515 Event.n.u3Type = SVM_EVENT_EXCEPTION;
7516 Event.n.u8Vector = X86_XCPT_BP;
7517 Event.n.u1ErrorCodeValid = 0;
7518 hmR0SvmSetPendingEvent(pVCpu, &Event, 0 /* GCPtrFaultAddress */);
7519 }
7520
7521 Assert(rc == VINF_SUCCESS || rc == VINF_EM_RAW_GUEST_TRAP || rc == VINF_EM_DBG_BREAKPOINT);
7522 return rc;
7523}
7524
7525
7526#ifdef VBOX_WITH_NESTED_HWVIRT
7527/**
7528 * \#VMEXIT handler for CLGI (SVM_EXIT_CLGI). Conditional \#VMEXIT.
7529 */
7530HMSVM_EXIT_DECL hmR0SvmExitClgi(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7531{
7532 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7533 /** @todo Stat. */
7534 /* STAM_COUNTER_INC(&pVCpu->hm.s.StatExitClgi); */
7535 uint8_t const cbInstr = hmR0SvmGetInstrLengthHwAssist(pVCpu, pCtx, 3);
7536 VBOXSTRICTRC rcStrict = IEMExecDecodedClgi(pVCpu, cbInstr);
7537 return VBOXSTRICTRC_VAL(rcStrict);
7538}
7539
7540
7541/**
7542 * \#VMEXIT handler for STGI (SVM_EXIT_STGI). Conditional \#VMEXIT.
7543 */
7544HMSVM_EXIT_DECL hmR0SvmExitStgi(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7545{
7546 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7547 /** @todo Stat. */
7548 /* STAM_COUNTER_INC(&pVCpu->hm.s.StatExitStgi); */
7549 uint8_t const cbInstr = hmR0SvmGetInstrLengthHwAssist(pVCpu, pCtx, 3);
7550 VBOXSTRICTRC rcStrict = IEMExecDecodedStgi(pVCpu, cbInstr);
7551 return VBOXSTRICTRC_VAL(rcStrict);
7552}
7553
7554
7555/**
7556 * \#VMEXIT handler for VMLOAD (SVM_EXIT_VMLOAD). Conditional \#VMEXIT.
7557 */
7558HMSVM_EXIT_DECL hmR0SvmExitVmload(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7559{
7560 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7561 /** @todo Stat. */
7562 /* STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmload); */
7563 uint8_t const cbInstr = hmR0SvmGetInstrLengthHwAssist(pVCpu, pCtx, 3);
7564 VBOXSTRICTRC rcStrict = IEMExecDecodedVmload(pVCpu, cbInstr);
7565 return VBOXSTRICTRC_VAL(rcStrict);
7566}
7567
7568
7569/**
7570 * \#VMEXIT handler for VMSAVE (SVM_EXIT_VMSAVE). Conditional \#VMEXIT.
7571 */
7572HMSVM_EXIT_DECL hmR0SvmExitVmsave(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7573{
7574 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7575 /** @todo Stat. */
7576 /* STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmsave); */
7577 uint8_t const cbInstr = hmR0SvmGetInstrLengthHwAssist(pVCpu, pCtx, 3);
7578 VBOXSTRICTRC rcStrict = IEMExecDecodedVmsave(pVCpu, cbInstr);
7579 return VBOXSTRICTRC_VAL(rcStrict);
7580}
7581
7582
7583/**
7584 * \#VMEXIT handler for INVLPGA (SVM_EXIT_INVLPGA). Conditional \#VMEXIT.
7585 */
7586HMSVM_EXIT_DECL hmR0SvmExitInvlpga(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7587{
7588 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7589 /** @todo Stat. */
7590 /* STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInvlpga); */
7591 uint8_t const cbInstr = hmR0SvmGetInstrLengthHwAssist(pVCpu, pCtx, 3);
7592 VBOXSTRICTRC rcStrict = IEMExecDecodedInvlpga(pVCpu, cbInstr);
7593 return VBOXSTRICTRC_VAL(rcStrict);
7594}
7595
7596
7597/**
7598 * \#VMEXIT handler for STGI (SVM_EXIT_VMRUN). Conditional \#VMEXIT.
7599 */
7600HMSVM_EXIT_DECL hmR0SvmExitVmrun(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7601{
7602 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7603 /** @todo Stat. */
7604 /* STAM_COUNTER_INC(&pVCpu->hm.s.StatExitVmrun); */
7605 VBOXSTRICTRC rcStrict;
7606 uint8_t const cbInstr = hmR0SvmGetInstrLengthHwAssist(pVCpu, pCtx, 3);
7607#if defined(VBOX_WITH_NESTED_HWVIRT) && defined(VBOX_WITH_NESTED_HWVIRT_ONLY_IN_IEM)
7608 rcStrict = IEMExecDecodedVmrun(pVCpu, cbInstr);
7609#else
7610 rcStrict = hmR0SvmExecVmrun(pVCpu, pCtx, pCtx->rax, cbInstr);
7611 if (rcStrict == VINF_SUCCESS)
7612 rcStrict = VINF_SVM_VMRUN;
7613#endif
7614 return VBOXSTRICTRC_VAL(rcStrict);
7615}
7616
7617/**
7618 * Nested-guest \#VMEXIT handler for IRET (SVM_EXIT_VMRUN). Conditional \#VMEXIT.
7619 */
7620HMSVM_EXIT_DECL hmR0SvmNestedExitIret(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7621{
7622 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7623
7624 /* Clear NMI blocking. */
7625 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_BLOCK_NMIS);
7626
7627 /* Indicate that we no longer need to #VMEXIT when the guest is ready to receive NMIs, it is now ready. */
7628 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
7629 hmR0SvmClearIretIntercept(pVmcbNstGst);
7630
7631 /* Deliver the pending NMI via hmR0SvmEvaluatePendingEventNested() and resume guest execution. */
7632 return VINF_SUCCESS;
7633}
7634
7635
7636/**
7637 * \#VMEXIT handler for virtual interrupt (SVM_EXIT_VINTR). Conditional
7638 * \#VMEXIT.
7639 */
7640HMSVM_EXIT_DECL hmR0SvmNestedExitVIntr(PVMCPU pVCpu, PCPUMCTX pCtx, PSVMTRANSIENT pSvmTransient)
7641{
7642 HMSVM_VALIDATE_EXIT_HANDLER_PARAMS();
7643
7644 /* No virtual interrupts pending, we'll inject the current one/NMI before reentry. */
7645 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
7646 pVmcbNstGst->ctrl.IntCtrl.n.u1VIrqPending = 0;
7647 pVmcbNstGst->ctrl.IntCtrl.n.u8VIntrVector = 0;
7648
7649 /* Indicate that we no longer need to #VMEXIT when the nested-guest is ready to receive interrupts/NMIs, it is now ready. */
7650 pVmcbNstGst->ctrl.u64InterceptCtrl &= ~SVM_CTRL_INTERCEPT_VINTR;
7651 pVmcbNstGst->ctrl.u64VmcbCleanBits &= ~(HMSVM_VMCB_CLEAN_INTERCEPTS | HMSVM_VMCB_CLEAN_TPR);
7652
7653 /* Deliver the pending interrupt/NMI via hmR0SvmEvaluatePendingEventNested() and resume guest execution. */
7654 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIntWindow);
7655 return VINF_SUCCESS;
7656}
7657
7658#endif /* VBOX_WITH_NESTED_HWVIRT */
7659
7660
7661/** @} */
7662
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