VirtualBox

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

Last change on this file since 73144 was 73144, checked in by vboxsync, 6 years ago

VMM/HMSVMR0: LogRel nit.

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

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