VirtualBox

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

Last change on this file since 46470 was 46470, checked in by vboxsync, 12 years ago

VMM/HMSVMR0: AMD-V bits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.1 KB
Line 
1/* $Id: HMSVMR0.cpp 46470 2013-06-10 15:14:27Z vboxsync $ */
2/** @file
3 * HM SVM (AMD-V) - Host Context Ring-0.
4 */
5
6/*
7 * Copyright (C) 2013 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* Header Files *
20*******************************************************************************/
21
22#ifdef DEBUG_ramshankar
23# define HMSVM_ALWAYS_TRAP_ALL_XCPTS
24# define HMSVM_ALWAYS_TRAP_PF
25#endif
26
27
28/*******************************************************************************
29* Defined Constants And Macros *
30*******************************************************************************/
31/** @name Segment attribute conversion between CPU and AMD-V VMCB format.
32 *
33 * The CPU format of the segment attribute is described in X86DESCATTRBITS
34 * which is 16-bits (i.e. includes 4 bits of the segment limit).
35 *
36 * The AMD-V VMCB format the segment attribute is compact 12-bits (strictly
37 * only the attribute bits and nothing else). Upper 4-bits are unused.
38 *
39 * @{ */
40#define HMSVM_CPU_2_VMCB_SEG_ATTR(a) (a & 0xff) | ((a & 0xf000) >> 4)
41#define HMSVM_VMCB_2_CPU_SEG_ATTR(a) (a & 0xff) | ((a & 0x0f00) << 4)
42/** @} */
43
44/** @name Macros for loading, storing segment registers to/from the VMCB.
45 * @{ */
46#define HMSVM_LOAD_SEG_REG(REG, reg) \
47 do \
48 { \
49 Assert(pCtx->reg.fFlags & CPUMSELREG_FLAGS_VALID); \
50 Assert(pCtx->reg.ValidSel == pCtx->reg.Sel); \
51 pVmcb->guest.REG.u16Sel = pCtx->reg.Sel; \
52 pVmcb->guest.REG.u32Limit = pCtx->reg.u32Limit; \
53 pVmcb->guest.REG.u64Base = pCtx->reg.u64Base; \
54 pVmcb->guest.REG.u16Attr = HMSVM_CPU_2_VMCB_SEG_ATTR(pCtx->reg.Attr.u); \
55 } while (0)
56
57#define HMSVM_SAVE_SEG_REG(REG, reg) \
58 do \
59 { \
60 pCtx->reg.Sel = pVmcb->guest.REG.u16Sel; \
61 pCtx->reg.ValidSel = pVmcb->guest.REG.u16Sel; \
62 pCtx->reg.fFlags = CPUMSELREG_FLAGS_VALID; \
63 pCtx->reg.u32Limit = pVmcb->guest.REG.u32Limit; \
64 pCtx->reg.u64Base = pVmcb->guest.REG.u64Base; \
65 pCtx->reg.Attr.u = HMSVM_VMCB_2_CPU_SEG_ATTR(pVmcb->guest.REG.u16Attr); \
66 } while (0)
67/** @} */
68
69/** @name VMCB Clean Bits used for VMCB-state caching. */
70/** All intercepts vectors, TSC offset, PAUSE filter counter. */
71#define HMSVM_VMCB_CLEAN_INTERCEPTS RT_BIT(0)
72/** I/O permission bitmap, MSR permission bitmap. */
73#define HMSVM_VMCB_CLEAN_IOPM_MSRPM RT_BIT(1)
74/** ASID. */
75#define HMSVM_VMCB_CLEAN_ASID RT_BIT(2)
76/** TRP: V_TPR, V_IRQ, V_INTR_PRIO, V_IGN_TPR, V_INTR_MASKING,
77V_INTR_VECTOR. */
78#define HMSVM_VMCB_CLEAN_TPR RT_BIT(3)
79/** Nested Paging: Nested CR3 (nCR3), PAT. */
80#define HMSVM_VMCB_CLEAN_NP RT_BIT(4)
81/** Control registers (CR0, CR3, CR4, EFER). */
82#define HMSVM_VMCB_CLEAN_CRX RT_BIT(5)
83/** Debug registers (DR6, DR7). */
84#define HMSVM_VMCB_CLEAN_DRX RT_BIT(6)
85/** GDT, IDT limit and base. */
86#define HMSVM_VMCB_CLEAN_DT RT_BIT(7)
87/** Segment register: CS, SS, DS, ES limit and base. */
88#define HMSVM_VMCB_CLEAN_SEG RT_BIT(8)
89/** CR2.*/
90#define HMSVM_VMCB_CLEAN_CR2 RT_BIT(9)
91/** Last-branch record (DbgCtlMsr, br_from, br_to, lastint_from, lastint_to) */
92#define HMSVM_VMCB_CLEAN_LBR RT_BIT(10)
93/** AVIC (AVIC APIC_BAR; AVIC APIC_BACKING_PAGE, AVIC
94PHYSICAL_TABLE and AVIC LOGICAL_TABLE Pointers). */
95#define HMSVM_VMCB_CLEAN_AVIC RT_BIT(11)
96/** @} */
97
98/**
99 * MSRPM (MSR permission bitmap) read permissions (for guest RDMSR).
100 */
101typedef enum SVMMSREXITREAD
102{
103 /** Reading this MSR causes a VM-exit. */
104 SVMMSREXIT_INTERCEPT_READ = 0xb,
105 /** Reading this MSR does not cause a VM-exit. */
106 SVMMSREXIT_PASSTHRU_READ
107} VMXMSREXITREAD;
108
109/**
110 * MSRPM (MSR permission bitmap) write permissions (for guest WRMSR).
111 */
112typedef enum SVMMSREXITWRITE
113{
114 /** Writing to this MSR causes a VM-exit. */
115 SVMMSREXIT_INTERCEPT_WRITE = 0xd,
116 /** Writing to this MSR does not cause a VM-exit. */
117 SVMMSREXIT_PASSTHRU_WRITE
118} VMXMSREXITWRITE;
119
120
121/*******************************************************************************
122* Internal Functions *
123*******************************************************************************/
124static void hmR0SvmSetMsrPermission(PVMCPU pVCpu, unsigned uMsr, SVMMSREXITREAD enmRead, SVMMSREXITWRITE enmWrite);
125
126
127/*******************************************************************************
128* Global Variables *
129*******************************************************************************/
130/** Ring-0 memory object for the IO bitmap. */
131RTR0MEMOBJ g_hMemObjIOBitmap = NIL_RTR0MEMOBJ;
132/** Physical address of the IO bitmap. */
133RTHCPHYS g_HCPhysIOBitmap = 0;
134/** Virtual address of the IO bitmap. */
135R0PTRTYPE(void *) g_pvIOBitmap = NULL;
136
137
138/**
139 * Sets up and activates AMD-V on the current CPU.
140 *
141 * @returns VBox status code.
142 * @param pCpu Pointer to the CPU info struct.
143 * @param pVM Pointer to the VM (can be NULL after a resume!).
144 * @param pvCpuPage Pointer to the global CPU page.
145 * @param HCPhysCpuPage Physical address of the global CPU page.
146 */
147VMMR0DECL(int) SVMR0EnableCpu(PHMGLOBLCPUINFO pCpu, PVM pVM, void *pvCpuPage, RTHCPHYS HCPhysCpuPage, bool fEnabledByHost)
148{
149 AssertReturn(!fEnabledByHost, VERR_INVALID_PARAMETER);
150 AssertReturn( HCPhysCpuPage
151 && HCPhysCpuPage != NIL_RTHCPHYS, VERR_INVALID_PARAMETER);
152 AssertReturn(pvCpuPage, VERR_INVALID_PARAMETER);
153
154 /*
155 * We must turn on AMD-V and setup the host state physical address, as those MSRs are per CPU.
156 */
157 uint64_t u64HostEfer = ASMRdMsr(MSR_K6_EFER);
158 if (u64HostEfer & MSR_K6_EFER_SVME)
159 {
160 /* If the VBOX_HWVIRTEX_IGNORE_SVM_IN_USE is active, then we blindly use AMD-V. */
161 if ( pVM
162 && pVM->hm.s.svm.fIgnoreInUseError)
163 {
164 pCpu->fIgnoreAMDVInUseError = true;
165 }
166
167 if (!pCpu->fIgnoreAMDVInUseError)
168 return VERR_SVM_IN_USE;
169 }
170
171 /* Turn on AMD-V in the EFER MSR. */
172 ASMWrMsr(MSR_K6_EFER, u64HostEfer | MSR_K6_EFER_SVME);
173
174 /* Write the physical page address where the CPU will store the host state while executing the VM. */
175 ASMWrMsr(MSR_K8_VM_HSAVE_PA, HCPhysCpuPage);
176
177 /*
178 * Theoretically, other hypervisors may have used ASIDs, ideally we should flush all non-zero ASIDs
179 * when enabling SVM. AMD doesn't have an SVM instruction to flush all ASIDs (flushing is done
180 * upon VMRUN). Therefore, just set the fFlushAsidBeforeUse flag which instructs hmR0SvmSetupTLB()
181 * to flush the TLB with before using a new ASID.
182 */
183 pCpu->fFlushAsidBeforeUse = true;
184
185 /*
186 * Ensure each VCPU scheduled on this CPU gets a new VPID on resume. See @bugref{6255}.
187 */
188 ++pCpu->cTlbFlushes;
189
190 return VINF_SUCCESS;
191}
192
193
194/**
195 * Deactivates AMD-V on the current CPU.
196 *
197 * @returns VBox status code.
198 * @param pCpu Pointer to the CPU info struct.
199 * @param pvCpuPage Pointer to the global CPU page.
200 * @param HCPhysCpuPage Physical address of the global CPU page.
201 */
202VMMR0DECL(int) SVMR0DisableCpu(PHMGLOBLCPUINFO pCpu, void *pvCpuPage, RTHCPHYS HCPhysCpuPage)
203{
204 AssertReturn( HCPhysCpuPage
205 && HCPhysCpuPage != NIL_RTHCPHYS, VERR_INVALID_PARAMETER);
206 AssertReturn(pvCpuPage, VERR_INVALID_PARAMETER);
207 NOREF(pCpu);
208
209 /* Turn off AMD-V in the EFER MSR if AMD-V is active. */
210 uint64_t u64HostEfer = ASMRdMsr(MSR_K6_EFER);
211 if (u64HostEfer & MSR_K6_EFER_SVME)
212 {
213 ASMWrMsr(MSR_K6_EFER, u64HostEfer & ~MSR_K6_EFER_SVME);
214
215 /* Invalidate host state physical address. */
216 ASMWrMsr(MSR_K8_VM_HSAVE_PA, 0);
217 }
218
219 return VINF_SUCCESS;
220}
221
222
223/**
224 * Does global AMD-V initialization (called during module initialization).
225 *
226 * @returns VBox status code.
227 */
228VMMR0DECL(int) SVMR0GlobalInit(void)
229{
230 /*
231 * Allocate 12 KB for the IO bitmap. Since this is non-optional and we always intercept all IO accesses, it's done
232 * once globally here instead of per-VM.
233 */
234 int rc = RTR0MemObjAllocCont(&g_hMemObjIOBitmap, 3 << PAGE_SHIFT, false /* fExecutable */);
235 if (RT_FAILURE(rc))
236 return rc;
237
238 g_pvIOBitmap = RTR0MemObjAddress(g_hMemObjIOBitmap);
239 g_HCPhysIOBitmap = RTR0MemObjGetPagePhysAddr(g_hMemObjIOBitmap, 0 /* iPage */);
240
241 /* Set all bits to intercept all IO accesses. */
242 ASMMemFill32(pVM->hm.s.svm.pvIOBitmap, 3 << PAGE_SHIFT, UINT32_C(0xffffffff));
243}
244
245
246/**
247 * Does global VT-x termination (called during module termination).
248 */
249VMMR0DECL(void) SVMR0GlobalTerm(void)
250{
251 if (g_hMemObjIOBitmap != NIL_RTR0MEMOBJ)
252 {
253 RTR0MemObjFree(pVM->hm.s.svm.hMemObjIOBitmap, false /* fFreeMappings */);
254 g_pvIOBitmap = NULL;
255 g_HCPhysIOBitmap = 0;
256 g_hMemObjIOBitmap = NIL_RTR0MEMOBJ;
257 }
258}
259
260
261/**
262 * Frees any allocated per-VCPU structures for a VM.
263 *
264 * @param pVM Pointer to the VM.
265 */
266DECLINLINE(void) hmR0SvmFreeStructs(PVM pVM)
267{
268 for (uint32_t i = 0; i < pVM->cCpus; i++)
269 {
270 PVMCPU pVCpu = &pVM->aCpus[i];
271 AssertPtr(pVCpu);
272
273 if (pVCpu->hm.s.svm.hMemObjVmcbHost != NIL_RTR0MEMOBJ)
274 {
275 RTR0MemObjFree(pVCpu->hm.s.svm.hMemObjVmcbHost, false);
276 pVCpu->hm.s.svm.pvVmcbHost = 0;
277 pVCpu->hm.s.svm.HCPhysVmcbHost = 0;
278 pVCpu->hm.s.svm.hMemObjVmcbHost = NIL_RTR0MEMOBJ;
279 }
280
281 if (pVCpu->hm.s.svm.hMemObjVmcb != NIL_RTR0MEMOBJ)
282 {
283 RTR0MemObjFree(pVCpu->hm.s.svm.hMemObjVmcb, false);
284 pVCpu->hm.s.svm.pvVmcb = 0;
285 pVCpu->hm.s.svm.HCPhysVmcb = 0;
286 pVCpu->hm.s.svm.hMemObjVmcb = NIL_RTR0MEMOBJ;
287 }
288
289 if (pVCpu->hm.s.svm.hMemObjMsrBitmap != NIL_RTR0MEMOBJ)
290 {
291 RTR0MemObjFree(pVCpu->hm.s.svm.hMemObjMsrBitmap, false);
292 pVCpu->hm.s.svm.pvMsrBitmap = 0;
293 pVCpu->hm.s.svm.HCPhysMsrBitmap = 0;
294 pVCpu->hm.s.svm.hMemObjMsrBitmap = NIL_RTR0MEMOBJ;
295 }
296 }
297}
298
299
300/**
301 * Does per-VM AMD-V initialization.
302 *
303 * @returns VBox status code.
304 * @param pVM Pointer to the VM.
305 */
306VMMR0DECL(int) SVMR0InitVM(PVM pVM)
307{
308 int rc = VERR_INTERNAL_ERROR_5;
309
310 /*
311 * Check for an AMD CPU erratum which requires us to flush the TLB before every world-switch.
312 */
313 uint32_t u32Family;
314 uint32_t u32Model;
315 uint32_t u32Stepping;
316 if (HMAmdIsSubjectToErratum170(&u32Family, &u32Model, &u32Stepping))
317 {
318 Log4(("SVMR0InitVM: AMD cpu with erratum 170 family %#x model %#x stepping %#x\n", u32Family, u32Model, u32Stepping));
319 pVM->hm.s.svm.fAlwaysFlushTLB = true;
320 }
321
322 /*
323 * Initialize the R0 memory objects up-front so we can properly cleanup on allocation failures.
324 */
325 for (VMCPUID i = 0; i < pVM->cCpus; i++)
326 {
327 PVMCPU pVCpu = &pVM->aCpus[i];
328 pVCpu->hm.s.svm.hMemObjVmcbHost = NIL_RTR0MEMOBJ;
329 pVCpu->hm.s.svm.hMemObjVmcb = NIL_RTR0MEMOBJ;
330 pVCpu->hm.s.svm.hMemObjMsrBitmap = NIL_RTR0MEMOBJ;
331 }
332
333 for (VMCPUID i = 0; i < pVM->cCpus; i++)
334 {
335 /*
336 * Allocate one page for the host-context VM control block (VMCB). This is used for additional host-state (such as
337 * FS, GS, Kernel GS Base, etc.) apart from the host-state save area specified in MSR_K8_VM_HSAVE_PA.
338 */
339 rc = RTR0MemObjAllocCont(&pVCpu->hm.s.svm.hMemObjVmcbHost, 1 << PAGE_SHIFT, false /* fExecutable */);
340 if (RT_FAILURE(rc))
341 goto failure_cleanup;
342
343 pVCpu->hm.s.svm.pvVmcbHost = RTR0MemObjAddress(pVCpu->hm.s.svm.hMemObjVmcbHost);
344 pVCpu->hm.s.svm.HCPhysVmcbHost = RTR0MemObjGetPagePhysAddr(pVCpu->hm.s.svm.hMemObjVmcbHost, 0 /* iPage */);
345 Assert(pVCpu->hm.s.svm.HCPhysVmcbHost < _4G);
346 ASMMemZeroPage(pVCpu->hm.s.svm.pvVmcbHost);
347
348 /*
349 * Allocate one page for the guest-state VMCB.
350 */
351 rc = RTR0MemObjAllocCont(&pVCpu->hm.s.svm.hMemObjVmcb, 1 << PAGE_SHIFT, false /* fExecutable */);
352 if (RT_FAILURE(rc))
353 goto failure_cleanup;
354
355 pVCpu->hm.s.svm.pvVmcb = RTR0MemObjAddress(pVCpu->hm.s.svm.hMemObjVmcb);
356 pVCpu->hm.s.svm.HCPhysVmcb = RTR0MemObjGetPagePhysAddr(pVCpu->hm.s.svm.hMemObjVmcb, 0 /* iPage */);
357 Assert(pVCpu->hm.s.svm.HCPhysVmcb < _4G);
358 ASMMemZeroPage(pVCpu->hm.s.svm.pvVmcb);
359
360 /*
361 * Allocate two pages (8 KB) for the MSR permission bitmap. There doesn't seem to be a way to convince
362 * SVM to not require one.
363 */
364 rc = RTR0MemObjAllocCont(&pVCpu->hm.s.svm.hMemObjMsrBitmap, 2 << PAGE_SHIFT, false /* fExecutable */);
365 if (RT_FAILURE(rc))
366 failure_cleanup;
367
368 pVCpu->hm.s.svm.pvMsrBitmap = RTR0MemObjAddress(pVCpu->hm.s.svm.hMemObjMsrBitmap);
369 pVCpu->hm.s.svm.HCPhysMsrBitmap = RTR0MemObjGetPagePhysAddr(pVCpu->hm.s.svm.hMemObjMsrBitmap, 0 /* iPage */);
370 /* Set all bits to intercept all MSR accesses (changed later on). */
371 ASMMemFill32(pVCpu->hm.s.svm.pvMsrBitmap, 2 << PAGE_SHIFT, 0xffffffff);
372 }
373
374 return VINF_SUCCESS;
375
376failure_cleanup:
377 hmR0SvmFreeVMStructs(pVM);
378 return rc;
379}
380
381
382/**
383 * Does per-VM AMD-V termination.
384 *
385 * @returns VBox status code.
386 * @param pVM Pointer to the VM.
387 */
388VMMR0DECL(int) SVMR0TermVM(PVM pVM)
389{
390 hmR0SvmFreeVMStructs(pVM);
391 return VINF_SUCCESS;
392}
393
394
395/**
396 * Sets the permission bits for the specified MSR in the MSRPM.
397 *
398 * @param pVCpu Pointer to the VMCPU.
399 * @param uMsr The MSR.
400 * @param fRead Whether reading is allowed.
401 * @param fWrite Whether writing is allowed.
402 */
403static void hmR0SvmSetMsrPermission(PVMCPU pVCpu, uint32_t uMsr, SVMMSREXITREAD enmRead, SVMMSREXITWRITE enmWrite)
404{
405 unsigned ulBit;
406 uint8_t *pbMsrBitmap = (uint8_t *)pVCpu->hm.s.svm.pvMsrBitmap;
407
408 /*
409 * Layout:
410 * Byte offset MSR range
411 * 0x000 - 0x7ff 0x00000000 - 0x00001fff
412 * 0x800 - 0xfff 0xc0000000 - 0xc0001fff
413 * 0x1000 - 0x17ff 0xc0010000 - 0xc0011fff
414 * 0x1800 - 0x1fff Reserved
415 */
416 if (uMsr <= 0x00001FFF)
417 {
418 /* Pentium-compatible MSRs */
419 ulBit = uMsr * 2;
420 }
421 else if ( uMsr >= 0xC0000000
422 && uMsr <= 0xC0001FFF)
423 {
424 /* AMD Sixth Generation x86 Processor MSRs and SYSCALL */
425 ulBit = (uMsr - 0xC0000000) * 2;
426 pbMsrBitmap += 0x800;
427 }
428 else if ( uMsr >= 0xC0010000
429 && uMsr <= 0xC0011FFF)
430 {
431 /* AMD Seventh and Eighth Generation Processor MSRs */
432 ulBit = (uMsr - 0xC0001000) * 2;
433 pbMsrBitmap += 0x1000;
434 }
435 else
436 {
437 AssertFailed();
438 return;
439 }
440
441 Assert(ulBit < 0x3fff /* 16 * 1024 - 1 */);
442 if (enmRead == SVMMSREXIT_INTERCEPT_READ)
443 ASMBitSet(pbMsrBitmap, ulBit);
444 else
445 ASMBitClear(pbMsrBitmap, ulBit);
446
447 if (enmWrite == SVMMSREXIT_INTERCEPT_WRITE)
448 ASMBitSet(pbMsrBitmap, ulBit + 1);
449 else
450 ASMBitClear(pbMsrBitmap, ulBit + 1);
451}
452
453
454/**
455 * Sets up AMD-V for the specified VM.
456 * This function is only called once per-VM during initalization.
457 *
458 * @returns VBox status code.
459 * @param pVM Pointer to the VM.
460 */
461VMMR0DECL(int) SVMR0SetupVM(PVM pVM)
462{
463 int rc = VINF_SUCCESS;
464
465 AssertReturn(pVM, VERR_INVALID_PARAMETER);
466 Assert(pVM->hm.s.svm.fSupported);
467
468 for (VMCPUID i = 0; i < pVM->cCpus; i++)
469 {
470 PVMCPU pVCpu = &pVM->aCpus[i];
471 PSVMVMCB pVmcb = (PSVMVMCB)pVM->aCpus[i].hm.s.svm.pvVmcbGuest;
472
473 AssertMsgReturn(pVmcb, ("Invalid pVmcb\n"), VERR_SVM_INVALID_PVMCB);
474
475 /* Trap exceptions unconditionally (debug purposes). */
476#ifdef HMSVM_ALWAYS_TRAP_PF
477 pVmcb->ctrl.u32InterceptException |= RT_BIT(X86_XCPT_PF);
478#endif
479#ifdef HMSVM_ALWAYS_TRAP_ALL_XCPTS
480 pVmcb->ctrl.u32InterceptException |= RT_BIT(X86_XCPT_BP)
481 | RT_BIT(X86_XCPT_DB)
482 | RT_BIT(X86_XCPT_DE)
483 | RT_BIT(X86_XCPT_NM)
484 | RT_BIT(X86_XCPT_UD)
485 | RT_BIT(X86_XCPT_NP)
486 | RT_BIT(X86_XCPT_SS)
487 | RT_BIT(X86_XCPT_GP)
488 | RT_BIT(X86_XCPT_PF)
489 | RT_BIT(X86_XCPT_MF);
490#endif
491
492 /* Set up unconditional intercepts and conditions. */
493 pVmcb->ctrl.u32InterceptCtrl1 = SVM_CTRL1_INTERCEPT_INTR /* External interrupt causes a VM-exit. */
494 | SVM_CTRL1_INTERCEPT_VINTR /* When guest enabled interrupts cause a VM-exit. */
495 | SVM_CTRL1_INTERCEPT_NMI /* Non-Maskable Interrupts causes a VM-exit. */
496 | SVM_CTRL1_INTERCEPT_SMI /* System Management Interrupt cause a VM-exit. */
497 | SVM_CTRL1_INTERCEPT_INIT /* INIT signal causes a VM-exit. */
498 | SVM_CTRL1_INTERCEPT_RDPMC /* RDPMC causes a VM-exit. */
499 | SVM_CTRL1_INTERCEPT_CPUID /* CPUID causes a VM-exit. */
500 | SVM_CTRL1_INTERCEPT_RSM /* RSM causes a VM-exit. */
501 | SVM_CTRL1_INTERCEPT_HLT /* HLT causes a VM-exit. */
502 | SVM_CTRL1_INTERCEPT_INOUT_BITMAP /* Use the IOPM to cause IOIO VM-exits. */
503 | SVM_CTRL1_INTERCEPT_MSR_SHADOW /* MSR access not covered by MSRPM causes a VM-exit.*/
504 | SVM_CTRL1_INTERCEPT_INVLPGA /* INVLPGA causes a VM-exit. */
505 | SVM_CTRL1_INTERCEPT_SHUTDOWN /* Shutdown events causes a VM-exit. */
506 | SVM_CTRL1_INTERCEPT_FERR_FREEZE; /* Intercept "freezing" during legacy FPU handling. */
507
508 pVmcb->ctrl.u32InterceptCtrl2 = SVM_CTRL2_INTERCEPT_VMRUN /* VMRUN causes a VM-exit. */
509 | SVM_CTRL2_INTERCEPT_VMMCALL /* VMMCALL causes a VM-exit. */
510 | SVM_CTRL2_INTERCEPT_VMLOAD /* VMLOAD causes a VM-exit. */
511 | SVM_CTRL2_INTERCEPT_VMSAVE /* VMSAVE causes a VM-exit. */
512 | SVM_CTRL2_INTERCEPT_STGI /* STGI causes a VM-exit. */
513 | SVM_CTRL2_INTERCEPT_CLGI /* CLGI causes a VM-exit. */
514 | SVM_CTRL2_INTERCEPT_SKINIT /* SKINIT causes a VM-exit. */
515 | SVM_CTRL2_INTERCEPT_WBINVD /* WBINVD causes a VM-exit. */
516 | SVM_CTRL2_INTERCEPT_MONITOR /* MONITOR causes a VM-exit. */
517 | SVM_CTRL2_INTERCEPT_MWAIT_UNCOND; /* MWAIT causes a VM-exit. */
518
519 /* CR0, CR4 reads must be intercepted, our shadow values are not necessarily the same as the guest's. */
520 pVmcb->ctrl.u16InterceptRdCRx = RT_BIT(0) | RT_BIT(4);
521
522 /* CR0, CR4 writes must be intercepted for obvious reasons. */
523 pVmcb->ctrl.u16InterceptWrCRx = RT_BIT(0) | RT_BIT(4);
524
525 /* Intercept all DRx reads and writes by default. Changed later on. */
526 pVmcb->ctrl.u16InterceptRdDRx = 0xffff;
527 pVmcb->ctrl.u16InterceptWrDRx = 0xffff;
528
529 /* Virtualize masking of INTR interrupts. (reads/writes from/to CR8 go to the V_TPR register) */
530 pVmcb->ctrl.IntCtrl.n.u1VIrqMasking = 1;
531
532 /* Ignore the priority in the TPR; just deliver it to the guest when we tell it to. */
533 pVmcb->ctrl.IntCtrl.n.u1IgnoreTPR = 1;
534
535 /* Set IO and MSR bitmap permission bitmap physical addresses. */
536 pVmcb->ctrl.u64IOPMPhysAddr = g_HCPhysIOBitmap;
537 pVmcb->ctrl.u64MSRPMPhysAddr = pVCpu->hm.s.svm.HCPhysMsrBitmap;
538
539 /* No LBR virtualization. */
540 pVmcb->ctrl.u64LBRVirt = 0;
541
542 /* The ASID must start at 1; the host uses 0. */
543 pVmcb->ctrl.TLBCtrl.n.u32ASID = 1;
544
545 /*
546 * Setup the PAT MSR (applicable for Nested Paging only).
547 * The default value should be 0x0007040600070406ULL, but we want to treat all guest memory as WB,
548 * so choose type 6 for all PAT slots.
549 */
550 pVmcb->guest.u64GPAT = UINT64_C(0x0006060606060606);
551
552 /* Without Nested Paging, we need additionally intercepts. */
553 if (!pVM->hm.s.fNestedPaging)
554 {
555 /* CR3 reads/writes must be intercepted; our shadow values differ from the guest values. */
556 pVmcb->ctrl.u16InterceptRdCRx |= RT_BIT(3);
557 pVmcb->ctrl.u16InterceptWrCRx |= RT_BIT(3);
558
559 /* Intercept INVLPG and task switches (may change CR3, EFLAGS, LDT). */
560 pVmcb->ctrl.u32InterceptCtrl1 |= SVM_CTRL1_INTERCEPT_INVLPG
561 | SVM_CTRL1_INTERCEPT_TASK_SWITCH;
562
563 /* Page faults must be intercepted to implement shadow paging. */
564 pVmcb->ctrl.u32InterceptException |= RT_BIT(X86_XCPT_PF);
565 }
566
567 /*
568 * The following MSRs are saved/restored automatically during the world-switch.
569 * Don't intercept guest read/write accesses to these MSRs.
570 */
571 hmR0SvmSetMsrPermission(pVCpu, MSR_K8_LSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
572 hmR0SvmSetMsrPermission(pVCpu, MSR_K8_CSTAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
573 hmR0SvmSetMsrPermission(pVCpu, MSR_K6_STAR, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
574 hmR0SvmSetMsrPermission(pVCpu, MSR_K8_SF_MASK, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
575 hmR0SvmSetMsrPermission(pVCpu, MSR_K8_FS_BASE, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
576 hmR0SvmSetMsrPermission(pVCpu, MSR_K8_GS_BASE, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
577 hmR0SvmSetMsrPermission(pVCpu, MSR_K8_KERNEL_GS_BASE, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
578 hmR0SvmSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_CS, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
579 hmR0SvmSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_ESP, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
580 hmR0SvmSetMsrPermission(pVCpu, MSR_IA32_SYSENTER_EIP, SVMMSREXIT_PASSTHRU_READ, SVMMSREXIT_PASSTHRU_WRITE);
581 }
582
583 return rc;
584}
585
586
587/**
588 * Flushes the appropriate tagged-TLB entries.
589 *
590 * @param pVM Pointer to the VM.
591 * @param pVCpu Pointer to the VMCPU.
592 */
593static void hmR0SvmFlushTaggedTlb(PVMCPU pVCpu)
594{
595 PVM pVM = pVCpu->CTX_SUFF(pVM);
596 PSVMVMCB pVmcb = (PSVMVMCB)pVCpu->hm.s.svm.pvVmcbGuest;
597 PHMGLOBLCPUINFO pCpu = HMR0GetCurrentCpu();
598
599 /*
600 * Force a TLB flush for the first world switch if the current CPU differs from the one we ran on last.
601 * This can happen both for start & resume due to long jumps back to ring-3.
602 * If the TLB flush count changed, another VM (VCPU rather) has hit the ASID limit while flushing the TLB,
603 * so we cannot reuse the ASIDs without flushing.
604 */
605 bool fNewAsid = false;
606 if ( pVCpu->hm.s.idLastCpu != pCpu->idCpu
607 || pVCpu->hm.s.cTlbFlushes != pCpu->cTlbFlushes)
608 {
609 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlbWorldSwitch);
610 pVCpu->hm.s.fForceTLBFlush = true;
611 fNewAsid = true;
612 }
613
614 /* Set TLB flush state as checked until we return from the world switch. */
615 ASMAtomicWriteBool(&pVCpu->hm.s.fCheckedTLBFlush, true);
616
617 /* Check for explicit TLB shootdowns. */
618 if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH))
619 {
620 pVCpu->hm.s.fForceTLBFlush = true;
621 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushTlb);
622 }
623
624 pVCpu->hm.s.idLastCpu = pCpu->idCpu;
625 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_NOTHING;
626
627 if (pVM->hm.s.svm.fAlwaysFlushTLB)
628 {
629 /*
630 * This is the AMD erratum 170. We need to flush the entire TLB for each world switch. Sad.
631 */
632 pCpu->uCurrentAsid = 1;
633 pVCpu->hm.s.uCurrentAsid = 1;
634 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
635 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
636 }
637 else if (pVCpu->hm.s.fForceTLBFlush)
638 {
639 if (fNewAsid)
640 {
641 ++pCpu->uCurrentAsid;
642 bool fHitASIDLimit = false;
643 if (pCpu->uCurrentAsid >= pVM->hm.s.uMaxAsid)
644 {
645 pCpu->uCurrentAsid = 1; /* Wraparound at 1; host uses 0 */
646 pCpu->cTlbFlushes++; /* All VCPUs that run on this host CPU must use a new VPID. */
647 fHitASIDLimit = true;
648
649 if (pVM->hm.s.svm.u32Features & AMD_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
650 {
651 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
652 pCpu->fFlushAsidBeforeUse = true;
653 }
654 else
655 {
656 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
657 pCpu->fFlushAsidBeforeUse = false;
658 }
659 }
660
661 if ( !fHitASIDLimit
662 && pCpu->fFlushAsidBeforeUse)
663 {
664 if (pVM->hm.s.svm.u32Features & AMD_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
665 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
666 else
667 {
668 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
669 pCpu->fFlushAsidBeforeUse = false;
670 }
671 }
672
673 pVCpu->hm.s.uCurrentAsid = pCpu->uCurrentAsid;
674 pVCpu->hm.s.cTlbFlushes = pCpu->cTlbFlushes;
675 }
676 else
677 {
678 if (pVM->hm.s.svm.u32Features & AMD_CPUID_SVM_FEATURE_EDX_FLUSH_BY_ASID)
679 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_SINGLE_CONTEXT;
680 else
681 pVmcb->ctrl.TLBCtrl.n.u8TLBFlush = SVM_TLB_FLUSH_ENTIRE;
682 }
683
684 pVCpu->hm.s.fForceTLBFlush = false;
685 }
686 else
687 {
688 /** @todo We never set VMCPU_FF_TLB_SHOOTDOWN anywhere so this path should
689 * not be executed. See hmQueueInvlPage() where it is commented
690 * out. Support individual entry flushing someday. */
691 if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TLB_SHOOTDOWN))
692 {
693 /* Deal with pending TLB shootdown actions which were queued when we were not executing code. */
694 STAM_COUNTER_INC(&pVCpu->hm.s.StatTlbShootdown);
695 for (uint32_t i = 0; i < pVCpu->hm.s.TlbShootdown.cPages; i++)
696 SVMR0InvlpgA(pVCpu->hm.s.TlbShootdown.aPages[i], pVmcb->ctrl.TLBCtrl.n.u32ASID);
697 }
698 }
699
700 pVCpu->hm.s.TlbShootdown.cPages = 0;
701 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
702
703 /* Update VMCB with the ASID. */
704 pVmcb->ctrl.TLBCtrl.n.u32ASID = pVCpu->hm.s.uCurrentAsid;
705
706 AssertMsg(pVCpu->hm.s.cTlbFlushes == pCpu->cTlbFlushes,
707 ("Flush count mismatch for cpu %d (%x vs %x)\n", pCpu->idCpu, pVCpu->hm.s.cTlbFlushes, pCpu->cTlbFlushes));
708 AssertMsg(pCpu->uCurrentAsid >= 1 && pCpu->uCurrentAsid < pVM->hm.s.uMaxAsid,
709 ("cpu%d uCurrentAsid = %x\n", pCpu->idCpu, pCpu->uCurrentAsid));
710 AssertMsg(pVCpu->hm.s.uCurrentAsid >= 1 && pVCpu->hm.s.uCurrentAsid < pVM->hm.s.uMaxAsid,
711 ("cpu%d VM uCurrentAsid = %x\n", pCpu->idCpu, pVCpu->hm.s.uCurrentAsid));
712
713#ifdef VBOX_WITH_STATISTICS
714 if (pVmcb->ctrl.TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_NOTHING)
715 STAM_COUNTER_INC(&pVCpu->hm.s.StatNoFlushTlbWorldSwitch);
716 else if ( pVmcb->ctrl.TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_SINGLE_CONTEXT
717 || pVmcb->ctrl.TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_SINGLE_CONTEXT_RETAIN_GLOBALS)
718 {
719 STAM_COUNTER_INC(&pVCpu->hm.s.StatFlushAsid);
720 }
721 else
722 Assert(pVmcb->ctrl.TLBCtrl.n.u8TLBFlush == SVM_TLB_FLUSH_ENTIRE)
723#endif
724}
725
726
727/** @name 64-bit guest on 32-bit host OS helper functions.
728 *
729 * The host CPU is still 64-bit capable but the host OS is running in 32-bit
730 * mode (code segment, paging). These wrappers/helpers perform the necessary
731 * bits for the 32->64 switcher.
732 *
733 * @{ */
734#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
735/**
736 * Prepares for and executes VMRUN (64-bit guests on a 32-bit host).
737 *
738 * @returns VBox status code.
739 * @param HCPhysVmcbHost Physical address of host VMCB.
740 * @param HCPhysVmcb Physical address of the VMCB.
741 * @param pCtx Pointer to the guest-CPU context.
742 * @param pVM Pointer to the VM.
743 * @param pVCpu Pointer to the VMCPU.
744 */
745DECLASM(int) SVMR0VMSwitcherRun64(RTHCPHYS HCPhysVmcbHost, RTHCPHYS HCPhysVmcb, PCPUMCTX pCtx, PVM pVM, PVMCPU pVCpu)
746{
747 uint32_t aParam[4];
748 aParam[0] = (uint32_t)(HCPhysVmcbHost); /* Param 1: HCPhysVmcbHost - Lo. */
749 aParam[1] = (uint32_t)(HCPhysVmcbHost >> 32); /* Param 1: HCPhysVmcbHost - Hi. */
750 aParam[2] = (uint32_t)(HCPhysVmcb); /* Param 2: HCPhysVmcb - Lo. */
751 aParam[3] = (uint32_t)(HCPhysVmcb >> 32); /* Param 2: HCPhysVmcb - Hi. */
752
753 return SVMR0Execute64BitsHandler(pVM, pVCpu, pCtx, HM64ON32OP_SVMRCVMRun64, 4, &aParam[0]);
754}
755
756
757/**
758 * Executes the specified VMRUN handler in 64-bit mode.
759 *
760 * @returns VBox status code.
761 * @param pVM Pointer to the VM.
762 * @param pVCpu Pointer to the VMCPU.
763 * @param pCtx Pointer to the guest-CPU context.
764 * @param enmOp The operation to perform.
765 * @param cbParam Number of parameters.
766 * @param paParam Array of 32-bit parameters.
767 */
768VMMR0DECL(int) SVMR0Execute64BitsHandler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, HM64ON32OP enmOp, uint32_t cbParam,
769 uint32_t *paParam)
770{
771 AssertReturn(pVM->hm.s.pfnHost32ToGuest64R0, VERR_HM_NO_32_TO_64_SWITCHER);
772 Assert(enmOp > HM64ON32OP_INVALID && enmOp < HM64ON32OP_END);
773
774 /* Disable interrupts. */
775 RTHCUINTREG uOldEFlags = ASMIntDisableFlags();
776
777#ifdef VBOX_WITH_VMMR0_DISABLE_LAPIC_NMI
778 RTCPUID idHostCpu = RTMpCpuId();
779 CPUMR0SetLApic(pVM, idHostCpu);
780#endif
781
782 CPUMSetHyperESP(pVCpu, VMMGetStackRC(pVCpu));
783 CPUMSetHyperEIP(pVCpu, enmOp);
784 for (int i = (int)cbParam - 1; i >= 0; i--)
785 CPUMPushHyper(pVCpu, paParam[i]);
786
787 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatWorldSwitch3264, z);
788 /* Call the switcher. */
789 int rc = pVM->hm.s.pfnHost32ToGuest64R0(pVM, RT_OFFSETOF(VM, aCpus[pVCpu->idCpu].cpum) - RT_OFFSETOF(VM, cpum));
790 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatWorldSwitch3264, z);
791
792 /* Restore interrupts. */
793 ASMSetFlags(uOldEFlags);
794 return rc;
795}
796
797#endif /* HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS) */
798/** @} */
799
800
801/**
802 * Saves the host state.
803 *
804 * @returns VBox status code.
805 * @param pVM Pointer to the VM.
806 * @param pVCpu Pointer to the VMCPU.
807 *
808 * @remarks No-long-jump zone!!!
809 */
810VMMR0DECL(int) SVMR0SaveHostState(PVM pVM, PVMCPU pVCpu)
811{
812 NOREF(pVM);
813 NOREF(pVCpu);
814 /* Nothing to do here. AMD-V does this for us automatically during the world-switch. */
815 return VINF_SUCCESS;
816}
817
818
819DECLINLINE(void) hmR0SvmAddXcptIntercept(uint32_t u32Xcpt)
820{
821 if (!(pVmcb->ctrl.u32InterceptException & RT_BIT(u32Xcpt))
822 {
823 pVmcb->ctrl.u32InterceptException |= RT_BIT(u32Xcpt);
824 pVmcb->u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
825 }
826}
827
828DECLINLINE(void) hmR0SvmRemoveXcptIntercept(uint32_t u32Xcpt)
829{
830#ifndef HMVMX_ALWAYS_TRAP_ALL_XCPTS
831 if (pVmcb->ctrl.u32InterceptException & RT_BIT(u32Xcpt))
832 {
833 pVmcb->ctrl.u32InterceptException &= ~RT_BIT(u32Xcpt);
834 pVmcb->u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
835 }
836#endif
837}
838
839
840/**
841 * Loads the guest control registers (CR0, CR2, CR3, CR4) into the VMCB.
842 *
843 * @returns VBox status code.
844 * @param pVCpu Pointer to the VMCPU.
845 * @param pCtx Pointer the guest-CPU context.
846 *
847 * @remarks No-long-jump zone!!!
848 */
849static int hmR0SvmLoadGuestControlRegs(PVMCPU pVCpu, PCPUMCTX pCtx)
850{
851 /*
852 * Guest CR0.
853 */
854 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_CR0)
855 {
856 uint64_t u64GuestCR0 = pCtx->cr0;
857
858 /* Always enable caching. */
859 u64GuestCR0 &= ~(X86_CR0_CD | X86_CR0_NW);
860
861 /*
862 * When Nested Paging is not available use shadow page tables and intercept #PFs (latter done in SVMR0SetupVM()).
863 */
864 if (!pVM->hm.s.fNestedPaging)
865 {
866 u64GuestCR0 |= X86_CR0_PG; /* When Nested Paging is not available, use shadow page tables. */
867 u64GuestCR0 |= X86_CR0_WP; /* Guest CPL 0 writes to its read-only pages should cause a #PF VM-exit. */
868 }
869
870 /*
871 * Guest FPU bits.
872 */
873 bool fInterceptNM = false;
874 bool fInterceptMF = false;
875 u64GuestCR0 |= X86_CR0_NE; /* Use internal x87 FPU exceptions handling rather than external interrupts. */
876 if (CPUMIsGuestFPUStateActive(pVCpu))
877 {
878 /* Catch floating point exceptions if we need to report them to the guest in a different way. */
879 if (!(u64GuestCR0 & X86_CR0_NE))
880 {
881 Log4(("hmR0SvmLoadGuestControlRegs: Intercepting Guest CR0.MP Old-style FPU handling!!!\n"));
882 pVmcb->ctrl.u32InterceptException |= RT_BIT(X86_XCPT_MF);
883 fInterceptMF = true;
884 }
885 }
886 else
887 {
888 fInterceptNM = true; /* Guest FPU inactive, VM-exit on #NM for lazy FPU loading. */
889 u32GuestCR0 |= X86_CR0_TS /* Guest can task switch quickly and do lazy FPU syncing. */
890 | X86_CR0_MP; /* FWAIT/WAIT should not ignore CR0.TS and should generate #NM. */
891 }
892
893 /*
894 * Update the exception intercept bitmap.
895 */
896 if (fInterceptNM)
897 hmR0SvmAddXcptIntercept(X86_XCPT_NM);
898 else
899 hmR0SvmRemoveXcptIntercept(X86_XCPT_NM);
900
901 if (fInterceptMF)
902 hmR0SvmAddXcptIntercept(X86_XCPT_MF);
903 else
904 hmR0SvmRemoveXcptIntercept(X86_XCPT_MF);
905
906 pVmcb->guest.u64CR0 = u64GuestCR0;
907 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_CR0;
908 }
909
910 /*
911 * Guest CR2.
912 */
913 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_CR2)
914 {
915 pVmcb->guest.u64CR2 = pCtx->cr2;
916 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_CR2;
917 }
918
919 /*
920 * Guest CR3.
921 */
922 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_CR3)
923 {
924 if (pVM->hm.s.fNestedPaging)
925 {
926 PGMMODE enmShwPagingMode;
927#if HC_ARCH_BITS == 32
928 if (CPUMIsGuestInLongModeEx(pCtx))
929 enmShwPagingMode = PGMMODE_AMD64_NX;
930 else
931#endif
932 enmShwPagingMode = PGMGetHostMode(pVM);
933
934 pVmcb->ctrl.u64NestedPagingCR3 = PGMGetNestedCR3(pVCpu, enmShwPagingMode);
935 Assert(pVmcb->ctrl.u64NestedPagingCR3);
936 pVmcb->guest.u64CR3 = pCtx->cr3;
937 }
938 else
939 pVmcb->guest.u64CR3 = PGMGetHyperCR3(pVCpu);
940
941 pVCpu->hm.s.fContextUseFlags &= HM_CHANGED_GUEST_CR3;
942 }
943
944 /*
945 * Guest CR4.
946 */
947 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_CR4)
948 {
949 uint64_t u64GuestCR4 = pCtx->cr4;
950 if (!pVM->hm.s.fNestedPaging)
951 {
952 switch (pVCpu->hm.s.enmShadowMode)
953 {
954 case PGMMODE_REAL:
955 case PGMMODE_PROTECTED: /* Protected mode, no paging. */
956 AssertFailed();
957 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
958
959 case PGMMODE_32_BIT: /* 32-bit paging. */
960 u64GuestCR4 &= ~X86_CR4_PAE;
961 break;
962
963 case PGMMODE_PAE: /* PAE paging. */
964 case PGMMODE_PAE_NX: /* PAE paging with NX enabled. */
965 /** Must use PAE paging as we could use physical memory > 4 GB */
966 u64GuestCR4 |= X86_CR4_PAE;
967 break;
968
969 case PGMMODE_AMD64: /* 64-bit AMD paging (long mode). */
970 case PGMMODE_AMD64_NX: /* 64-bit AMD paging (long mode) with NX enabled. */
971#ifdef VBOX_ENABLE_64_BITS_GUESTS
972 break;
973#else
974 AssertFailed();
975 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
976#endif
977
978 default: /* shut up gcc */
979 AssertFailed();
980 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
981 }
982 }
983
984 pVmcb->guest.u64CR4 = u64GuestCR4;
985 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_CR4;
986 }
987
988 return VINF_SUCCESS;
989}
990
991/**
992 * Loads the guest segment registers into the VMCB.
993 *
994 * @returns VBox status code.
995 * @param pVCpu Pointer to the VMCPU.
996 * @param pCtx Pointer to the guest-CPU context.
997 *
998 * @remarks No-long-jump zone!!!
999 */
1000static void hmR0SvmLoadGuestSegmentRegs(PVMCPU pVCpu, PCPUMCTX pCtx)
1001{
1002 /* Guest Segment registers: CS, SS, DS, ES, FS, GS. */
1003 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_SEGMENT_REGS)
1004 {
1005 HMSVM_LOAD_SEG_REG(CS, cs);
1006 HMSVM_LOAD_SEG_REG(SS, cs);
1007 HMSVM_LOAD_SEG_REG(DS, cs);
1008 HMSVM_LOAD_SEG_REG(ES, cs);
1009 HMSVM_LOAD_SEG_REG(FS, cs);
1010 HMSVM_LOAD_SEG_REG(GS, cs);
1011
1012 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_SEGMENT_REGS;
1013 }
1014
1015 /* Guest TR. */
1016 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_TR)
1017 {
1018 HMSVM_LOAD_SEG_REG(TR, tr);
1019 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_TR;
1020 }
1021
1022 /* Guest LDTR. */
1023 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_LDTR)
1024 {
1025 HMSVM_LOAD_SEG_REG(LDTR, ldtr);
1026 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_LDTR;
1027 }
1028
1029 /* Guest GDTR. */
1030 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_GDTR)
1031 {
1032 pVmcb->guest.GDTR.u32Limit = pCtx->gdtr.cbGdt;
1033 pVmcb->guest.GDTR.u64Base = pCtx->gdtr.pGdt;
1034 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_GDTR;
1035 }
1036
1037 /* Guest IDTR. */
1038 if (pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_IDTR)
1039 {
1040 pVmcb->guest.IDTR.u32Limit = pCtx->idtr.cbIdt;
1041 pVmcb->guest.IDTR.u64Base = pCtx->idtr.pIdt;
1042 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_IDTR;
1043 }
1044}
1045
1046
1047/**
1048 * Loads the guest MSRs into the VMCB.
1049 *
1050 * @param pVCpu Pointer to the VMCPU.
1051 * @param pCtx Pointer to the guest-CPU context.
1052 *
1053 * @remarks No-long-jump zone!!!
1054 */
1055static void hmR0SvmLoadGuestMsrs(PVMCPU pVCpu, PCPUMCTX pCtx)
1056{
1057 /* Guest Sysenter MSRs. */
1058 pVmcb->guest.u64SysEnterCS = pCtx->SysEnter.cs;
1059 pVmcb->guest.u64SysEnterEIP = pCtx->SysEnter.eip;
1060 pVmcb->guest.u64SysEnterESP = pCtx->SysEnter.esp;
1061
1062 /* Guest EFER MSR. */
1063 /* AMD-V requires guest EFER.SVME to be set. Weird.
1064 See AMD spec. 15.5.1 "Basic Operation" | "Canonicalization and Consistency Checks". */
1065 pVmcb->guest.u64EFER = pCtx->msrEFER | MSR_K6_EFER_SVME;
1066
1067 /* 64-bit MSRs. */
1068 if (CPUMIsGuestInLongModeEx(pCtx))
1069 {
1070 pVmcb->guest.FS.u64Base = pCtx->fs.u64Base;
1071 pVmcb->guest.GS.u64Base = pCtx->gs.u64Base;
1072 }
1073 else
1074 {
1075 /* If the guest isn't in 64-bit mode, clear MSR_K6_LME bit from guest EFER otherwise AMD-V expects amd64 shadow paging. */
1076 pVmcb->guest.u64EFER &= ~MSR_K6_EFER_LME;
1077 }
1078
1079 /** @todo The following are used in 64-bit only (SYSCALL/SYSRET) but they might
1080 * be writable in 32-bit mode. Clarify with AMD spec. */
1081 pVmcb->guest.u64STAR = pCtx->msrSTAR;
1082 pVmcb->guest.u64LSTAR = pCtx->msrLSTAR;
1083 pVmcb->guest.u64CSTAR = pCtx->msrCSTAR;
1084 pVmcb->guest.u64SFMASK = pCtx->msrSFMASK;
1085 pVmcb->guest.u64KernelGSBase = pCtx->msrKERNELGSBASE;
1086}
1087
1088/**
1089 * Loads the guest debug registers into the VMCB.
1090 *
1091 * @param pVCpu Pointer to the VMCPU.
1092 * @param pCtx Pointer to the guest-CPU context.
1093 *
1094 * @remarks No-long-jump zone!!!
1095 */
1096static void hmR0SvmLoadGuestDebugRegs(PVMCPU pVCpu, PCPUMCTX pCtx)
1097{
1098 if (!(pVCpu->hm.s.fContextUseFlags & HM_CHANGED_GUEST_DEBUG))
1099 return;
1100
1101 /** @todo Turn these into assertions if possible. */
1102 pCtx->dr[6] |= X86_DR6_INIT_VAL; /* Set reserved bits to 1. */
1103 pCtx->dr[6] &= ~RT_BIT(12); /* MBZ. */
1104
1105 pCtx->dr[7] &= 0xffffffff; /* Upper 32 bits MBZ. */
1106 pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* MBZ. */
1107 pCtx->dr[7] |= 0x400; /* MB1. */
1108
1109 /* Update DR6, DR7 with the guest values. */
1110 pVmcb->guest.u64DR7 = pCtx->dr[7];
1111 pVmcb->guest.u64DR6 = pCtx->dr[6];
1112 pVmcb->u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DRX;
1113
1114 bool fInterceptDB = false;
1115 bool fInterceptMovDRx = false;
1116 if (DBGFIsStepping(pVCpu))
1117 {
1118 /* AMD-V doesn't have any monitor-trap flag equivalent. Instead, enable tracing in the guest and trap #DB. */
1119 pVmcb->guest.u64RFlags |= X86_EFL_TF;
1120 fInterceptDB = true;
1121 }
1122
1123 if (CPUMGetHyperDR7(pVCpu) & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
1124 {
1125 if (!CPUMIsHyperDebugStateActive(pVCpu))
1126 {
1127 rc = CPUMR0LoadHyperDebugState(pVM, pVCpu, pMixedCtx, true /* include DR6 */);
1128 AssertRC(rc);
1129
1130 /* Update DR6, DR7 with the hypervisor values. */
1131 pVmcb->guest.u64DR7 = CPUMGetHyperDR7(pVCpu);
1132 pVmcb->guest.u64DR6 = CPUMGetHyperDR6(pVCpu);
1133 pVmcb->u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DRX;
1134 }
1135 Assert(CPUMIsHyperDebugStateActive(pVCpu));
1136 fInterceptMovDRx = true;
1137 }
1138 else if (pMixedCtx->dr[7] & (X86_DR7_ENABLED_MASK | X86_DR7_GD))
1139 {
1140 if (!CPUMIsGuestDebugStateActive(pVCpu))
1141 {
1142 rc = CPUMR0LoadGuestDebugState(pVM, pVCpu, pMixedCtx, true /* include DR6 */);
1143 AssertRC(rc);
1144 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxArmed);
1145 }
1146 Assert(CPUMIsGuestDebugStateActive(pVCpu));
1147 Assert(fInterceptMovDRx == false);
1148 }
1149 else if (!CPUMIsGuestDebugStateActive(pVCpu))
1150 {
1151 /* For the first time we would need to intercept MOV DRx accesses even when the guest debug registers aren't loaded. */
1152 fInterceptMovDRx = true;
1153 }
1154
1155 if (fInterceptDB)
1156 hmR0SvmAddXcptIntercept(X86_XCPT_DB);
1157 else
1158 hmR0SvmRemoveXcptIntercept(X86_XCPT_DB);
1159
1160 if (fInterceptMovDRx)
1161 {
1162 if ( pVmcb->ctrl.u16InterceptRdDRx != 0xffff
1163 || pVmcb->ctrl.u16InterceptWrDRx != 0xffff)
1164 {
1165 pVmcb->ctrl.u16InterceptRdDRx = 0xffff;
1166 pVmcb->ctrl.u16InterceptWrDRx = 0xffff;
1167 pVmcb->u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
1168 }
1169 }
1170 else
1171 {
1172 if ( pVmcb->ctrl.u16InterceptRdDRx
1173 || pVmcb->ctrl.u16InterceptWrDRx)
1174 {
1175 pVmcb->ctrl.u16InterceptRdDRx = 0;
1176 pVmcb->ctrl.u16InterceptWrDRx = 0;
1177 pVmcb->u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_INTERCEPTS;
1178 }
1179 }
1180
1181 pVCpu->hm.s.fContextUseFlags &= ~HM_CHANGED_GUEST_DEBUG;
1182}
1183
1184/**
1185 * Sets up the appropriate function to run guest code.
1186 *
1187 * @returns VBox status code.
1188 * @param pVCpu Pointer to the VMCPU.
1189 * @param pMixedCtx Pointer to the guest-CPU context. The data may be
1190 * out-of-sync. Make sure to update the required fields
1191 * before using them.
1192 *
1193 * @remarks No-long-jump zone!!!
1194 */
1195static int hmR0SvmSetupVMRunHandler(PVMCPU pVCpu, PCPUMCTX pCtx)
1196{
1197 if (CPUMIsGuestInLongModeEx(pCtx))
1198 {
1199#ifndef VBOX_ENABLE_64_BITS_GUESTS
1200 return VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE;
1201#endif
1202 Assert(pVCpu->CTX_SUFF(pVM)->hm.s.fAllow64BitGuests); /* Guaranteed by hmR3InitFinalizeR0(). */
1203#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
1204 /* 32-bit host. We need to switch to 64-bit before running the 64-bit guest. */
1205 pVCpu->hm.s.svm.pfnVMRun = SVMR0VMSwitcherRun64;
1206#else
1207 /* 64-bit host or hybrid host. */
1208 pVCpu->hm.s.svm.pfnVMRun = SVMR0VMRun64;
1209#endif
1210 }
1211 else
1212 {
1213 /* Guest is not in long mode, use the 32-bit handler. */
1214 pVCpu->hm.s.svm.pfnVMRun = SVMR0VMRun;
1215 }
1216 return VINF_SUCCESS;
1217}
1218
1219
1220/**
1221 * Loads the guest state.
1222 *
1223 * @returns VBox status code.
1224 * @param pVM Pointer to the VM.
1225 * @param pVCpu Pointer to the VMCPU.
1226 * @param pCtx Pointer to the guest-CPU context.
1227 *
1228 * @remarks No-long-jump zone!!!
1229 */
1230VMMR0DECL(int) SVMR0LoadGuestState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
1231{
1232 AssertPtr(pVM);
1233 AssertPtr(pVCpu);
1234 AssertPtr(pMixedCtx);
1235 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
1236
1237 PSVMVMCB pVmcb = (PSVMVMCB)pVCpu->hm.s.svm.pvVmcb;
1238 AssertMsgReturn(pVmcb, ("Invalid pVmcb\n"), VERR_SVM_INVALID_PVMCB);
1239
1240 STAM_PROFILE_ADV_START(&pVCpu->hm.s.StatLoadGuestState, x);
1241
1242 int rc = hmR0SvmLoadGuestControlRegs(pVCpu, pMixedCtx);
1243 AssertLogRelMsgRCReturn(rc, ("hmR0SvmLoadGuestControlRegs! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
1244
1245 hmR0SvmLoadGuestSegmentRegs(pVCpu, pCtx);
1246 hmR0SvmLoadGuestMsrs(pVCpu, pCtx);
1247
1248 /* Guest RIP, RSP, RFLAGS, CPL. */
1249 pVmcb->guest.u64RIP = pCtx->rip;
1250 pVmcb->guest.u64RSP = pCtx->rsp;
1251 pVmcb->guest.u64RFlags = pCtx->eflags.u32;
1252 pVmcb->guest.u8CPL = pCtx->ss.Attr.n.u2Dpl;
1253
1254 /* hmR0SvmLoadGuestDebugRegs() must be called -after- updating guest RFLAGS as the RFLAGS may need to be changed. */
1255 hmR0SvmLoadGuestDebugRegs(pVCpu, pCtx);
1256
1257 /* Guest RAX (VMRUN uses RAX as an implicit parameter). */
1258 pVmcb->guest.u64RAX = pCtx->rax;
1259
1260 /* -XXX tsc offsetting */
1261
1262 rc = hmR0SvmSetupVMRunHandler(pVCpu, pMixedCtx);
1263 AssertLogRelMsgRCReturn(rc, ("hmR0SvmSetupVMRunHandler! rc=%Rrc (pVM=%p pVCpu=%p)\n", rc, pVM, pVCpu), rc);
1264
1265 /* Clear any unused and reserved bits. */
1266 pVCpu->hm.s.fContextUseFlags &= ~( HM_CHANGED_GUEST_SYSENTER_CS_MSR
1267 | HM_CHANGED_GUEST_SYSENTER_EIP_MSR
1268 | HM_CHANGED_GUEST_SYSENTER_ESP_MSR);
1269
1270 AssertMsg(!pVCpu->hm.s.fContextUseFlags,
1271 ("Missed updating flags while loading guest state. pVM=%p pVCpu=%p fContextUseFlags=%#RX32\n",
1272 pVM, pVCpu, pVCpu->hm.s.fContextUseFlags));
1273
1274 STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatLoadGuestState, x);
1275
1276 return rc;
1277}
1278
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