VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMRC/TRPMRC.cpp@ 41939

Last change on this file since 41939 was 41931, checked in by vboxsync, 13 years ago

TRPM: Save state directly to the CPUMCPU context member instead of putting on the stack. this avoid copying the state around before returning to host context to service an IRQ, or before using IEM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.0 KB
Line 
1/* $Id: TRPMRC.cpp 41931 2012-06-27 16:12:16Z vboxsync $ */
2/** @file
3 * TRPM - The Trap Monitor, Guest Context
4 */
5
6/*
7 * Copyright (C) 2006-2007 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_TRPM
23#include <VBox/vmm/trpm.h>
24#include <VBox/vmm/cpum.h>
25#include <VBox/vmm/em.h>
26#include <VBox/vmm/vmm.h>
27#include "TRPMInternal.h"
28#include <VBox/vmm/vm.h>
29
30#include <VBox/err.h>
31#include <iprt/assert.h>
32#include <iprt/asm.h>
33#include <iprt/x86.h>
34#include <VBox/log.h>
35#include <VBox/vmm/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 Pointer to the VM.
50 * @param iTrap Trap number to install handler [0..255].
51 * @param pfnHandler Pointer to the handler. Use NULL for uninstalling the handler.
52 */
53VMMRCDECL(int) TRPMGCSetTempHandler(PVM pVM, unsigned iTrap, PFNTRPMGCTRAPHANDLER pfnHandler)
54{
55 /*
56 * Validate input.
57 */
58 if (iTrap >= RT_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] = (RTRCPTR)(uintptr_t)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 Pointer to the VM.
79 * @param rc The return code for host context.
80 */
81VMMRCDECL(void) TRPMGCHyperReturnToHost(PVM pVM, int rc)
82{
83 PVMCPU pVCpu = VMMGetCpu0(pVM);
84
85 LogFlow(("TRPMGCHyperReturnToHost: rc=%Rrc\n", rc));
86 TRPMResetTrap(pVCpu);
87 VMMGCGuestToHost(pVM, rc);
88 AssertReleaseFailed();
89}
90
91
92/**
93 * \#PF Virtual Handler callback for Guest write access to the Guest's own current IDT.
94 *
95 * @returns VBox status code (appropriate for trap handling and GC return).
96 * @param pVM Pointer to the VM.
97 * @param uErrorCode CPU Error code.
98 * @param pRegFrame Trap register frame.
99 * @param pvFault The fault address (cr2).
100 * @param pvRange The base address of the handled virtual range.
101 * @param offRange The offset of the access into this range.
102 * (If it's a EIP range this is the EIP, if not it's pvFault.)
103 */
104VMMRCDECL(int) trpmRCGuestIDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
105{
106 PVMCPU pVCpu = VMMGetCpu0(pVM);
107 uint16_t cbIDT;
108 RTGCPTR GCPtrIDT = (RTGCPTR)CPUMGetGuestIDTR(pVCpu, &cbIDT);
109#ifdef VBOX_STRICT
110 RTGCPTR GCPtrIDTEnd = (RTGCPTR)((RTGCUINTPTR)GCPtrIDT + cbIDT + 1);
111#endif
112 uint32_t iGate = ((RTGCUINTPTR)pvFault - (RTGCUINTPTR)GCPtrIDT)/sizeof(VBOXIDTE);
113
114 AssertMsg(offRange < (uint32_t)cbIDT+1, ("pvFault=%RGv GCPtrIDT=%RGv-%RGv pvRange=%RGv\n", pvFault, GCPtrIDT, GCPtrIDTEnd, pvRange));
115 Assert((RTGCPTR)(RTRCUINTPTR)pvRange == GCPtrIDT);
116 NOREF(uErrorCode);
117
118#if 0
119 /* Note! this causes problems in Windows XP as instructions following the update can be dangerous (str eax has been seen) */
120 /* Note! not going back to ring 3 could make the code scanner miss them. */
121 /* Check if we can handle the write here. */
122 if ( iGate != 3 /* Gate 3 is handled differently; could do it here as well, but let ring 3 handle this case for now. */
123 && !ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iGate)) /* Passthru gates need special attention too. */
124 {
125 uint32_t cb;
126 int rc = EMInterpretInstructionEx(pVM, pVCpu, pRegFrame, pvFault, &cb);
127 if (RT_SUCCESS(rc) && cb)
128 {
129 uint32_t iGate1 = (offRange + cb - 1)/sizeof(VBOXIDTE);
130
131 Log(("trpmRCGuestIDTWriteHandler: write to gate %x (%x) offset %x cb=%d\n", iGate, iGate1, offRange, cb));
132
133 trpmClearGuestTrapHandler(pVM, iGate);
134 if (iGate != iGate1)
135 trpmClearGuestTrapHandler(pVM, iGate1);
136
137 STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTHandled);
138 return VINF_SUCCESS;
139 }
140 }
141#else
142 NOREF(iGate);
143#endif
144
145 Log(("trpmRCGuestIDTWriteHandler: eip=%RGv write to gate %x offset %x\n", pRegFrame->eip, iGate, offRange));
146
147 /** @todo Check which IDT entry and keep the update cost low in TRPMR3SyncIDT() and CSAMCheckGates(). */
148 VMCPU_FF_SET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
149
150 STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTFault);
151 return VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT;
152}
153
154
155/**
156 * \#PF Virtual Handler callback for Guest write access to the VBox shadow IDT.
157 *
158 * @returns VBox status code (appropriate for trap handling and GC return).
159 * @param pVM Pointer to the VM.
160 * @param uErrorCode CPU Error code.
161 * @param pRegFrame Trap register frame.
162 * @param pvFault The fault address (cr2).
163 * @param pvRange The base address of the handled virtual range.
164 * @param offRange The offset of the access into this range.
165 * (If it's a EIP range this is the EIP, if not it's pvFault.)
166 */
167VMMRCDECL(int) trpmRCShadowIDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
168{
169 PVMCPU pVCpu = VMMGetCpu0(pVM);
170 LogRel(("FATAL ERROR: trpmRCShadowIDTWriteHandler: eip=%08X pvFault=%RGv pvRange=%08X\r\n", pRegFrame->eip, pvFault, pvRange));
171 NOREF(uErrorCode); NOREF(offRange);
172
173 /*
174 * If we ever get here, then the guest has executed an SIDT instruction
175 * that we failed to patch. In theory this could be very bad, but there
176 * are nasty applications out there that install device drivers that mess
177 * with the guest's IDT. In those cases, it's quite ok to simply ignore
178 * the writes and pretend success.
179 */
180 DISSTATE Dis;
181 int rc = EMInterpretDisasOne(pVM, pVCpu, pRegFrame, &Dis, NULL);
182 if (rc == VINF_SUCCESS)
183 {
184 /* Just ignore the write. */
185 pRegFrame->eip += Dis.cbInstr;
186 return VINF_SUCCESS;
187 }
188
189 return VERR_TRPM_SHADOW_IDT_WRITE;
190}
191
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