VirtualBox

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

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

The Giant CDDL Dual-License Header Change.

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