VirtualBox

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

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

Ring-1 compression patches, courtesy of trivirt AG:

  • main: diff to remove the hwvirt requirement for QNX
  • rem: diff for dealing with raw ring 0/1 selectors and general changes to allowed guest execution states
  • vmm: changes for using the guest's TSS selector index as our hypervisor TSS selector (makes str safe) (VBOX_WITH_SAFE_STR )
  • vmm: changes for dealing with guest ring 1 code (VBOX_WITH_RAW_RING1)
  • vmm: change to emulate smsw in RC/R0 (QNX uses this old style instruction a lot so going to qemu for emulation is very expensive)
  • vmm: change (hack) to kick out patm virtual handlers in case they conflict with guest GDT/TSS write monitors; we should allow multiple handlers per page, but that change would be rather invasive
  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 8.2 KB
Line 
1/* $Id: CPUMRC.cpp 45276 2013-04-02 08:17:11Z vboxsync $ */
2/** @file
3 * CPUM - Raw-mode Context Code.
4 */
5
6/*
7 * Copyright (C) 2006-2012 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
34
35/*******************************************************************************
36* Internal Functions *
37*******************************************************************************/
38RT_C_DECLS_BEGIN /* addressed from asm (not called so no DECLASM). */
39DECLCALLBACK(int) cpumRCHandleNPAndGP(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser);
40RT_C_DECLS_END
41
42
43/**
44 * Deal with traps occurring during segment loading and IRET when resuming guest
45 * context execution.
46 *
47 * @returns VBox status code.
48 * @param pVM Pointer to the VM.
49 * @param pRegFrame The register frame.
50 * @param uUser User argument. In this case a combination of the
51 * CPUM_HANDLER_* \#defines.
52 */
53DECLCALLBACK(int) cpumRCHandleNPAndGP(PVM pVM, PCPUMCTXCORE pRegFrame, uintptr_t uUser)
54{
55 Log(("********************************************************\n"));
56 Log(("cpumRCHandleNPAndGP: eip=%RX32 uUser=%#x\n", pRegFrame->eip, uUser));
57 Log(("********************************************************\n"));
58
59 /*
60 * Take action based on what's happened.
61 */
62 switch (uUser & CPUM_HANDLER_TYPEMASK)
63 {
64 case CPUM_HANDLER_GS:
65 case CPUM_HANDLER_DS:
66 case CPUM_HANDLER_ES:
67 case CPUM_HANDLER_FS:
68 TRPMGCHyperReturnToHost(pVM, VINF_EM_RAW_STALE_SELECTOR);
69 break;
70
71 case CPUM_HANDLER_IRET:
72 TRPMGCHyperReturnToHost(pVM, VINF_EM_RAW_IRET_TRAP);
73 break;
74 }
75
76 AssertMsgFailed(("uUser=%#x eip=%#x\n", uUser, pRegFrame->eip));
77 return VERR_TRPM_DONT_PANIC;
78}
79
80
81/**
82 * Called by TRPM and CPUM assembly code to make sure the guest state is
83 * ready for execution.
84 *
85 * @param pVM The VM handle.
86 */
87DECLASM(void) CPUMRCAssertPreExecutionSanity(PVM pVM)
88{
89 /*
90 * Check some important assumptions before resuming guest execution.
91 */
92 PVMCPU pVCpu = VMMGetCpu0(pVM);
93 PCCPUMCTX pCtx = &pVCpu->cpum.s.Guest;
94 uint8_t const uRawCpl = CPUMGetGuestCPL(pVCpu);
95 uint32_t const u32EFlags = CPUMRawGetEFlags(pVCpu);
96 bool const fPatch = PATMIsPatchGCAddr(pVM, pCtx->eip);
97 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" : ""));
98 AssertMsg(pCtx->eflags.Bits.u2IOPL < RT_MAX(uRawCpl, 1U),
99 ("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" : ""));
100 if (!(u32EFlags & X86_EFL_VM))
101 {
102 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" : ""));
103 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" : ""));
104 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" : ""));
105 }
106 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" : ""));
107 //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" : ""));
108}
109
110
111/**
112 * Get the current privilege level of the guest.
113 *
114 * @returns CPL
115 * @param pVCpu The current virtual CPU.
116 * @param pRegFrame Pointer to the register frame.
117 */
118VMMDECL(uint32_t) CPUMRCGetGuestCPL(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)
119{
120 /*
121 * CPL can reliably be found in SS.DPL (hidden regs valid) or SS if not.
122 *
123 * Note! We used to check CS.DPL here, assuming it was always equal to
124 * CPL even if a conforming segment was loaded. But this truned out to
125 * only apply to older AMD-V. With VT-x we had an ACP2 regression
126 * during install after a far call to ring 2 with VT-x. Then on newer
127 * AMD-V CPUs we have to move the VMCB.guest.u8CPL into cs.Attr.n.u2Dpl
128 * as well as ss.Attr.n.u2Dpl to make this (and other) code work right.
129 *
130 * So, forget CS.DPL, always use SS.DPL.
131 *
132 * Note! The SS RPL is always equal to the CPL, while the CS RPL
133 * isn't necessarily equal if the segment is conforming.
134 * See section 4.11.1 in the AMD manual.
135 */
136 uint32_t uCpl;
137 if (!pRegFrame->eflags.Bits.u1VM)
138 {
139 uCpl = (pRegFrame->ss.Sel & X86_SEL_RPL);
140#ifdef VBOX_WITH_RAW_MODE_NOT_R0
141# ifdef VBOX_WITH_RAW_RING1
142 if (pVCpu->cpum.s.fRawEntered)
143 {
144 if ( EMIsRawRing1Enabled(pVCpu->CTX_SUFF(pVM))
145 && uCpl == 2)
146 uCpl = 1;
147 else
148 if (uCpl == 1)
149 uCpl = 0;
150 }
151 Assert(uCpl != 2); /* ring 2 support not allowed anymore. */
152# else
153 if (uCpl == 1)
154 uCpl = 0;
155# endif
156#endif
157 }
158 else
159 uCpl = 3; /* V86 has CPL=3; REM doesn't set DPL=3 in V8086 mode. See @bugref{5130}. */
160
161 return uCpl;
162}
163
164#ifdef VBOX_WITH_RAW_RING1
165/**
166 * Transforms the guest CPU state to raw-ring mode.
167 *
168 * This function will change the any of the cs and ss register with DPL=0 to DPL=1.
169 *
170 * @returns VBox status. (recompiler failure)
171 * @param pVCpu Pointer to the VMCPU.
172 * @param pCtxCore The context core (for trap usage).
173 * @see @ref pg_raw
174 */
175VMMDECL(void) CPUMRCRecheckRawState(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore)
176{
177 /*
178 * Are we in Ring-0?
179 */
180 if ( pCtxCore->ss.Sel
181 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 0
182 && !pCtxCore->eflags.Bits.u1VM)
183 {
184 /*
185 * Set CPL to Ring-1.
186 */
187 pCtxCore->ss.Sel |= 1;
188 if ( pCtxCore->cs.Sel
189 && (pCtxCore->cs.Sel & X86_SEL_RPL) == 0)
190 pCtxCore->cs.Sel |= 1;
191 }
192 else
193 {
194 if ( EMIsRawRing1Enabled(pVCpu->CTX_SUFF(pVM))
195 && !pCtxCore->eflags.Bits.u1VM
196 && (pCtxCore->ss.Sel & X86_SEL_RPL) == 1)
197 {
198 /* Set CPL to Ring-2. */
199 pCtxCore->ss.Sel = (pCtxCore->ss.Sel & ~X86_SEL_RPL) | 2;
200 if (pCtxCore->cs.Sel && (pCtxCore->cs.Sel & X86_SEL_RPL) == 1)
201 pCtxCore->cs.Sel = (pCtxCore->cs.Sel & ~X86_SEL_RPL) | 2;
202 }
203 }
204
205 /*
206 * Assert sanity.
207 */
208 AssertMsg((pCtxCore->eflags.u32 & X86_EFL_IF), ("X86_EFL_IF is clear\n"));
209 AssertReleaseMsg(pCtxCore->eflags.Bits.u2IOPL == 0,
210 ("X86_EFL_IOPL=%d CPL=%d\n", pCtxCore->eflags.Bits.u2IOPL, pCtxCore->ss.Sel & X86_SEL_RPL));
211
212 pCtxCore->eflags.u32 |= X86_EFL_IF; /* paranoia */
213}
214#endif /* VBOX_WITH_RAW_RING1 */
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