VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMRC/CPUMRC.cpp@ 61144

Last change on this file since 61144 was 61144, checked in by vboxsync, 8 years ago

CPUM,HM,GVMM,TRPM,VMM: Next part of the FPU state handling for IEM. This is a little bit risky change as we now leave CR0.TS+EM cleared after saving the host state, they only get restored when we restore the host state. On Windows, Darwin, and later on Linux (needs testing) we will rely on #NM handling of the host OS and not our own CR.TS/EM handy work. This means we won't be saving the host state but rather the ring-3 state of our own thread. This change also introduces a CPUM force flag that we're using for restoring CR0.TS/EM in raw-mode (it may be extended with other uses later if we need to).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 9.8 KB
Line 
1/* $Id: CPUMRC.cpp 61144 2016-05-23 22:16:26Z vboxsync $ */
2/** @file
3 * CPUM - Raw-mode Context Code.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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_CPUM
23#include <VBox/vmm/cpum.h>
24#include <VBox/vmm/vmm.h>
25#include <VBox/vmm/patm.h>
26#include <VBox/vmm/trpm.h>
27#include <VBox/vmm/em.h>
28#include "CPUMInternal.h"
29#include <VBox/vmm/vm.h>
30#include <VBox/err.h>
31#include <iprt/assert.h>
32#include <VBox/log.h>
33#include <iprt/asm-amd64-x86.h>
34
35
36/*********************************************************************************************************************************
37* Internal Functions *
38*********************************************************************************************************************************/
39RT_C_DECLS_BEGIN /* addressed from asm (not called so no DECLASM). */
40DECLCALLBACK(int) cpumRCHandleNPAndGP(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser);
41RT_C_DECLS_END
42
43
44/**
45 * Deal with traps occurring during segment loading and IRET when resuming guest
46 * context execution.
47 *
48 * @returns VBox status code.
49 * @param pVM The cross context VM structure.
50 * @param pRegFrame The register frame.
51 * @param uUser User argument. In this case a combination of the
52 * CPUM_HANDLER_* \#defines.
53 */
54DECLCALLBACK(int) cpumRCHandleNPAndGP(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser)
55{
56 Log(("********************************************************\n"));
57 Log(("cpumRCHandleNPAndGP: eip=%RX32 uUser=%#x\n", pRegFrame->eip, uUser));
58 Log(("********************************************************\n"));
59
60 /*
61 * Take action based on what's happened.
62 */
63 switch (uUser & CPUM_HANDLER_TYPEMASK)
64 {
65 case CPUM_HANDLER_GS:
66 case CPUM_HANDLER_DS:
67 case CPUM_HANDLER_ES:
68 case CPUM_HANDLER_FS:
69 TRPMGCHyperReturnToHost(pVM, VINF_EM_RAW_STALE_SELECTOR);
70 break;
71
72 case CPUM_HANDLER_IRET:
73 TRPMGCHyperReturnToHost(pVM, VINF_EM_RAW_IRET_TRAP);
74 break;
75 }
76
77 AssertMsgFailed(("uUser=%#x eip=%#x\n", uUser, pRegFrame->eip));
78 return VERR_TRPM_DONT_PANIC;
79}
80
81
82/**
83 * Called by TRPM and CPUM assembly code to make sure the guest state is
84 * ready for execution.
85 *
86 * @param pVM The cross context VM structure.
87 */
88DECLASM(void) CPUMRCAssertPreExecutionSanity(PVM pVM)
89{
90 /*
91 * Check some important assumptions before resuming guest execution.
92 */
93 PVMCPU pVCpu = VMMGetCpu0(pVM);
94 PCCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
95 uint8_t const uRawCpl = CPUMGetGuestCPL(pVCpu);
96 uint32_t const u32EFlags = CPUMRawGetEFlags(pVCpu);
97 bool const fPatch = PATMIsPatchGCAddr(pVM, pCtx->eip);
98 AssertMsg(pCtx->eflags.Bits.u1IF, ("cs:eip=%04x:%08x ss:esp=%04x:%08x cpl=%u raw/efl=%#x/%#x%s\n", pCtx->cs.Sel, pCtx->eip, pCtx->ss.Sel, pCtx->esp, uRawCpl, u32EFlags, pCtx->eflags.u, fPatch ? " patch" : ""));
99 AssertMsg(pCtx->eflags.Bits.u2IOPL < RT_MAX(uRawCpl, 1U),
100 ("cs:eip=%04x:%08x ss:esp=%04x:%08x cpl=%u raw/efl=%#x/%#x%s\n", pCtx->cs.Sel, pCtx->eip, pCtx->ss.Sel, pCtx->esp, uRawCpl, u32EFlags, pCtx->eflags.u, fPatch ? " patch" : ""));
101 if (!(u32EFlags & X86_EFL_VM))
102 {
103 AssertMsg((u32EFlags & X86_EFL_IF) || fPatch,("cs:eip=%04x:%08x ss:esp=%04x:%08x cpl=%u raw/efl=%#x/%#x%s\n", pCtx->cs.Sel, pCtx->eip, pCtx->ss.Sel, pCtx->esp, uRawCpl, u32EFlags, pCtx->eflags.u, fPatch ? " patch" : ""));
104 AssertMsg((pCtx->cs.Sel & X86_SEL_RPL) > 0, ("cs:eip=%04x:%08x ss:esp=%04x:%08x cpl=%u raw/efl=%#x/%#x%s\n", pCtx->cs.Sel, pCtx->eip, pCtx->ss.Sel, pCtx->esp, uRawCpl, u32EFlags, pCtx->eflags.u, fPatch ? " patch" : ""));
105 AssertMsg((pCtx->ss.Sel & X86_SEL_RPL) > 0, ("cs:eip=%04x:%08x ss:esp=%04x:%08x cpl=%u raw/efl=%#x/%#x%s\n", pCtx->cs.Sel, pCtx->eip, pCtx->ss.Sel, pCtx->esp, uRawCpl, u32EFlags, pCtx->eflags.u, fPatch ? " patch" : ""));
106 }
107 AssertMsg(CPUMIsGuestInRawMode(pVCpu), ("cs:eip=%04x:%08x ss:esp=%04x:%08x cpl=%u raw/efl=%#x/%#x%s\n", pCtx->cs.Sel, pCtx->eip, pCtx->ss.Sel, pCtx->esp, uRawCpl, u32EFlags, pCtx->eflags.u, fPatch ? " patch" : ""));
108 //Log2(("cs:eip=%04x:%08x ss:esp=%04x:%08x cpl=%u raw/efl=%#x/%#x%s\n", pCtx->cs.Sel, pCtx->eip, pCtx->ss.Sel, pCtx->esp, uRawCpl, u32EFlags, pCtx->eflags.u, fPatch ? " patch" : ""));
109}
110
111
112/**
113 * Get the current privilege level of the guest.
114 *
115 * @returns CPL
116 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
117 * @param pRegFrame Pointer to the register frame.
118 *
119 * @todo r=bird: This is very similar to CPUMGetGuestCPL and I cannot quite
120 * see why this variant of the code is necessary.
121 */
122VMMDECL(uint32_t) CPUMRCGetGuestCPL(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
123{
124 /*
125 * CPL can reliably be found in SS.DPL (hidden regs valid) or SS if not.
126 *
127 * Note! We used to check CS.DPL here, assuming it was always equal to
128 * CPL even if a conforming segment was loaded. But this truned out to
129 * only apply to older AMD-V. With VT-x we had an ACP2 regression
130 * during install after a far call to ring 2 with VT-x. Then on newer
131 * AMD-V CPUs we have to move the VMCB.guest.u8CPL into cs.Attr.n.u2Dpl
132 * as well as ss.Attr.n.u2Dpl to make this (and other) code work right.
133 *
134 * So, forget CS.DPL, always use SS.DPL.
135 *
136 * Note! The SS RPL is always equal to the CPL, while the CS RPL
137 * isn't necessarily equal if the segment is conforming.
138 * See section 4.11.1 in the AMD manual.
139 */
140 uint32_t uCpl;
141 if (!pRegFrame->eflags.Bits.u1VM)
142 {
143 uCpl = (pRegFrame->ss.Sel & X86_SEL_RPL);
144#ifdef VBOX_WITH_RAW_MODE_NOT_R0
145# ifdef VBOX_WITH_RAW_RING1
146 if (pVCpu->cpum.s.fRawEntered)
147 {
148 if ( uCpl == 2
149 && EMIsRawRing1Enabled(pVCpu->CTX_SUFF(pVM)) )
150 uCpl = 1;
151 else if (uCpl == 1)
152 uCpl = 0;
153 }
154 Assert(uCpl != 2); /* ring 2 support not allowed anymore. */
155# else
156 if (uCpl == 1)
157 uCpl = 0;
158# endif
159#endif
160 }
161 else
162 uCpl = 3; /* V86 has CPL=3; REM doesn't set DPL=3 in V8086 mode. See @bugref{5130}. */
163
164 return uCpl;
165}
166
167
168#ifdef VBOX_WITH_RAW_RING1
169/**
170 * Transforms the guest CPU state to raw-ring mode.
171 *
172 * This function will change the any of the cs and ss register with DPL=0 to DPL=1.
173 *
174 * Used by emInterpretIret() after the new state has been loaded.
175 *
176 * @param pVCpu The cross context virtual CPU structure.
177 * @param pCtxCore The context core (for trap usage).
178 * @see @ref pg_raw
179 * @remarks Will be probably obsoleted by #5653 (it will leave and reenter raw
180 * mode instead, I think).
181 */
182VMMDECL(void) CPUMRCRecheckRawState(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
183{
184 /*
185 * Are we in Ring-0?
186 */
187 if ( pCtxCore->ss.Sel
188 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 0
189 && !pCtxCore->eflags.Bits.u1VM)
190 {
191 /*
192 * Set CPL to Ring-1.
193 */
194 pCtxCore->ss.Sel |= 1;
195 if ( pCtxCore->cs.Sel
196 && (pCtxCore->cs.Sel & X86_SEL_RPL) == 0)
197 pCtxCore->cs.Sel |= 1;
198 }
199 else
200 {
201 if ( EMIsRawRing1Enabled(pVCpu->CTX_SUFF(pVM))
202 && !pCtxCore->eflags.Bits.u1VM
203 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 1)
204 {
205 /* Set CPL to Ring-2. */
206 pCtxCore->ss.Sel = (pCtxCore->ss.Sel & ~X86_SEL_RPL) | 2;
207 if (pCtxCore->cs.Sel && (pCtxCore->cs.Sel & X86_SEL_RPL) == 1)
208 pCtxCore->cs.Sel = (pCtxCore->cs.Sel & ~X86_SEL_RPL) | 2;
209 }
210 }
211
212 /*
213 * Assert sanity.
214 */
215 AssertMsg((pCtxCore->eflags.u32 & X86_EFL_IF), ("X86_EFL_IF is clear\n"));
216 AssertReleaseMsg(pCtxCore->eflags.Bits.u2IOPL == 0,
217 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss.Sel & X86_SEL_RPL));
218
219 pCtxCore->eflags.u32 |= X86_EFL_IF; /* paranoia */
220}
221#endif /* VBOX_WITH_RAW_RING1 */
222
223
224/**
225 * Called by trpmGCExitTrap when VMCPU_FF_CPUM is set (by CPUMRZ.cpp).
226 *
227 * We can be called unecessarily here if we returned to ring-3 for some other
228 * reason before we tried to resume executed guest code. This is detected and
229 * ignored.
230 *
231 * @param pVCpu The cross context CPU structure for the calling EMT.
232 */
233VMMRCDECL(void) CPUMRCProcessForceFlag(PVMVCPU pVCpu)
234{
235 /* Only modify CR0 if we're in the post IEM state (host state saved, guest no longer active). */
236 if ((pVCpu->cpum.s.fUseFlags & (CPUM_USED_FPU_GUEST | CPUM_USED_FPU_HOST)) == CPUM_USED_FPU_HOST)
237 {
238 /*
239 * Doing the same CR0 calculation as in AMD64andLegacy.mac so that we'll
240 * catch guest FPU accesses and load the FPU/SSE/AVX register state as needed.
241 */
242 uint32_t cr0 = ASMGetCR0();
243 cr0 |= pVCpu->cpum.s.Guest.cr0 & X86_CR0_EM;
244 cr0 |= X86_CR0_TS | X86_CR0_MP;
245 ASMSetCR0(cr0);
246 }
247}
248
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