VirtualBox

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

Last change on this file since 23911 was 19141, checked in by vboxsync, 16 years ago

Action flags breakup.
Fixed PGM saved state loading of 2.2.2 images.
Reduced hacks in PATM state loading (fixups).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.3 KB
Line 
1/* $Id: TRPMGC.cpp 19141 2009-04-23 13:52:18Z 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(pVCpu);
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 VMCPU_FF_SET(pVCpu, VMCPU_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