VirtualBox

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

Last change on this file since 78177 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 6.8 KB
Line 
1/* $Id: TRPMRC.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * TRPM - The Trap Monitor, Guest Context
4 */
5
6/*
7 * Copyright (C) 2006-2019 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 code.
49 * @param pVM The cross context VM structure.
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 The cross context VM structure.
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 VMMRCGuestToHost(pVM, rc);
88 AssertReleaseFailed();
89}
90
91
92/**
93 * @callback_method_impl{FNPGMRCVIRTPFHANDLER,
94 * \#PF Virtual Handler callback for Guest write access to the Guest's own current IDT.}
95 */
96DECLEXPORT(VBOXSTRICTRC) trpmRCGuestIDTWritePfHandler(PVM pVM, PVMCPU pVCpu, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
97 RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange, void *pvUser)
98{
99 uint16_t cbIDT;
100 RTGCPTR GCPtrIDT = (RTGCPTR)CPUMGetGuestIDTR(pVCpu, &cbIDT);
101#ifdef VBOX_STRICT
102 RTGCPTR GCPtrIDTEnd = (RTGCPTR)((RTGCUINTPTR)GCPtrIDT + cbIDT + 1);
103#endif
104 uint32_t iGate = ((RTGCUINTPTR)pvFault - (RTGCUINTPTR)GCPtrIDT)/sizeof(VBOXIDTE);
105 RT_NOREF_PV(offRange); RT_NOREF_PV(pvRange); RT_NOREF_PV(pRegFrame); RT_NOREF_PV(pVM);
106
107 AssertMsg(offRange < (uint32_t)cbIDT+1, ("pvFault=%RGv GCPtrIDT=%RGv-%RGv pvRange=%RGv\n", pvFault, GCPtrIDT, GCPtrIDTEnd, pvRange));
108 Assert((RTGCPTR)(RTRCUINTPTR)pvRange == GCPtrIDT);
109 NOREF(uErrorCode); NOREF(pvUser);
110
111#if 0
112 /* Note! this causes problems in Windows XP as instructions following the update can be dangerous (str eax has been seen) */
113 /* Note! not going back to ring 3 could make the code scanner miss them. */
114 /* Check if we can handle the write here. */
115 if ( iGate != 3 /* Gate 3 is handled differently; could do it here as well, but let ring 3 handle this case for now. */
116 && !ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iGate)) /* Passthru gates need special attention too. */
117 {
118 uint32_t cb;
119 int rc = EMInterpretInstructionEx(pVM, pVCpu, pRegFrame, pvFault, &cb);
120 if (RT_SUCCESS(rc) && cb)
121 {
122 uint32_t iGate1 = (offRange + cb - 1)/sizeof(VBOXIDTE);
123
124 Log(("trpmRCGuestIDTWriteHandler: write to gate %x (%x) offset %x cb=%d\n", iGate, iGate1, offRange, cb));
125
126 trpmClearGuestTrapHandler(pVM, iGate);
127 if (iGate != iGate1)
128 trpmClearGuestTrapHandler(pVM, iGate1);
129
130 STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTHandled);
131 return VINF_SUCCESS;
132 }
133 }
134#else
135 NOREF(iGate);
136#endif
137
138 Log(("trpmRCGuestIDTWritePfHandler: eip=%RGv write to gate %x offset %x\n", pRegFrame->eip, iGate, offRange));
139
140 /** @todo Check which IDT entry and keep the update cost low in TRPMR3SyncIDT() and CSAMCheckGates(). */
141 VMCPU_FF_SET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
142
143 STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTFault);
144 return VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT;
145}
146
147
148/**
149 * @callback_method_impl{FNPGMRCVIRTPFHANDLER,
150 * \#PF Virtual Handler callback for Guest write access to the VBox shadow IDT.}
151 */
152DECLEXPORT(VBOXSTRICTRC) trpmRCShadowIDTWritePfHandler(PVM pVM, PVMCPU pVCpu, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame,
153 RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange, void *pvUser)
154{
155 LogRel(("FATAL ERROR: trpmRCShadowIDTWritePfHandler: eip=%08X pvFault=%RGv pvRange=%08RGv\r\n", pRegFrame->eip, pvFault, pvRange));
156 NOREF(uErrorCode); NOREF(offRange); NOREF(pvUser);
157
158 /*
159 * If we ever get here, then the guest has *probably* executed an SIDT
160 * instruction that we failed to patch. In theory this could be very bad,
161 * but there are nasty applications out there that install device drivers
162 * that mess with the guest's IDT. In those cases, it's quite ok to simply
163 * ignore the writes and pretend success.
164 *
165 * Another posibility is that the guest is touching some page memory and
166 * it having nothing to do with our IDT or anything like that, just a
167 * potential conflict that we didn't discover in time.
168 */
169 DISSTATE Dis;
170 int rc = EMInterpretDisasCurrent(pVM, pVCpu, &Dis, NULL);
171 if (rc == VINF_SUCCESS)
172 {
173 /* Just ignore the write. */
174 pRegFrame->eip += Dis.cbInstr;
175 return VINF_SUCCESS;
176 }
177
178 return VERR_TRPM_SHADOW_IDT_WRITE;
179}
180
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