VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/CPUMR0.cpp@ 10835

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

Save the FPU control word and MXCSR on entry and restore them afterwards. (VT-x & AMD-V)
Security measure so the guest can't cause fpu/sse exceptions as we no longer restore the entire
host fpu state.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.4 KB
Line 
1/* $Id: CPUMR0.cpp 10687 2008-07-16 09:22:28Z vboxsync $ */
2/** @file
3 * CPUM - Host Context Ring 0.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_CPUM
27#include <VBox/cpum.h>
28#include "CPUMInternal.h"
29#include <VBox/vm.h>
30#include <VBox/x86.h>
31#include <VBox/err.h>
32#include <VBox/log.h>
33#include <iprt/assert.h>
34#include <iprt/asm.h>
35
36
37
38
39/**
40 * Does Ring-0 CPUM initialization.
41 *
42 * This is mainly to check that the Host CPU mode is compatible
43 * with VBox.
44 *
45 * @returns VBox status code.
46 * @param pVM The VM to operate on.
47 */
48CPUMR0DECL(int) CPUMR0Init(PVM pVM)
49{
50 LogFlow(("CPUMR0Init: %p\n", pVM));
51
52 /*
53 * Check CR0 & CR4 flags.
54 */
55 uint32_t u32CR0 = ASMGetCR0();
56 if ((u32CR0 & (X86_CR0_PE | X86_CR0_PG)) != (X86_CR0_PE | X86_CR0_PG)) /* a bit paranoid perhaps.. */
57 {
58 Log(("CPUMR0Init: PE or PG not set. cr0=%#x\n", u32CR0));
59 return VERR_UNSUPPORTED_CPU_MODE;
60 }
61
62 /*
63 * Check for sysenter if it's used.
64 */
65 if (ASMHasCpuId())
66 {
67 uint32_t u32CpuVersion;
68 uint32_t u32Dummy;
69 uint32_t u32Features;
70 ASMCpuId(1, &u32CpuVersion, &u32Dummy, &u32Dummy, &u32Features);
71 uint32_t u32Family = u32CpuVersion >> 8;
72 uint32_t u32Model = (u32CpuVersion >> 4) & 0xF;
73 uint32_t u32Stepping = u32CpuVersion & 0xF;
74
75 /*
76 * Intel docs claim you should test both the flag and family, model & stepping.
77 * Some Pentium Pro cpus have the SEP cpuid flag set, but don't support it.
78 */
79 if ( (u32Features & X86_CPUID_FEATURE_EDX_SEP)
80 && !(u32Family == 6 && u32Model < 3 && u32Stepping < 3))
81 {
82 /*
83 * Read the MSR and see if it's in use or not.
84 */
85 uint32_t u32 = ASMRdMsr_Low(MSR_IA32_SYSENTER_CS);
86 if (u32)
87 {
88 pVM->cpum.s.fUseFlags |= CPUM_USE_SYSENTER;
89 Log(("CPUMR0Init: host uses sysenter cs=%08x%08x\n", ASMRdMsr_High(MSR_IA32_SYSENTER_CS), u32));
90 }
91 }
92
93 /** @todo check for AMD and syscall!!!!!! */
94 }
95
96
97 /*
98 * Check if debug registers are armed.
99 */
100 uint32_t u32DR7 = ASMGetDR7();
101 if (u32DR7 & X86_DR7_ENABLED_MASK)
102 {
103 pVM->cpum.s.fUseFlags |= CPUM_USE_DEBUG_REGS_HOST;
104 Log(("CPUMR0Init: host uses debug registers (dr7=%x)\n", u32DR7));
105 }
106
107 return VINF_SUCCESS;
108}
109
110
111/**
112 * Lazily sync in the FPU/XMM state
113 *
114 * @returns VBox status code.
115 * @param pVM VM handle.
116 * @param pCtx CPU context
117 */
118CPUMR0DECL(int) CPUMR0LoadGuestFPU(PVM pVM, PCPUMCTX pCtx)
119{
120 Assert(pVM->cpum.s.CPUFeatures.edx.u1FXSR);
121 Assert(ASMGetCR4() & X86_CR4_OSFSXR);
122
123 /* If the FPU state has already been loaded, then it's a guest trap. */
124 if (pVM->cpum.s.fUseFlags & CPUM_USED_FPU)
125 {
126 Assert( ((pCtx->cr0 & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS)) == (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))
127 || ((pCtx->cr0 & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS)) == (X86_CR0_MP | X86_CR0_TS)));
128 return VINF_EM_RAW_GUEST_TRAP;
129 }
130
131 /*
132 * There are two basic actions:
133 * 1. Save host fpu and restore guest fpu.
134 * 2. Generate guest trap.
135 *
136 * When entering the hypervisor we'll always enable MP (for proper wait
137 * trapping) and TS (for intercepting all fpu/mmx/sse stuff). The EM flag
138 * is taken from the guest OS in order to get proper SSE handling.
139 *
140 *
141 * Actions taken depending on the guest CR0 flags:
142 *
143 * 3 2 1
144 * TS | EM | MP | FPUInstr | WAIT :: VMM Action
145 * ------------------------------------------------------------------------
146 * 0 | 0 | 0 | Exec | Exec :: Clear TS & MP, Save HC, Load GC.
147 * 0 | 0 | 1 | Exec | Exec :: Clear TS, Save HC, Load GC.
148 * 0 | 1 | 0 | #NM | Exec :: Clear TS & MP, Save HC, Load GC.
149 * 0 | 1 | 1 | #NM | Exec :: Clear TS, Save HC, Load GC.
150 * 1 | 0 | 0 | #NM | Exec :: Clear MP, Save HC, Load GC. (EM is already cleared.)
151 * 1 | 0 | 1 | #NM | #NM :: Go to guest taking trap there.
152 * 1 | 1 | 0 | #NM | Exec :: Clear MP, Save HC, Load GC. (EM is already set.)
153 * 1 | 1 | 1 | #NM | #NM :: Go to guest taking trap there.
154 */
155
156 switch(pCtx->cr0 & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))
157 {
158 case X86_CR0_MP | X86_CR0_TS:
159 case X86_CR0_MP | X86_CR0_EM | X86_CR0_TS:
160 return VINF_EM_RAW_GUEST_TRAP;
161
162 default:
163 break;
164 }
165 /* Save the FPU control word and MXCSR, so we can restore the properly afterwards.
166 * We don't want the guest to be able to trigger floating point/SSE exceptions on the host.
167 */
168 pVM->cpum.s.Host.fpu.FCW = CPUMGetFCW();
169 if (pVM->cpum.s.CPUFeatures.edx.u1SSE)
170 pVM->cpum.s.Host.fpu.MXCSR = CPUMGetMXCSR();
171
172 CPUMLoadFPUAsm(pCtx);
173
174 /* The MSR_K6_EFER_FFXSR feature is AMD only so far, but check the cpuid just in case Intel adds it in the future.
175 *
176 * MSR_K6_EFER_FFXSR changes the behaviour of fxsave and fxrstore: the XMM state isn't saved/restored
177 */
178 if (pVM->cpum.s.CPUFeaturesExt.edx & X86_CPUID_AMD_FEATURE_EDX_FFXSR)
179 {
180 /* @todo Do we really need to read this every time?? The host could change this on the fly though. */
181 uint64_t msrEFERHost = ASMRdMsr(MSR_K6_EFER);
182
183 if (msrEFERHost & MSR_K6_EFER_FFXSR)
184 {
185 /* fxrstor doesn't restore the XMM state! */
186 CPUMLoadXMMAsm(pCtx);
187 pVM->cpum.s.fUseFlags |= CPUM_MANUAL_XMM_RESTORE;
188 }
189 }
190
191 pVM->cpum.s.fUseFlags |= CPUM_USED_FPU;
192 return VINF_SUCCESS;
193}
194
195
196/**
197 * Save guest FPU/XMM state
198 *
199 * @returns VBox status code.
200 * @param pVM VM handle.
201 * @param pCtx CPU context
202 */
203CPUMR0DECL(int) CPUMR0SaveGuestFPU(PVM pVM, PCPUMCTX pCtx)
204{
205 Assert(pVM->cpum.s.CPUFeatures.edx.u1FXSR);
206 Assert(ASMGetCR4() & X86_CR4_OSFSXR);
207 AssertReturn((pVM->cpum.s.fUseFlags & CPUM_USED_FPU), VINF_SUCCESS);
208
209 CPUMSaveFPUAsm(pCtx);
210 if (pVM->cpum.s.fUseFlags & CPUM_MANUAL_XMM_RESTORE)
211 {
212 /* fxsave doesn't save the XMM state! */
213 CPUMSaveXMMAsm(pCtx);
214 }
215 /* Restore the original FPU control word and MXCSR.
216 * We don't want the guest to be able to trigger floating point/SSE exceptions on the host.
217 */
218 CPUMSetFCW(pVM->cpum.s.Host.fpu.FCW);
219 if (pVM->cpum.s.CPUFeatures.edx.u1SSE)
220 CPUMSetMXCSR(pVM->cpum.s.Host.fpu.MXCSR);
221
222 pVM->cpum.s.fUseFlags &= ~(CPUM_USED_FPU|CPUM_MANUAL_XMM_RESTORE);
223 return VINF_SUCCESS;
224}
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