VirtualBox

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

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

VMM/HMSVMR0: Comment.

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

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