VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMGC/TRPMGC.cpp@ 18992

Last change on this file since 18992 was 18927, checked in by vboxsync, 16 years ago

Big step to separate VMM data structures for guest SMP. (pgm, em)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.3 KB
Line 
1/* $Id: TRPMGC.cpp 18927 2009-04-16 11:41:38Z vboxsync $ */
2/** @file
3 * TRPM - The Trap Monitor, Guest Context
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_TRPM
27#include <VBox/trpm.h>
28#include <VBox/cpum.h>
29#include <VBox/vmm.h>
30#include "TRPMInternal.h"
31#include <VBox/vm.h>
32
33#include <VBox/err.h>
34#include <VBox/x86.h>
35#include <VBox/em.h>
36#include <iprt/assert.h>
37#include <iprt/asm.h>
38#include <VBox/log.h>
39#include <VBox/selm.h>
40
41
42
43/**
44 * Arms a temporary trap handler for traps in Hypervisor code.
45 *
46 * The operation is similar to a System V signal handler. I.e. when the handler
47 * is called it is first set to default action. So, if you need to handler more
48 * than one trap, you must reinstall the handler.
49 *
50 * To uninstall the temporary handler, call this function with pfnHandler set to NULL.
51 *
52 * @returns VBox status.
53 * @param pVM VM handle.
54 * @param iTrap Trap number to install handler [0..255].
55 * @param pfnHandler Pointer to the handler. Use NULL for uninstalling the handler.
56 */
57VMMRCDECL(int) TRPMGCSetTempHandler(PVM pVM, unsigned iTrap, PFNTRPMGCTRAPHANDLER pfnHandler)
58{
59 /*
60 * Validate input.
61 */
62 if (iTrap >= RT_ELEMENTS(pVM->trpm.s.aTmpTrapHandlers))
63 {
64 AssertMsgFailed(("Trap handler iTrap=%u is out of range!\n", iTrap));
65 return VERR_INVALID_PARAMETER;
66 }
67
68 /*
69 * Install handler.
70 */
71 pVM->trpm.s.aTmpTrapHandlers[iTrap] = (RTRCPTR)(uintptr_t)pfnHandler;
72 return VINF_SUCCESS;
73}
74
75
76/**
77 * Return to host context from a hypervisor trap handler.
78 *
79 * This function will *never* return.
80 * It will also reset any traps that are pending.
81 *
82 * @param pVM The VM handle.
83 * @param rc The return code for host context.
84 */
85VMMRCDECL(void) TRPMGCHyperReturnToHost(PVM pVM, int rc)
86{
87 PVMCPU pVCpu = VMMGetCpu0(pVM);
88
89 LogFlow(("TRPMGCHyperReturnToHost: rc=%Rrc\n", rc));
90 TRPMResetTrap(pVM);
91 CPUMHyperSetCtxCore(pVCpu, NULL);
92 VMMGCGuestToHost(pVM, rc);
93 AssertReleaseFailed();
94}
95
96
97/**
98 * \#PF Virtual Handler callback for Guest write access to the Guest's own current IDT.
99 *
100 * @returns VBox status code (appropriate for trap handling and GC return).
101 * @param pVM VM Handle.
102 * @param uErrorCode CPU Error code.
103 * @param pRegFrame Trap register frame.
104 * @param pvFault The fault address (cr2).
105 * @param pvRange The base address of the handled virtual range.
106 * @param offRange The offset of the access into this range.
107 * (If it's a EIP range this's the EIP, if not it's pvFault.)
108 */
109VMMRCDECL(int) trpmRCGuestIDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
110{
111 PVMCPU pVCpu = VMMGetCpu0(pVM);
112 uint16_t cbIDT;
113 RTGCPTR GCPtrIDT = (RTGCPTR)CPUMGetGuestIDTR(pVCpu, &cbIDT);
114#ifdef VBOX_STRICT
115 RTGCPTR GCPtrIDTEnd = (RTGCPTR)((RTGCUINTPTR)GCPtrIDT + cbIDT + 1);
116#endif
117 uint32_t iGate = ((RTGCUINTPTR)pvFault - (RTGCUINTPTR)GCPtrIDT)/sizeof(VBOXIDTE);
118
119 AssertMsg(offRange < (uint32_t)cbIDT+1, ("pvFault=%RGv GCPtrIDT=%RGv-%RGv pvRange=%RGv\n", pvFault, GCPtrIDT, GCPtrIDTEnd, pvRange));
120 Assert((RTGCPTR)(RTRCUINTPTR)pvRange == GCPtrIDT);
121
122#if 0
123 /* Note! this causes problems in Windows XP as instructions following the update can be dangerous (str eax has been seen) */
124 /* Note! not going back to ring 3 could make the code scanner miss them. */
125 /* Check if we can handle the write here. */
126 if ( iGate != 3 /* Gate 3 is handled differently; could do it here as well, but let ring 3 handle this case for now. */
127 && !ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iGate)) /* Passthru gates need special attention too. */
128 {
129 uint32_t cb;
130 int rc = EMInterpretInstruction(pVM, pVCpu, pRegFrame, pvFault, &cb);
131 if (RT_SUCCESS(rc) && cb)
132 {
133 uint32_t iGate1 = (offRange + cb - 1)/sizeof(VBOXIDTE);
134
135 Log(("trpmRCGuestIDTWriteHandler: write to gate %x (%x) offset %x cb=%d\n", iGate, iGate1, offRange, cb));
136
137 trpmClearGuestTrapHandler(pVM, iGate);
138 if (iGate != iGate1)
139 trpmClearGuestTrapHandler(pVM, iGate1);
140
141 STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTHandled);
142 return VINF_SUCCESS;
143 }
144 }
145#else
146 NOREF(iGate);
147#endif
148
149 Log(("trpmRCGuestIDTWriteHandler: eip=%RGv write to gate %x offset %x\n", pRegFrame->eip, iGate, offRange));
150
151 /** @todo Check which IDT entry and keep the update cost low in TRPMR3SyncIDT() and CSAMCheckGates(). */
152 VM_FF_SET(pVM, VM_FF_TRPM_SYNC_IDT);
153
154 STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTFault);
155 return VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT;
156}
157
158
159/**
160 * \#PF Virtual Handler callback for Guest write access to the VBox shadow IDT.
161 *
162 * @returns VBox status code (appropriate for trap handling and GC return).
163 * @param pVM VM Handle.
164 * @param uErrorCode CPU Error code.
165 * @param pRegFrame Trap register frame.
166 * @param pvFault The fault address (cr2).
167 * @param pvRange The base address of the handled virtual range.
168 * @param offRange The offset of the access into this range.
169 * (If it's a EIP range this's the EIP, if not it's pvFault.)
170 */
171VMMRCDECL(int) trpmRCShadowIDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
172{
173 PVMCPU pVCpu = VMMGetCpu0(pVM);
174 LogRel(("FATAL ERROR: trpmRCShadowIDTWriteHandler: eip=%08X pvFault=%RGv pvRange=%08X\r\n", pRegFrame->eip, pvFault, pvRange));
175
176 /* If we ever get here, then the guest has executed an sidt instruction that we failed to patch. In theory this could be very bad, but
177 * there are nasty applications out there that install device drivers that mess with the guest's IDT. In those cases, it's quite ok
178 * to simply ignore the writes and pretend success.
179 */
180 RTGCPTR PC;
181 int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
182 if (rc == VINF_SUCCESS)
183 {
184 DISCPUSTATE Cpu;
185 uint32_t cbOp;
186 rc = EMInterpretDisasOneEx(pVM, pVCpu, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
187 if (rc == VINF_SUCCESS)
188 {
189 /* Just ignore the write. */
190 pRegFrame->eip += Cpu.opsize;
191 return VINF_SUCCESS;
192 }
193 }
194
195 return VERR_TRPM_SHADOW_IDT_WRITE;
196}
197
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