VirtualBox

source: vbox/trunk/src/VBox/VMM/TRPM.cpp@ 17206

Last change on this file since 17206 was 16478, checked in by vboxsync, 16 years ago

Disable usage of the 0x80 idt gate on 32 bits Windows too. (raw mode only)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 72.7 KB
Line 
1/* $Id: TRPM.cpp 16478 2009-02-03 10:07:55Z vboxsync $ */
2/** @file
3 * TRPM - The Trap Monitor.
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/** @page pg_trpm TRPM - The Trap Monitor
23 *
24 * The Trap Monitor (TRPM) is responsible for all trap and interrupt handling in
25 * the VMM. It plays a major role in raw-mode execution and a lesser one in the
26 * hardware assisted mode.
27 *
28 * Note first, the following will use trap as a collective term for faults,
29 * aborts and traps.
30 *
31 * @see grp_trpm
32 *
33 *
34 * @section sec_trpm_rc Raw-Mode Context
35 *
36 * When executing in the raw-mode context, TRPM will be managing the IDT and
37 * processing all traps and interrupts. It will also monitor the guest IDT
38 * because CSAM wishes to know about changes to it (trap/interrupt/syscall
39 * handler patching) and TRPM needs to keep the #\BP gate in sync (ring-3
40 * considerations). See TRPMR3SyncIDT and CSAMR3CheckGates.
41 *
42 * External interrupts will be forwarded to the host context by the quickest
43 * possible route where they will be reasserted. The other events will be
44 * categorized into virtualization traps, genuine guest traps and hypervisor
45 * traps. The latter group may be recoverable depending on when they happen and
46 * whether there is a handler for it, otherwise it will cause a guru meditation.
47 *
48 * TRPM disgishishes the between the first two (virt and guest traps) and the
49 * latter (hyper) by checking the CPL of the trapping code, if CPL == 0 then
50 * it's a hyper trap otherwise it's a virt/guest trap. There are three trap
51 * dispatcher tables, one ad-hoc for one time traps registered via
52 * TRPMGCSetTempHandler(), one for hyper traps and one for virt/guest traps.
53 * The latter two live in TRPMGCHandlersA.asm, the former in the VM structure.
54 *
55 * The raw-mode context trap handlers found in TRPMGCHandlers.cpp (for the most
56 * part), will call up the other VMM sub-systems depending on what it things
57 * happens. The two most busy traps are page faults (\#PF) and general
58 * protection fault/trap (\#GP).
59 *
60 * Before resuming guest code after having taken a virtualization trap or
61 * injected a guest trap, TRPM will check for pending forced action and
62 * every now and again let TM check for timed out timers. This allows code that
63 * is being executed as part of virtualization traps to signal ring-3 exits,
64 * page table resyncs and similar without necessarily using the status code. It
65 * also make sure we're more responsive to timers and requests from other
66 * threads (necessarily running on some different core/cpu in most cases).
67 *
68 *
69 * @section sec_trpm_all All Contexts
70 *
71 * TRPM will also dispatch / inject interrupts and traps to the guest, both when
72 * in raw-mode and when in hardware assisted mode. See TRPMInject().
73 *
74 */
75
76/*******************************************************************************
77* Header Files *
78*******************************************************************************/
79#define LOG_GROUP LOG_GROUP_TRPM
80#include <VBox/trpm.h>
81#include <VBox/cpum.h>
82#include <VBox/selm.h>
83#include <VBox/ssm.h>
84#include <VBox/pdmapi.h>
85#include <VBox/pgm.h>
86#include <VBox/dbgf.h>
87#include <VBox/mm.h>
88#include <VBox/stam.h>
89#include <VBox/csam.h>
90#include <VBox/patm.h>
91#include "TRPMInternal.h"
92#include <VBox/vm.h>
93#include <VBox/em.h>
94#include <VBox/rem.h>
95#include <VBox/hwaccm.h>
96
97#include <VBox/err.h>
98#include <VBox/param.h>
99#include <VBox/log.h>
100#include <iprt/assert.h>
101#include <iprt/asm.h>
102#include <iprt/string.h>
103#include <iprt/alloc.h>
104
105
106/*******************************************************************************
107* Structures and Typedefs *
108*******************************************************************************/
109/**
110 * Trap handler function.
111 * @todo need to specialize this as we go along.
112 */
113typedef enum TRPMHANDLER
114{
115 /** Generic Interrupt handler. */
116 TRPM_HANDLER_INT = 0,
117 /** Generic Trap handler. */
118 TRPM_HANDLER_TRAP,
119 /** Trap 8 (\#DF) handler. */
120 TRPM_HANDLER_TRAP_08,
121 /** Trap 12 (\#MC) handler. */
122 TRPM_HANDLER_TRAP_12,
123 /** Max. */
124 TRPM_HANDLER_MAX
125} TRPMHANDLER, *PTRPMHANDLER;
126
127
128/*******************************************************************************
129* Global Variables *
130*******************************************************************************/
131/** Preinitialized IDT.
132 * The u16OffsetLow is a value of the TRPMHANDLER enum which TRPMR3Relocate()
133 * will use to pick the right address. The u16SegSel is always VMM CS.
134 */
135static VBOXIDTE_GENERIC g_aIdt[256] =
136{
137/* special trap handler - still, this is an interrupt gate not a trap gate... */
138#define IDTE_TRAP(enm) { (unsigned)enm, 0, 0, VBOX_IDTE_TYPE1, VBOX_IDTE_TYPE2_INT_32, 0, 1, 0 }
139/* generic trap handler. */
140#define IDTE_TRAP_GEN() IDTE_TRAP(TRPM_HANDLER_TRAP)
141/* special interrupt handler. */
142#define IDTE_INT(enm) { (unsigned)enm, 0, 0, VBOX_IDTE_TYPE1, VBOX_IDTE_TYPE2_INT_32, 0, 1, 0 }
143/* generic interrupt handler. */
144#define IDTE_INT_GEN() IDTE_INT(TRPM_HANDLER_INT)
145/* special task gate IDT entry (for critical exceptions like #DF). */
146#define IDTE_TASK(enm) { (unsigned)enm, 0, 0, VBOX_IDTE_TYPE1, VBOX_IDTE_TYPE2_TASK, 0, 1, 0 }
147/* draft, fixme later when the handler is written. */
148#define IDTE_RESERVED() { 0, 0, 0, 0, 0, 0, 0, 0 }
149
150 /* N - M M - T - C - D i */
151 /* o - n o - y - o - e p */
152 /* - e n - p - d - s t */
153 /* - i - e - e - c . */
154 /* - c - - - r */
155 /* ============================================================= */
156 IDTE_TRAP_GEN(), /* 0 - #DE - F - N - Divide error */
157 IDTE_TRAP_GEN(), /* 1 - #DB - F/T - N - Single step, INT 1 instruction */
158#ifdef VBOX_WITH_NMI
159 IDTE_TRAP_GEN(), /* 2 - - I - N - Non-Maskable Interrupt (NMI) */
160#else
161 IDTE_INT_GEN(), /* 2 - - I - N - Non-Maskable Interrupt (NMI) */
162#endif
163 IDTE_TRAP_GEN(), /* 3 - #BP - T - N - Breakpoint, INT 3 instruction. */
164 IDTE_TRAP_GEN(), /* 4 - #OF - T - N - Overflow, INTO instruction. */
165 IDTE_TRAP_GEN(), /* 5 - #BR - F - N - BOUND Range Exceeded, BOUND instruction. */
166 IDTE_TRAP_GEN(), /* 6 - #UD - F - N - Undefined(/Invalid) Opcode. */
167 IDTE_TRAP_GEN(), /* 7 - #NM - F - N - Device not available, FP or (F)WAIT instruction. */
168 IDTE_TASK(TRPM_HANDLER_TRAP_08), /* 8 - #DF - A - 0 - Double fault. */
169 IDTE_TRAP_GEN(), /* 9 - - F - N - Coprocessor Segment Overrun (obsolete). */
170 IDTE_TRAP_GEN(), /* a - #TS - F - Y - Invalid TSS, Taskswitch or TSS access. */
171 IDTE_TRAP_GEN(), /* b - #NP - F - Y - Segment not present. */
172 IDTE_TRAP_GEN(), /* c - #SS - F - Y - Stack-Segment fault. */
173 IDTE_TRAP_GEN(), /* d - #GP - F - Y - General protection fault. */
174 IDTE_TRAP_GEN(), /* e - #PF - F - Y - Page fault. - interrupt gate!!! */
175 IDTE_RESERVED(), /* f - - - - Intel Reserved. Do not use. */
176 IDTE_TRAP_GEN(), /* 10 - #MF - F - N - x86 FPU Floating-Point Error (Math fault), FP or (F)WAIT instruction. */
177 IDTE_TRAP_GEN(), /* 11 - #AC - F - 0 - Alignment Check. */
178 IDTE_TRAP(TRPM_HANDLER_TRAP_12), /* 12 - #MC - A - N - Machine Check. */
179 IDTE_TRAP_GEN(), /* 13 - #XF - F - N - SIMD Floating-Point Exception. */
180 IDTE_RESERVED(), /* 14 - - - - Intel Reserved. Do not use. */
181 IDTE_RESERVED(), /* 15 - - - - Intel Reserved. Do not use. */
182 IDTE_RESERVED(), /* 16 - - - - Intel Reserved. Do not use. */
183 IDTE_RESERVED(), /* 17 - - - - Intel Reserved. Do not use. */
184 IDTE_RESERVED(), /* 18 - - - - Intel Reserved. Do not use. */
185 IDTE_RESERVED(), /* 19 - - - - Intel Reserved. Do not use. */
186 IDTE_RESERVED(), /* 1a - - - - Intel Reserved. Do not use. */
187 IDTE_RESERVED(), /* 1b - - - - Intel Reserved. Do not use. */
188 IDTE_RESERVED(), /* 1c - - - - Intel Reserved. Do not use. */
189 IDTE_RESERVED(), /* 1d - - - - Intel Reserved. Do not use. */
190 IDTE_RESERVED(), /* 1e - - - - Intel Reserved. Do not use. */
191 IDTE_RESERVED(), /* 1f - - - - Intel Reserved. Do not use. */
192 IDTE_INT_GEN(), /* 20 - - I - - User defined Interrupts, external of INT n. */
193 IDTE_INT_GEN(), /* 21 - - I - - User defined Interrupts, external of INT n. */
194 IDTE_INT_GEN(), /* 22 - - I - - User defined Interrupts, external of INT n. */
195 IDTE_INT_GEN(), /* 23 - - I - - User defined Interrupts, external of INT n. */
196 IDTE_INT_GEN(), /* 24 - - I - - User defined Interrupts, external of INT n. */
197 IDTE_INT_GEN(), /* 25 - - I - - User defined Interrupts, external of INT n. */
198 IDTE_INT_GEN(), /* 26 - - I - - User defined Interrupts, external of INT n. */
199 IDTE_INT_GEN(), /* 27 - - I - - User defined Interrupts, external of INT n. */
200 IDTE_INT_GEN(), /* 28 - - I - - User defined Interrupts, external of INT n. */
201 IDTE_INT_GEN(), /* 29 - - I - - User defined Interrupts, external of INT n. */
202 IDTE_INT_GEN(), /* 2a - - I - - User defined Interrupts, external of INT n. */
203 IDTE_INT_GEN(), /* 2b - - I - - User defined Interrupts, external of INT n. */
204 IDTE_INT_GEN(), /* 2c - - I - - User defined Interrupts, external of INT n. */
205 IDTE_INT_GEN(), /* 2d - - I - - User defined Interrupts, external of INT n. */
206 IDTE_INT_GEN(), /* 2e - - I - - User defined Interrupts, external of INT n. */
207 IDTE_INT_GEN(), /* 2f - - I - - User defined Interrupts, external of INT n. */
208 IDTE_INT_GEN(), /* 30 - - I - - User defined Interrupts, external of INT n. */
209 IDTE_INT_GEN(), /* 31 - - I - - User defined Interrupts, external of INT n. */
210 IDTE_INT_GEN(), /* 32 - - I - - User defined Interrupts, external of INT n. */
211 IDTE_INT_GEN(), /* 33 - - I - - User defined Interrupts, external of INT n. */
212 IDTE_INT_GEN(), /* 34 - - I - - User defined Interrupts, external of INT n. */
213 IDTE_INT_GEN(), /* 35 - - I - - User defined Interrupts, external of INT n. */
214 IDTE_INT_GEN(), /* 36 - - I - - User defined Interrupts, external of INT n. */
215 IDTE_INT_GEN(), /* 37 - - I - - User defined Interrupts, external of INT n. */
216 IDTE_INT_GEN(), /* 38 - - I - - User defined Interrupts, external of INT n. */
217 IDTE_INT_GEN(), /* 39 - - I - - User defined Interrupts, external of INT n. */
218 IDTE_INT_GEN(), /* 3a - - I - - User defined Interrupts, external of INT n. */
219 IDTE_INT_GEN(), /* 3b - - I - - User defined Interrupts, external of INT n. */
220 IDTE_INT_GEN(), /* 3c - - I - - User defined Interrupts, external of INT n. */
221 IDTE_INT_GEN(), /* 3d - - I - - User defined Interrupts, external of INT n. */
222 IDTE_INT_GEN(), /* 3e - - I - - User defined Interrupts, external of INT n. */
223 IDTE_INT_GEN(), /* 3f - - I - - User defined Interrupts, external of INT n. */
224 IDTE_INT_GEN(), /* 40 - - I - - User defined Interrupts, external of INT n. */
225 IDTE_INT_GEN(), /* 41 - - I - - User defined Interrupts, external of INT n. */
226 IDTE_INT_GEN(), /* 42 - - I - - User defined Interrupts, external of INT n. */
227 IDTE_INT_GEN(), /* 43 - - I - - User defined Interrupts, external of INT n. */
228 IDTE_INT_GEN(), /* 44 - - I - - User defined Interrupts, external of INT n. */
229 IDTE_INT_GEN(), /* 45 - - I - - User defined Interrupts, external of INT n. */
230 IDTE_INT_GEN(), /* 46 - - I - - User defined Interrupts, external of INT n. */
231 IDTE_INT_GEN(), /* 47 - - I - - User defined Interrupts, external of INT n. */
232 IDTE_INT_GEN(), /* 48 - - I - - User defined Interrupts, external of INT n. */
233 IDTE_INT_GEN(), /* 49 - - I - - User defined Interrupts, external of INT n. */
234 IDTE_INT_GEN(), /* 4a - - I - - User defined Interrupts, external of INT n. */
235 IDTE_INT_GEN(), /* 4b - - I - - User defined Interrupts, external of INT n. */
236 IDTE_INT_GEN(), /* 4c - - I - - User defined Interrupts, external of INT n. */
237 IDTE_INT_GEN(), /* 4d - - I - - User defined Interrupts, external of INT n. */
238 IDTE_INT_GEN(), /* 4e - - I - - User defined Interrupts, external of INT n. */
239 IDTE_INT_GEN(), /* 4f - - I - - User defined Interrupts, external of INT n. */
240 IDTE_INT_GEN(), /* 50 - - I - - User defined Interrupts, external of INT n. */
241 IDTE_INT_GEN(), /* 51 - - I - - User defined Interrupts, external of INT n. */
242 IDTE_INT_GEN(), /* 52 - - I - - User defined Interrupts, external of INT n. */
243 IDTE_INT_GEN(), /* 53 - - I - - User defined Interrupts, external of INT n. */
244 IDTE_INT_GEN(), /* 54 - - I - - User defined Interrupts, external of INT n. */
245 IDTE_INT_GEN(), /* 55 - - I - - User defined Interrupts, external of INT n. */
246 IDTE_INT_GEN(), /* 56 - - I - - User defined Interrupts, external of INT n. */
247 IDTE_INT_GEN(), /* 57 - - I - - User defined Interrupts, external of INT n. */
248 IDTE_INT_GEN(), /* 58 - - I - - User defined Interrupts, external of INT n. */
249 IDTE_INT_GEN(), /* 59 - - I - - User defined Interrupts, external of INT n. */
250 IDTE_INT_GEN(), /* 5a - - I - - User defined Interrupts, external of INT n. */
251 IDTE_INT_GEN(), /* 5b - - I - - User defined Interrupts, external of INT n. */
252 IDTE_INT_GEN(), /* 5c - - I - - User defined Interrupts, external of INT n. */
253 IDTE_INT_GEN(), /* 5d - - I - - User defined Interrupts, external of INT n. */
254 IDTE_INT_GEN(), /* 5e - - I - - User defined Interrupts, external of INT n. */
255 IDTE_INT_GEN(), /* 5f - - I - - User defined Interrupts, external of INT n. */
256 IDTE_INT_GEN(), /* 60 - - I - - User defined Interrupts, external of INT n. */
257 IDTE_INT_GEN(), /* 61 - - I - - User defined Interrupts, external of INT n. */
258 IDTE_INT_GEN(), /* 62 - - I - - User defined Interrupts, external of INT n. */
259 IDTE_INT_GEN(), /* 63 - - I - - User defined Interrupts, external of INT n. */
260 IDTE_INT_GEN(), /* 64 - - I - - User defined Interrupts, external of INT n. */
261 IDTE_INT_GEN(), /* 65 - - I - - User defined Interrupts, external of INT n. */
262 IDTE_INT_GEN(), /* 66 - - I - - User defined Interrupts, external of INT n. */
263 IDTE_INT_GEN(), /* 67 - - I - - User defined Interrupts, external of INT n. */
264 IDTE_INT_GEN(), /* 68 - - I - - User defined Interrupts, external of INT n. */
265 IDTE_INT_GEN(), /* 69 - - I - - User defined Interrupts, external of INT n. */
266 IDTE_INT_GEN(), /* 6a - - I - - User defined Interrupts, external of INT n. */
267 IDTE_INT_GEN(), /* 6b - - I - - User defined Interrupts, external of INT n. */
268 IDTE_INT_GEN(), /* 6c - - I - - User defined Interrupts, external of INT n. */
269 IDTE_INT_GEN(), /* 6d - - I - - User defined Interrupts, external of INT n. */
270 IDTE_INT_GEN(), /* 6e - - I - - User defined Interrupts, external of INT n. */
271 IDTE_INT_GEN(), /* 6f - - I - - User defined Interrupts, external of INT n. */
272 IDTE_INT_GEN(), /* 70 - - I - - User defined Interrupts, external of INT n. */
273 IDTE_INT_GEN(), /* 71 - - I - - User defined Interrupts, external of INT n. */
274 IDTE_INT_GEN(), /* 72 - - I - - User defined Interrupts, external of INT n. */
275 IDTE_INT_GEN(), /* 73 - - I - - User defined Interrupts, external of INT n. */
276 IDTE_INT_GEN(), /* 74 - - I - - User defined Interrupts, external of INT n. */
277 IDTE_INT_GEN(), /* 75 - - I - - User defined Interrupts, external of INT n. */
278 IDTE_INT_GEN(), /* 76 - - I - - User defined Interrupts, external of INT n. */
279 IDTE_INT_GEN(), /* 77 - - I - - User defined Interrupts, external of INT n. */
280 IDTE_INT_GEN(), /* 78 - - I - - User defined Interrupts, external of INT n. */
281 IDTE_INT_GEN(), /* 79 - - I - - User defined Interrupts, external of INT n. */
282 IDTE_INT_GEN(), /* 7a - - I - - User defined Interrupts, external of INT n. */
283 IDTE_INT_GEN(), /* 7b - - I - - User defined Interrupts, external of INT n. */
284 IDTE_INT_GEN(), /* 7c - - I - - User defined Interrupts, external of INT n. */
285 IDTE_INT_GEN(), /* 7d - - I - - User defined Interrupts, external of INT n. */
286 IDTE_INT_GEN(), /* 7e - - I - - User defined Interrupts, external of INT n. */
287 IDTE_INT_GEN(), /* 7f - - I - - User defined Interrupts, external of INT n. */
288 IDTE_INT_GEN(), /* 80 - - I - - User defined Interrupts, external of INT n. */
289 IDTE_INT_GEN(), /* 81 - - I - - User defined Interrupts, external of INT n. */
290 IDTE_INT_GEN(), /* 82 - - I - - User defined Interrupts, external of INT n. */
291 IDTE_INT_GEN(), /* 83 - - I - - User defined Interrupts, external of INT n. */
292 IDTE_INT_GEN(), /* 84 - - I - - User defined Interrupts, external of INT n. */
293 IDTE_INT_GEN(), /* 85 - - I - - User defined Interrupts, external of INT n. */
294 IDTE_INT_GEN(), /* 86 - - I - - User defined Interrupts, external of INT n. */
295 IDTE_INT_GEN(), /* 87 - - I - - User defined Interrupts, external of INT n. */
296 IDTE_INT_GEN(), /* 88 - - I - - User defined Interrupts, external of INT n. */
297 IDTE_INT_GEN(), /* 89 - - I - - User defined Interrupts, external of INT n. */
298 IDTE_INT_GEN(), /* 8a - - I - - User defined Interrupts, external of INT n. */
299 IDTE_INT_GEN(), /* 8b - - I - - User defined Interrupts, external of INT n. */
300 IDTE_INT_GEN(), /* 8c - - I - - User defined Interrupts, external of INT n. */
301 IDTE_INT_GEN(), /* 8d - - I - - User defined Interrupts, external of INT n. */
302 IDTE_INT_GEN(), /* 8e - - I - - User defined Interrupts, external of INT n. */
303 IDTE_INT_GEN(), /* 8f - - I - - User defined Interrupts, external of INT n. */
304 IDTE_INT_GEN(), /* 90 - - I - - User defined Interrupts, external of INT n. */
305 IDTE_INT_GEN(), /* 91 - - I - - User defined Interrupts, external of INT n. */
306 IDTE_INT_GEN(), /* 92 - - I - - User defined Interrupts, external of INT n. */
307 IDTE_INT_GEN(), /* 93 - - I - - User defined Interrupts, external of INT n. */
308 IDTE_INT_GEN(), /* 94 - - I - - User defined Interrupts, external of INT n. */
309 IDTE_INT_GEN(), /* 95 - - I - - User defined Interrupts, external of INT n. */
310 IDTE_INT_GEN(), /* 96 - - I - - User defined Interrupts, external of INT n. */
311 IDTE_INT_GEN(), /* 97 - - I - - User defined Interrupts, external of INT n. */
312 IDTE_INT_GEN(), /* 98 - - I - - User defined Interrupts, external of INT n. */
313 IDTE_INT_GEN(), /* 99 - - I - - User defined Interrupts, external of INT n. */
314 IDTE_INT_GEN(), /* 9a - - I - - User defined Interrupts, external of INT n. */
315 IDTE_INT_GEN(), /* 9b - - I - - User defined Interrupts, external of INT n. */
316 IDTE_INT_GEN(), /* 9c - - I - - User defined Interrupts, external of INT n. */
317 IDTE_INT_GEN(), /* 9d - - I - - User defined Interrupts, external of INT n. */
318 IDTE_INT_GEN(), /* 9e - - I - - User defined Interrupts, external of INT n. */
319 IDTE_INT_GEN(), /* 9f - - I - - User defined Interrupts, external of INT n. */
320 IDTE_INT_GEN(), /* a0 - - I - - User defined Interrupts, external of INT n. */
321 IDTE_INT_GEN(), /* a1 - - I - - User defined Interrupts, external of INT n. */
322 IDTE_INT_GEN(), /* a2 - - I - - User defined Interrupts, external of INT n. */
323 IDTE_INT_GEN(), /* a3 - - I - - User defined Interrupts, external of INT n. */
324 IDTE_INT_GEN(), /* a4 - - I - - User defined Interrupts, external of INT n. */
325 IDTE_INT_GEN(), /* a5 - - I - - User defined Interrupts, external of INT n. */
326 IDTE_INT_GEN(), /* a6 - - I - - User defined Interrupts, external of INT n. */
327 IDTE_INT_GEN(), /* a7 - - I - - User defined Interrupts, external of INT n. */
328 IDTE_INT_GEN(), /* a8 - - I - - User defined Interrupts, external of INT n. */
329 IDTE_INT_GEN(), /* a9 - - I - - User defined Interrupts, external of INT n. */
330 IDTE_INT_GEN(), /* aa - - I - - User defined Interrupts, external of INT n. */
331 IDTE_INT_GEN(), /* ab - - I - - User defined Interrupts, external of INT n. */
332 IDTE_INT_GEN(), /* ac - - I - - User defined Interrupts, external of INT n. */
333 IDTE_INT_GEN(), /* ad - - I - - User defined Interrupts, external of INT n. */
334 IDTE_INT_GEN(), /* ae - - I - - User defined Interrupts, external of INT n. */
335 IDTE_INT_GEN(), /* af - - I - - User defined Interrupts, external of INT n. */
336 IDTE_INT_GEN(), /* b0 - - I - - User defined Interrupts, external of INT n. */
337 IDTE_INT_GEN(), /* b1 - - I - - User defined Interrupts, external of INT n. */
338 IDTE_INT_GEN(), /* b2 - - I - - User defined Interrupts, external of INT n. */
339 IDTE_INT_GEN(), /* b3 - - I - - User defined Interrupts, external of INT n. */
340 IDTE_INT_GEN(), /* b4 - - I - - User defined Interrupts, external of INT n. */
341 IDTE_INT_GEN(), /* b5 - - I - - User defined Interrupts, external of INT n. */
342 IDTE_INT_GEN(), /* b6 - - I - - User defined Interrupts, external of INT n. */
343 IDTE_INT_GEN(), /* b7 - - I - - User defined Interrupts, external of INT n. */
344 IDTE_INT_GEN(), /* b8 - - I - - User defined Interrupts, external of INT n. */
345 IDTE_INT_GEN(), /* b9 - - I - - User defined Interrupts, external of INT n. */
346 IDTE_INT_GEN(), /* ba - - I - - User defined Interrupts, external of INT n. */
347 IDTE_INT_GEN(), /* bb - - I - - User defined Interrupts, external of INT n. */
348 IDTE_INT_GEN(), /* bc - - I - - User defined Interrupts, external of INT n. */
349 IDTE_INT_GEN(), /* bd - - I - - User defined Interrupts, external of INT n. */
350 IDTE_INT_GEN(), /* be - - I - - User defined Interrupts, external of INT n. */
351 IDTE_INT_GEN(), /* bf - - I - - User defined Interrupts, external of INT n. */
352 IDTE_INT_GEN(), /* c0 - - I - - User defined Interrupts, external of INT n. */
353 IDTE_INT_GEN(), /* c1 - - I - - User defined Interrupts, external of INT n. */
354 IDTE_INT_GEN(), /* c2 - - I - - User defined Interrupts, external of INT n. */
355 IDTE_INT_GEN(), /* c3 - - I - - User defined Interrupts, external of INT n. */
356 IDTE_INT_GEN(), /* c4 - - I - - User defined Interrupts, external of INT n. */
357 IDTE_INT_GEN(), /* c5 - - I - - User defined Interrupts, external of INT n. */
358 IDTE_INT_GEN(), /* c6 - - I - - User defined Interrupts, external of INT n. */
359 IDTE_INT_GEN(), /* c7 - - I - - User defined Interrupts, external of INT n. */
360 IDTE_INT_GEN(), /* c8 - - I - - User defined Interrupts, external of INT n. */
361 IDTE_INT_GEN(), /* c9 - - I - - User defined Interrupts, external of INT n. */
362 IDTE_INT_GEN(), /* ca - - I - - User defined Interrupts, external of INT n. */
363 IDTE_INT_GEN(), /* cb - - I - - User defined Interrupts, external of INT n. */
364 IDTE_INT_GEN(), /* cc - - I - - User defined Interrupts, external of INT n. */
365 IDTE_INT_GEN(), /* cd - - I - - User defined Interrupts, external of INT n. */
366 IDTE_INT_GEN(), /* ce - - I - - User defined Interrupts, external of INT n. */
367 IDTE_INT_GEN(), /* cf - - I - - User defined Interrupts, external of INT n. */
368 IDTE_INT_GEN(), /* d0 - - I - - User defined Interrupts, external of INT n. */
369 IDTE_INT_GEN(), /* d1 - - I - - User defined Interrupts, external of INT n. */
370 IDTE_INT_GEN(), /* d2 - - I - - User defined Interrupts, external of INT n. */
371 IDTE_INT_GEN(), /* d3 - - I - - User defined Interrupts, external of INT n. */
372 IDTE_INT_GEN(), /* d4 - - I - - User defined Interrupts, external of INT n. */
373 IDTE_INT_GEN(), /* d5 - - I - - User defined Interrupts, external of INT n. */
374 IDTE_INT_GEN(), /* d6 - - I - - User defined Interrupts, external of INT n. */
375 IDTE_INT_GEN(), /* d7 - - I - - User defined Interrupts, external of INT n. */
376 IDTE_INT_GEN(), /* d8 - - I - - User defined Interrupts, external of INT n. */
377 IDTE_INT_GEN(), /* d9 - - I - - User defined Interrupts, external of INT n. */
378 IDTE_INT_GEN(), /* da - - I - - User defined Interrupts, external of INT n. */
379 IDTE_INT_GEN(), /* db - - I - - User defined Interrupts, external of INT n. */
380 IDTE_INT_GEN(), /* dc - - I - - User defined Interrupts, external of INT n. */
381 IDTE_INT_GEN(), /* dd - - I - - User defined Interrupts, external of INT n. */
382 IDTE_INT_GEN(), /* de - - I - - User defined Interrupts, external of INT n. */
383 IDTE_INT_GEN(), /* df - - I - - User defined Interrupts, external of INT n. */
384 IDTE_INT_GEN(), /* e0 - - I - - User defined Interrupts, external of INT n. */
385 IDTE_INT_GEN(), /* e1 - - I - - User defined Interrupts, external of INT n. */
386 IDTE_INT_GEN(), /* e2 - - I - - User defined Interrupts, external of INT n. */
387 IDTE_INT_GEN(), /* e3 - - I - - User defined Interrupts, external of INT n. */
388 IDTE_INT_GEN(), /* e4 - - I - - User defined Interrupts, external of INT n. */
389 IDTE_INT_GEN(), /* e5 - - I - - User defined Interrupts, external of INT n. */
390 IDTE_INT_GEN(), /* e6 - - I - - User defined Interrupts, external of INT n. */
391 IDTE_INT_GEN(), /* e7 - - I - - User defined Interrupts, external of INT n. */
392 IDTE_INT_GEN(), /* e8 - - I - - User defined Interrupts, external of INT n. */
393 IDTE_INT_GEN(), /* e9 - - I - - User defined Interrupts, external of INT n. */
394 IDTE_INT_GEN(), /* ea - - I - - User defined Interrupts, external of INT n. */
395 IDTE_INT_GEN(), /* eb - - I - - User defined Interrupts, external of INT n. */
396 IDTE_INT_GEN(), /* ec - - I - - User defined Interrupts, external of INT n. */
397 IDTE_INT_GEN(), /* ed - - I - - User defined Interrupts, external of INT n. */
398 IDTE_INT_GEN(), /* ee - - I - - User defined Interrupts, external of INT n. */
399 IDTE_INT_GEN(), /* ef - - I - - User defined Interrupts, external of INT n. */
400 IDTE_INT_GEN(), /* f0 - - I - - User defined Interrupts, external of INT n. */
401 IDTE_INT_GEN(), /* f1 - - I - - User defined Interrupts, external of INT n. */
402 IDTE_INT_GEN(), /* f2 - - I - - User defined Interrupts, external of INT n. */
403 IDTE_INT_GEN(), /* f3 - - I - - User defined Interrupts, external of INT n. */
404 IDTE_INT_GEN(), /* f4 - - I - - User defined Interrupts, external of INT n. */
405 IDTE_INT_GEN(), /* f5 - - I - - User defined Interrupts, external of INT n. */
406 IDTE_INT_GEN(), /* f6 - - I - - User defined Interrupts, external of INT n. */
407 IDTE_INT_GEN(), /* f7 - - I - - User defined Interrupts, external of INT n. */
408 IDTE_INT_GEN(), /* f8 - - I - - User defined Interrupts, external of INT n. */
409 IDTE_INT_GEN(), /* f9 - - I - - User defined Interrupts, external of INT n. */
410 IDTE_INT_GEN(), /* fa - - I - - User defined Interrupts, external of INT n. */
411 IDTE_INT_GEN(), /* fb - - I - - User defined Interrupts, external of INT n. */
412 IDTE_INT_GEN(), /* fc - - I - - User defined Interrupts, external of INT n. */
413 IDTE_INT_GEN(), /* fd - - I - - User defined Interrupts, external of INT n. */
414 IDTE_INT_GEN(), /* fe - - I - - User defined Interrupts, external of INT n. */
415 IDTE_INT_GEN(), /* ff - - I - - User defined Interrupts, external of INT n. */
416#undef IDTE_TRAP
417#undef IDTE_TRAP_GEN
418#undef IDTE_INT
419#undef IDTE_INT_GEN
420#undef IDTE_TASK
421#undef IDTE_UNUSED
422#undef IDTE_RESERVED
423};
424
425
426/** Enable or disable tracking of Guest's IDT. */
427#define TRPM_TRACK_GUEST_IDT_CHANGES
428
429/** Enable or disable tracking of Shadow IDT. */
430#define TRPM_TRACK_SHADOW_IDT_CHANGES
431
432/** TRPM saved state version. */
433#define TRPM_SAVED_STATE_VERSION 8
434
435
436/*******************************************************************************
437* Internal Functions *
438*******************************************************************************/
439static DECLCALLBACK(int) trpmR3Save(PVM pVM, PSSMHANDLE pSSM);
440static DECLCALLBACK(int) trpmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
441static DECLCALLBACK(int) trpmR3GuestIDTWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
442
443
444/**
445 * Initializes the Trap Manager
446 *
447 * @returns VBox status code.
448 * @param pVM The VM to operate on.
449 */
450VMMR3DECL(int) TRPMR3Init(PVM pVM)
451{
452 LogFlow(("TRPMR3Init\n"));
453
454 /*
455 * Assert sizes and alignments.
456 */
457 AssertRelease(!(RT_OFFSETOF(VM, trpm.s) & 31));
458 AssertRelease(!(RT_OFFSETOF(VM, trpm.s.aIdt) & 15));
459 AssertRelease(sizeof(pVM->trpm.s) <= sizeof(pVM->trpm.padding));
460 AssertRelease(RT_ELEMENTS(pVM->trpm.s.aGuestTrapHandler) == sizeof(pVM->trpm.s.au32IdtPatched)*8);
461
462 /*
463 * Initialize members.
464 */
465 pVM->trpm.s.offVM = RT_OFFSETOF(VM, trpm);
466 pVM->trpm.s.uActiveVector = ~0;
467 pVM->trpm.s.GuestIdtr.pIdt = RTRCPTR_MAX;
468 pVM->trpm.s.pvMonShwIdtRC = RTRCPTR_MAX;
469 pVM->trpm.s.fDisableMonitoring = false;
470 pVM->trpm.s.fSafeToDropGuestIDTMonitoring = false;
471
472 /*
473 * Read the configuration (if any).
474 */
475 PCFGMNODE pTRPMNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "TRPM");
476 if (pTRPMNode)
477 {
478 bool f;
479 int rc = CFGMR3QueryBool(pTRPMNode, "SafeToDropGuestIDTMonitoring", &f);
480 if (RT_SUCCESS(rc))
481 pVM->trpm.s.fSafeToDropGuestIDTMonitoring = f;
482 }
483
484 /* write config summary to log */
485 if (pVM->trpm.s.fSafeToDropGuestIDTMonitoring)
486 LogRel(("TRPM: Dropping Guest IDT Monitoring.\n"));
487
488 /*
489 * Initialize the IDT.
490 * The handler addresses will be set in the TRPMR3Relocate() function.
491 */
492 Assert(sizeof(pVM->trpm.s.aIdt) == sizeof(g_aIdt));
493 memcpy(&pVM->trpm.s.aIdt[0], &g_aIdt[0], sizeof(pVM->trpm.s.aIdt));
494
495 /*
496 * Register the saved state data unit.
497 */
498 int rc = SSMR3RegisterInternal(pVM, "trpm", 1, TRPM_SAVED_STATE_VERSION, sizeof(TRPM),
499 NULL, trpmR3Save, NULL,
500 NULL, trpmR3Load, NULL);
501 if (RT_FAILURE(rc))
502 return rc;
503
504 /*
505 * Statistics.
506 */
507 STAM_REG(pVM, &pVM->trpm.s.StatRCWriteGuestIDTFault, STAMTYPE_COUNTER, "/TRPM/RC/IDTWritesFault", STAMUNIT_OCCURENCES, "Guest IDT writes the we returned to R3 to handle.");
508 STAM_REG(pVM, &pVM->trpm.s.StatRCWriteGuestIDTHandled, STAMTYPE_COUNTER, "/TRPM/RC/IDTWritesHandled", STAMUNIT_OCCURENCES, "Guest IDT writes that we handled successfully.");
509 STAM_REG(pVM, &pVM->trpm.s.StatSyncIDT, STAMTYPE_PROFILE, "/PROF/TRPM/SyncIDT", STAMUNIT_TICKS_PER_CALL, "Profiling of TRPMR3SyncIDT().");
510
511 /* traps */
512 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x00], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/00", STAMUNIT_TICKS_PER_CALL, "#DE - Divide error.");
513 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x01], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/01", STAMUNIT_TICKS_PER_CALL, "#DB - Debug (single step and more).");
514 //STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x02], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/02", STAMUNIT_TICKS_PER_CALL, "NMI");
515 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x03], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/03", STAMUNIT_TICKS_PER_CALL, "#BP - Breakpoint.");
516 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x04], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/04", STAMUNIT_TICKS_PER_CALL, "#OF - Overflow.");
517 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x05], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/05", STAMUNIT_TICKS_PER_CALL, "#BR - Bound range exceeded.");
518 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x06], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/06", STAMUNIT_TICKS_PER_CALL, "#UD - Undefined opcode.");
519 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x07], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/07", STAMUNIT_TICKS_PER_CALL, "#NM - Device not available (FPU).");
520 //STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x08], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/08", STAMUNIT_TICKS_PER_CALL, "#DF - Double fault.");
521 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x09], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/09", STAMUNIT_TICKS_PER_CALL, "#?? - Coprocessor segment overrun (obsolete).");
522 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0a], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0a", STAMUNIT_TICKS_PER_CALL, "#TS - Task switch fault.");
523 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0b], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0b", STAMUNIT_TICKS_PER_CALL, "#NP - Segemnt not present.");
524 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0c], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0c", STAMUNIT_TICKS_PER_CALL, "#SS - Stack segment fault.");
525 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0d], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0d", STAMUNIT_TICKS_PER_CALL, "#GP - General protection fault.");
526 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0e], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0e", STAMUNIT_TICKS_PER_CALL, "#PF - Page fault.");
527 //STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0f], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0f", STAMUNIT_TICKS_PER_CALL, "Reserved.");
528 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x10], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/10", STAMUNIT_TICKS_PER_CALL, "#MF - Math fault..");
529 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x11], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/11", STAMUNIT_TICKS_PER_CALL, "#AC - Alignment check.");
530 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x12], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/12", STAMUNIT_TICKS_PER_CALL, "#MC - Machine check.");
531 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x13], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/13", STAMUNIT_TICKS_PER_CALL, "#XF - SIMD Floating-Point Exception.");
532
533#ifdef VBOX_WITH_STATISTICS
534 rc = MMHyperAlloc(pVM, sizeof(STAMCOUNTER) * 255, 8, MM_TAG_STAM, (void **)&pVM->trpm.s.paStatForwardedIRQR3);
535 AssertRCReturn(rc, rc);
536 pVM->trpm.s.paStatForwardedIRQRC = MMHyperR3ToRC(pVM, pVM->trpm.s.paStatForwardedIRQR3);
537 pVM->trpm.s.paStatForwardedIRQR0 = MMHyperR3ToR0(pVM, pVM->trpm.s.paStatForwardedIRQR3);
538 for (unsigned i = 0; i < 255; i++)
539 STAMR3RegisterF(pVM, &pVM->trpm.s.paStatForwardedIRQR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "Forwarded interrupts.",
540 i < 0x20 ? "/TRPM/ForwardRaw/TRAP/%02X" : "/TRPM/ForwardRaw/IRQ/%02X", i);
541#endif
542
543 STAM_REG(pVM, &pVM->trpm.s.StatForwardProfR3, STAMTYPE_PROFILE_ADV, "/TRPM/ForwardRaw/ProfR3", STAMUNIT_TICKS_PER_CALL, "Profiling TRPMForwardTrap.");
544 STAM_REG(pVM, &pVM->trpm.s.StatForwardProfRZ, STAMTYPE_PROFILE_ADV, "/TRPM/ForwardRaw/ProfRZ", STAMUNIT_TICKS_PER_CALL, "Profiling TRPMForwardTrap.");
545 STAM_REG(pVM, &pVM->trpm.s.StatForwardFailNoHandler, STAMTYPE_COUNTER, "/TRPM/ForwardRaw/FailNoHandler", STAMUNIT_OCCURENCES,"Failure to forward interrupt in raw mode.");
546 STAM_REG(pVM, &pVM->trpm.s.StatForwardFailPatchAddr, STAMTYPE_COUNTER, "/TRPM/ForwardRaw/FailPatchAddr", STAMUNIT_OCCURENCES,"Failure to forward interrupt in raw mode.");
547 STAM_REG(pVM, &pVM->trpm.s.StatForwardFailR3, STAMTYPE_COUNTER, "/TRPM/ForwardRaw/FailR3", STAMUNIT_OCCURENCES, "Failure to forward interrupt in raw mode.");
548 STAM_REG(pVM, &pVM->trpm.s.StatForwardFailRZ, STAMTYPE_COUNTER, "/TRPM/ForwardRaw/FailRZ", STAMUNIT_OCCURENCES, "Failure to forward interrupt in raw mode.");
549
550 STAM_REG(pVM, &pVM->trpm.s.StatTrap0dDisasm, STAMTYPE_PROFILE, "/TRPM/RC/Traps/0d/Disasm", STAMUNIT_TICKS_PER_CALL, "Profiling disassembly part of trpmGCTrap0dHandler.");
551 STAM_REG(pVM, &pVM->trpm.s.StatTrap0dRdTsc, STAMTYPE_COUNTER, "/TRPM/RC/Traps/0d/RdTsc", STAMUNIT_OCCURENCES, "Number of RDTSC #GPs.");
552
553 /*
554 * Default action when entering raw mode for the first time
555 */
556 VM_FF_SET(pVM, VM_FF_TRPM_SYNC_IDT);
557 return 0;
558}
559
560
561/**
562 * Applies relocations to data and code managed by this component.
563 *
564 * This function will be called at init and whenever the VMM need
565 * to relocate itself inside the GC.
566 *
567 * @param pVM The VM handle.
568 * @param offDelta Relocation delta relative to old location.
569 */
570VMMR3DECL(void) TRPMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
571{
572 LogFlow(("TRPMR3Relocate\n"));
573 /*
574 * Get the trap handler addresses.
575 *
576 * If VMMGC.gc is screwed, so are we. We'll assert here since it elsewise
577 * would make init order impossible if we should assert the presence of these
578 * exports in TRPMR3Init().
579 */
580 RTRCPTR aRCPtrs[TRPM_HANDLER_MAX] = {0};
581 int rc;
582 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerInterupt", &aRCPtrs[TRPM_HANDLER_INT]);
583 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerInterupt in VMMGC.gc!\n"));
584
585 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerGeneric", &aRCPtrs[TRPM_HANDLER_TRAP]);
586 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerGeneric in VMMGC.gc!\n"));
587
588 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerTrap08", &aRCPtrs[TRPM_HANDLER_TRAP_08]);
589 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerTrap08 in VMMGC.gc!\n"));
590
591 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerTrap12", &aRCPtrs[TRPM_HANDLER_TRAP_12]);
592 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerTrap12 in VMMGC.gc!\n"));
593
594 RTSEL SelCS = CPUMGetHyperCS(pVM);
595
596 /*
597 * Iterate the idt and set the addresses.
598 */
599 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[0];
600 PVBOXIDTE_GENERIC pIdteTemplate = &g_aIdt[0];
601 for (unsigned i = 0; i < RT_ELEMENTS(pVM->trpm.s.aIdt); i++, pIdte++, pIdteTemplate++)
602 {
603 if ( pIdte->Gen.u1Present
604 && !ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], i)
605 )
606 {
607 Assert(pIdteTemplate->u16OffsetLow < TRPM_HANDLER_MAX);
608 RTGCPTR Offset = aRCPtrs[pIdteTemplate->u16OffsetLow];
609 switch (pIdteTemplate->u16OffsetLow)
610 {
611 /*
612 * Generic handlers have different entrypoints for each possible
613 * vector number. These entrypoints makes a sort of an array with
614 * 8 byte entries where the vector number is the index.
615 * See TRPMGCHandlersA.asm for details.
616 */
617 case TRPM_HANDLER_INT:
618 case TRPM_HANDLER_TRAP:
619 Offset += i * 8;
620 break;
621 case TRPM_HANDLER_TRAP_12:
622 break;
623 case TRPM_HANDLER_TRAP_08:
624 /* Handle #DF Task Gate in special way. */
625 pIdte->Gen.u16SegSel = SELMGetTrap8Selector(pVM);
626 pIdte->Gen.u16OffsetLow = 0;
627 pIdte->Gen.u16OffsetHigh = 0;
628 SELMSetTrap8EIP(pVM, Offset);
629 continue;
630 }
631 /* (non-task gates only ) */
632 pIdte->Gen.u16OffsetLow = Offset & 0xffff;
633 pIdte->Gen.u16OffsetHigh = Offset >> 16;
634 pIdte->Gen.u16SegSel = SelCS;
635 }
636 }
637
638 /*
639 * Update IDTR (limit is including!).
640 */
641 CPUMSetHyperIDTR(pVM, VM_RC_ADDR(pVM, &pVM->trpm.s.aIdt[0]), sizeof(pVM->trpm.s.aIdt)-1);
642
643 if (!pVM->trpm.s.fDisableMonitoring)
644 {
645#ifdef TRPM_TRACK_SHADOW_IDT_CHANGES
646 if (pVM->trpm.s.pvMonShwIdtRC != RTRCPTR_MAX)
647 {
648 rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.pvMonShwIdtRC);
649 AssertRC(rc);
650 }
651 pVM->trpm.s.pvMonShwIdtRC = VM_RC_ADDR(pVM, &pVM->trpm.s.aIdt[0]);
652 rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_HYPERVISOR, pVM->trpm.s.pvMonShwIdtRC, pVM->trpm.s.pvMonShwIdtRC + sizeof(pVM->trpm.s.aIdt) - 1,
653 0, 0, "trpmRCShadowIDTWriteHandler", 0, "Shadow IDT write access handler");
654 AssertRC(rc);
655#endif
656 }
657
658 /* Relocate IDT handlers for forwarding guest traps/interrupts. */
659 for (uint32_t iTrap = 0; iTrap < RT_ELEMENTS(pVM->trpm.s.aGuestTrapHandler); iTrap++)
660 {
661 if (pVM->trpm.s.aGuestTrapHandler[iTrap] != TRPM_INVALID_HANDLER)
662 {
663 Log(("TRPMR3Relocate: iGate=%2X Handler %RRv -> %RRv\n", iTrap, pVM->trpm.s.aGuestTrapHandler[iTrap], pVM->trpm.s.aGuestTrapHandler[iTrap] + offDelta));
664 pVM->trpm.s.aGuestTrapHandler[iTrap] += offDelta;
665 }
666
667 if (ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iTrap))
668 {
669 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[iTrap];
670 RTGCPTR pHandler = VBOXIDTE_OFFSET(*pIdte);
671
672 Log(("TRPMR3Relocate: *iGate=%2X Handler %RGv -> %RGv\n", iTrap, pHandler, pHandler + offDelta));
673 pHandler += offDelta;
674
675 pIdte->Gen.u16OffsetHigh = pHandler >> 16;
676 pIdte->Gen.u16OffsetLow = pHandler & 0xFFFF;
677
678 }
679 }
680
681#ifdef VBOX_WITH_STATISTICS
682 pVM->trpm.s.paStatForwardedIRQRC += offDelta;
683 pVM->trpm.s.paStatForwardedIRQR0 = MMHyperR3ToR0(pVM, pVM->trpm.s.paStatForwardedIRQR3);
684#endif
685}
686
687
688/**
689 * Terminates the Trap Manager
690 *
691 * @returns VBox status code.
692 * @param pVM The VM to operate on.
693 */
694VMMR3DECL(int) TRPMR3Term(PVM pVM)
695{
696 NOREF(pVM);
697 return 0;
698}
699
700
701/**
702 * The VM is being reset.
703 *
704 * For the TRPM component this means that any IDT write monitors
705 * needs to be removed, any pending trap cleared, and the IDT reset.
706 *
707 * @param pVM VM handle.
708 */
709VMMR3DECL(void) TRPMR3Reset(PVM pVM)
710{
711 /*
712 * Deregister any virtual handlers.
713 */
714#ifdef TRPM_TRACK_GUEST_IDT_CHANGES
715 if (pVM->trpm.s.GuestIdtr.pIdt != RTRCPTR_MAX)
716 {
717 if (!pVM->trpm.s.fSafeToDropGuestIDTMonitoring)
718 {
719 int rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.GuestIdtr.pIdt);
720 AssertRC(rc);
721 }
722 pVM->trpm.s.GuestIdtr.pIdt = RTRCPTR_MAX;
723 }
724 pVM->trpm.s.GuestIdtr.cbIdt = 0;
725#endif
726
727 /*
728 * Reinitialize other members calling the relocator to get things right.
729 */
730 pVM->trpm.s.uActiveVector = ~0;
731 memcpy(&pVM->trpm.s.aIdt[0], &g_aIdt[0], sizeof(pVM->trpm.s.aIdt));
732 memset(pVM->trpm.s.aGuestTrapHandler, 0, sizeof(pVM->trpm.s.aGuestTrapHandler));
733 TRPMR3Relocate(pVM, 0);
734
735 /*
736 * Default action when entering raw mode for the first time
737 */
738 VM_FF_SET(pVM, VM_FF_TRPM_SYNC_IDT);
739}
740
741
742/**
743 * Execute state save operation.
744 *
745 * @returns VBox status code.
746 * @param pVM VM Handle.
747 * @param pSSM SSM operation handle.
748 */
749static DECLCALLBACK(int) trpmR3Save(PVM pVM, PSSMHANDLE pSSM)
750{
751 LogFlow(("trpmR3Save:\n"));
752
753 /*
754 * Active and saved traps.
755 */
756 PTRPM pTrpm = &pVM->trpm.s;
757 SSMR3PutUInt(pSSM, pTrpm->uActiveVector);
758 SSMR3PutUInt(pSSM, pTrpm->enmActiveType);
759 SSMR3PutGCUInt(pSSM, pTrpm->uActiveErrorCode);
760 SSMR3PutGCUIntPtr(pSSM, pTrpm->uActiveCR2);
761 SSMR3PutGCUInt(pSSM, pTrpm->uSavedVector);
762 SSMR3PutUInt(pSSM, pTrpm->enmSavedType);
763 SSMR3PutGCUInt(pSSM, pTrpm->uSavedErrorCode);
764 SSMR3PutGCUIntPtr(pSSM, pTrpm->uSavedCR2);
765 SSMR3PutGCUInt(pSSM, pTrpm->uPrevVector);
766#if 0 /** @todo Enable this (+ load change) on the next version change. */
767 SSMR3PutBool(pSSM, pTrpm->fDisableMonitoring);
768#else
769 SSMR3PutGCUInt(pSSM, pTrpm->fDisableMonitoring);
770#endif
771 SSMR3PutUInt(pSSM, VM_FF_ISSET(pVM, VM_FF_TRPM_SYNC_IDT));
772 SSMR3PutMem(pSSM, &pTrpm->au32IdtPatched[0], sizeof(pTrpm->au32IdtPatched));
773 SSMR3PutU32(pSSM, ~0); /* separator. */
774
775 /*
776 * Save any trampoline gates.
777 */
778 for (uint32_t iTrap = 0; iTrap < RT_ELEMENTS(pTrpm->aGuestTrapHandler); iTrap++)
779 {
780 if (pTrpm->aGuestTrapHandler[iTrap])
781 {
782 SSMR3PutU32(pSSM, iTrap);
783 SSMR3PutGCPtr(pSSM, pTrpm->aGuestTrapHandler[iTrap]);
784 SSMR3PutMem(pSSM, &pTrpm->aIdt[iTrap], sizeof(pTrpm->aIdt[iTrap]));
785 }
786 }
787
788 return SSMR3PutU32(pSSM, ~0); /* terminator */
789}
790
791
792/**
793 * Execute state load operation.
794 *
795 * @returns VBox status code.
796 * @param pVM VM Handle.
797 * @param pSSM SSM operation handle.
798 * @param u32Version Data layout version.
799 */
800static DECLCALLBACK(int) trpmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
801{
802 LogFlow(("trpmR3Load:\n"));
803
804 /*
805 * Validate version.
806 */
807 if (u32Version != TRPM_SAVED_STATE_VERSION)
808 {
809 AssertMsgFailed(("trpmR3Load: Invalid version u32Version=%d!\n", u32Version));
810 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
811 }
812
813 /*
814 * Call the reset function to kick out any handled gates and other potential trouble.
815 */
816 TRPMR3Reset(pVM);
817
818 /*
819 * Active and saved traps.
820 */
821 PTRPM pTrpm = &pVM->trpm.s;
822 SSMR3GetUInt(pSSM, &pTrpm->uActiveVector);
823 SSMR3GetUInt(pSSM, (uint32_t *)&pTrpm->enmActiveType);
824 SSMR3GetGCUInt(pSSM, &pTrpm->uActiveErrorCode);
825 SSMR3GetGCUIntPtr(pSSM, &pTrpm->uActiveCR2);
826 SSMR3GetGCUInt(pSSM, &pTrpm->uSavedVector);
827 SSMR3GetUInt(pSSM, (uint32_t *)&pTrpm->enmSavedType);
828 SSMR3GetGCUInt(pSSM, &pTrpm->uSavedErrorCode);
829 SSMR3GetGCUIntPtr(pSSM, &pTrpm->uSavedCR2);
830 SSMR3GetGCUInt(pSSM, &pTrpm->uPrevVector);
831#if 0 /** @todo Enable this + the corresponding save code on the next version change. */
832 SSMR3GetBool(pSSM, &pTrpm->fDisableMonitoring);
833#else
834 RTGCUINT fDisableMonitoring;
835 SSMR3GetGCUInt(pSSM, &fDisableMonitoring);
836 pTrpm->fDisableMonitoring = !!fDisableMonitoring;
837#endif
838
839 RTUINT fSyncIDT;
840 int rc = SSMR3GetUInt(pSSM, &fSyncIDT);
841 if (RT_FAILURE(rc))
842 return rc;
843 if (fSyncIDT & ~1)
844 {
845 AssertMsgFailed(("fSyncIDT=%#x\n", fSyncIDT));
846 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
847 }
848 if (fSyncIDT)
849 VM_FF_SET(pVM, VM_FF_TRPM_SYNC_IDT);
850 /* else: cleared by reset call above. */
851
852 SSMR3GetMem(pSSM, &pTrpm->au32IdtPatched[0], sizeof(pTrpm->au32IdtPatched));
853
854 /* check the separator */
855 uint32_t u32Sep;
856 rc = SSMR3GetU32(pSSM, &u32Sep);
857 if (RT_FAILURE(rc))
858 return rc;
859 if (u32Sep != (uint32_t)~0)
860 {
861 AssertMsgFailed(("u32Sep=%#x (first)\n", u32Sep));
862 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
863 }
864
865 /*
866 * Restore any trampoline gates.
867 */
868 for (;;)
869 {
870 /* gate number / terminator */
871 uint32_t iTrap;
872 rc = SSMR3GetU32(pSSM, &iTrap);
873 if (RT_FAILURE(rc))
874 return rc;
875 if (iTrap == (uint32_t)~0)
876 break;
877 if ( iTrap >= RT_ELEMENTS(pTrpm->aIdt)
878 || pTrpm->aGuestTrapHandler[iTrap])
879 {
880 AssertMsgFailed(("iTrap=%#x\n", iTrap));
881 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
882 }
883
884 /* restore the IDT entry. */
885 RTGCPTR GCPtrHandler;
886 SSMR3GetGCPtr(pSSM, &GCPtrHandler);
887 VBOXIDTE Idte;
888 rc = SSMR3GetMem(pSSM, &Idte, sizeof(Idte));
889 if (RT_FAILURE(rc))
890 return rc;
891 Assert(GCPtrHandler);
892 pTrpm->aIdt[iTrap] = Idte;
893 }
894
895 return VINF_SUCCESS;
896}
897
898
899/**
900 * Check if gate handlers were updated
901 * (callback for the VM_FF_TRPM_SYNC_IDT forced action).
902 *
903 * @returns VBox status code.
904 * @param pVM The VM handle.
905 */
906VMMR3DECL(int) TRPMR3SyncIDT(PVM pVM)
907{
908 STAM_PROFILE_START(&pVM->trpm.s.StatSyncIDT, a);
909 const bool fRawRing0 = EMIsRawRing0Enabled(pVM);
910 int rc;
911
912 if (pVM->trpm.s.fDisableMonitoring)
913 {
914 VM_FF_CLEAR(pVM, VM_FF_TRPM_SYNC_IDT);
915 return VINF_SUCCESS; /* Nothing to do */
916 }
917
918 if (fRawRing0 && CSAMIsEnabled(pVM))
919 {
920 /* Clear all handlers */
921 Log(("TRPMR3SyncIDT: Clear all trap handlers.\n"));
922 /** @todo inefficient, but simple */
923 for (unsigned iGate = 0; iGate < 256; iGate++)
924 trpmClearGuestTrapHandler(pVM, iGate);
925
926 /* Scan them all (only the first time) */
927 CSAMR3CheckGates(pVM, 0, 256);
928 }
929
930 /*
931 * Get the IDTR.
932 */
933 VBOXIDTR IDTR;
934 IDTR.pIdt = CPUMGetGuestIDTR(pVM, &IDTR.cbIdt);
935 if (!IDTR.cbIdt)
936 {
937 Log(("No IDT entries...\n"));
938 return DBGFSTOP(pVM);
939 }
940
941#ifdef TRPM_TRACK_GUEST_IDT_CHANGES
942 /*
943 * Check if Guest's IDTR has changed.
944 */
945 if ( IDTR.pIdt != pVM->trpm.s.GuestIdtr.pIdt
946 || IDTR.cbIdt != pVM->trpm.s.GuestIdtr.cbIdt)
947 {
948 Log(("TRPMR3UpdateFromCPUM: Guest's IDT is changed to pIdt=%08X cbIdt=%08X\n", IDTR.pIdt, IDTR.cbIdt));
949 if (!pVM->trpm.s.fSafeToDropGuestIDTMonitoring)
950 {
951 /*
952 * [Re]Register write virtual handler for guest's IDT.
953 */
954 if (pVM->trpm.s.GuestIdtr.pIdt != RTRCPTR_MAX)
955 {
956 rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.GuestIdtr.pIdt);
957 AssertRCReturn(rc, rc);
958 }
959 /* limit is including */
960 rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, IDTR.pIdt, IDTR.pIdt + IDTR.cbIdt /* already inclusive */,
961 0, trpmR3GuestIDTWriteHandler, "trpmRCGuestIDTWriteHandler", 0, "Guest IDT write access handler");
962
963 if (rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT)
964 {
965 /* Could be a conflict with CSAM */
966 CSAMR3RemovePage(pVM, IDTR.pIdt);
967 if (PAGE_ADDRESS(IDTR.pIdt) != PAGE_ADDRESS(IDTR.pIdt + IDTR.cbIdt))
968 CSAMR3RemovePage(pVM, IDTR.pIdt + IDTR.cbIdt);
969
970 rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, IDTR.pIdt, IDTR.pIdt + IDTR.cbIdt /* already inclusive */,
971 0, trpmR3GuestIDTWriteHandler, "trpmRCGuestIDTWriteHandler", 0, "Guest IDT write access handler");
972 }
973
974 AssertRCReturn(rc, rc);
975 }
976
977 /* Update saved Guest IDTR. */
978 pVM->trpm.s.GuestIdtr = IDTR;
979 }
980#endif
981
982 /*
983 * Sync the interrupt gate.
984 * Should probably check/sync the others too, but for now we'll handle that in #GP.
985 */
986 X86DESC Idte3;
987 rc = PGMPhysSimpleReadGCPtr(pVM, &Idte3, IDTR.pIdt + sizeof(Idte3) * 3, sizeof(Idte3));
988 if (RT_FAILURE(rc))
989 {
990 AssertMsgRC(rc, ("Failed to read IDT[3]! rc=%Rrc\n", rc));
991 return DBGFSTOP(pVM);
992 }
993 AssertRCReturn(rc, rc);
994 if (fRawRing0)
995 pVM->trpm.s.aIdt[3].Gen.u2DPL = RT_MAX(Idte3.Gen.u2Dpl, 1);
996 else
997 pVM->trpm.s.aIdt[3].Gen.u2DPL = Idte3.Gen.u2Dpl;
998
999 /*
1000 * Clear the FF and we're done.
1001 */
1002 VM_FF_CLEAR(pVM, VM_FF_TRPM_SYNC_IDT);
1003 STAM_PROFILE_STOP(&pVM->trpm.s.StatSyncIDT, a);
1004 return VINF_SUCCESS;
1005}
1006
1007
1008/**
1009 * Disable IDT monitoring and syncing
1010 *
1011 * @param pVM The VM to operate on.
1012 */
1013VMMR3DECL(void) TRPMR3DisableMonitoring(PVM pVM)
1014{
1015 /*
1016 * Deregister any virtual handlers.
1017 */
1018#ifdef TRPM_TRACK_GUEST_IDT_CHANGES
1019 if (pVM->trpm.s.GuestIdtr.pIdt != RTRCPTR_MAX)
1020 {
1021 if (!pVM->trpm.s.fSafeToDropGuestIDTMonitoring)
1022 {
1023 int rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.GuestIdtr.pIdt);
1024 AssertRC(rc);
1025 }
1026 pVM->trpm.s.GuestIdtr.pIdt = RTRCPTR_MAX;
1027 }
1028 pVM->trpm.s.GuestIdtr.cbIdt = 0;
1029#endif
1030
1031#ifdef TRPM_TRACK_SHADOW_IDT_CHANGES
1032 if (pVM->trpm.s.pvMonShwIdtRC != RTRCPTR_MAX)
1033 {
1034 int rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.pvMonShwIdtRC);
1035 AssertRC(rc);
1036 pVM->trpm.s.pvMonShwIdtRC = RTRCPTR_MAX;
1037 }
1038#endif
1039
1040 VM_FF_CLEAR(pVM, VM_FF_TRPM_SYNC_IDT);
1041
1042 pVM->trpm.s.fDisableMonitoring = true;
1043}
1044
1045
1046/**
1047 * \#PF Handler callback for virtual access handler ranges.
1048 *
1049 * Important to realize that a physical page in a range can have aliases, and
1050 * for ALL and WRITE handlers these will also trigger.
1051 *
1052 * @returns VINF_SUCCESS if the handler have carried out the operation.
1053 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
1054 * @param pVM VM Handle.
1055 * @param GCPtr The virtual address the guest is writing to. (not correct if it's an alias!)
1056 * @param pvPtr The HC mapping of that address.
1057 * @param pvBuf What the guest is reading/writing.
1058 * @param cbBuf How much it's reading/writing.
1059 * @param enmAccessType The access type.
1060 * @param pvUser User argument.
1061 */
1062static DECLCALLBACK(int) trpmR3GuestIDTWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
1063{
1064 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
1065 Log(("trpmR3GuestIDTWriteHandler: write to %RGv size %d\n", GCPtr, cbBuf));
1066 VM_FF_SET(pVM, VM_FF_TRPM_SYNC_IDT);
1067 return VINF_PGM_HANDLER_DO_DEFAULT;
1068}
1069
1070
1071/**
1072 * Clear passthrough interrupt gate handler (reset to default handler)
1073 *
1074 * @returns VBox status code.
1075 * @param pVM The VM to operate on.
1076 * @param iTrap Trap/interrupt gate number.
1077 */
1078VMMR3DECL(int) trpmR3ClearPassThroughHandler(PVM pVM, unsigned iTrap)
1079{
1080 /** @todo cleanup trpmR3ClearPassThroughHandler()! */
1081 RTRCPTR aGCPtrs[TRPM_HANDLER_MAX];
1082 int rc;
1083
1084 memset(aGCPtrs, 0, sizeof(aGCPtrs));
1085
1086 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerInterupt", &aGCPtrs[TRPM_HANDLER_INT]);
1087 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerInterupt in VMMGC.gc!\n"));
1088
1089 if ( iTrap < TRPM_HANDLER_INT_BASE
1090 || iTrap >= RT_ELEMENTS(pVM->trpm.s.aIdt))
1091 {
1092 AssertMsg(iTrap < TRPM_HANDLER_INT_BASE, ("Illegal gate number %#x!\n", iTrap));
1093 return VERR_INVALID_PARAMETER;
1094 }
1095 memcpy(&pVM->trpm.s.aIdt[iTrap], &g_aIdt[iTrap], sizeof(pVM->trpm.s.aIdt[0]));
1096
1097 /* Unmark it for relocation purposes. */
1098 ASMBitClear(&pVM->trpm.s.au32IdtPatched[0], iTrap);
1099
1100 RTSEL SelCS = CPUMGetHyperCS(pVM);
1101 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[iTrap];
1102 PVBOXIDTE_GENERIC pIdteTemplate = &g_aIdt[iTrap];
1103 if (pIdte->Gen.u1Present)
1104 {
1105 Assert(pIdteTemplate->u16OffsetLow == TRPM_HANDLER_INT);
1106 Assert(sizeof(RTRCPTR) == sizeof(aGCPtrs[0]));
1107 RTRCPTR Offset = (RTRCPTR)aGCPtrs[pIdteTemplate->u16OffsetLow];
1108
1109 /*
1110 * Generic handlers have different entrypoints for each possible
1111 * vector number. These entrypoints make a sort of an array with
1112 * 8 byte entries where the vector number is the index.
1113 * See TRPMGCHandlersA.asm for details.
1114 */
1115 Offset += iTrap * 8;
1116
1117 if (pIdte->Gen.u5Type2 != VBOX_IDTE_TYPE2_TASK)
1118 {
1119 pIdte->Gen.u16OffsetLow = Offset & 0xffff;
1120 pIdte->Gen.u16OffsetHigh = Offset >> 16;
1121 pIdte->Gen.u16SegSel = SelCS;
1122 }
1123 }
1124
1125 return VINF_SUCCESS;
1126}
1127
1128
1129/**
1130 * Check if address is a gate handler (interrupt or trap).
1131 *
1132 * @returns gate nr or ~0 is not found
1133 *
1134 * @param pVM VM handle.
1135 * @param GCPtr GC address to check.
1136 */
1137VMMR3DECL(uint32_t) TRPMR3QueryGateByHandler(PVM pVM, RTRCPTR GCPtr)
1138{
1139 for (uint32_t iTrap = 0; iTrap < RT_ELEMENTS(pVM->trpm.s.aGuestTrapHandler); iTrap++)
1140 {
1141 if (pVM->trpm.s.aGuestTrapHandler[iTrap] == GCPtr)
1142 return iTrap;
1143
1144 /* redundant */
1145 if (ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iTrap))
1146 {
1147 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[iTrap];
1148 RTGCPTR pHandler = VBOXIDTE_OFFSET(*pIdte);
1149
1150 if (pHandler == GCPtr)
1151 return iTrap;
1152 }
1153 }
1154 return ~0;
1155}
1156
1157
1158/**
1159 * Get guest trap/interrupt gate handler
1160 *
1161 * @returns Guest trap handler address or TRPM_INVALID_HANDLER if none installed
1162 * @param pVM The VM to operate on.
1163 * @param iTrap Interrupt/trap number.
1164 */
1165VMMR3DECL(RTRCPTR) TRPMR3GetGuestTrapHandler(PVM pVM, unsigned iTrap)
1166{
1167 AssertReturn(iTrap < RT_ELEMENTS(pVM->trpm.s.aIdt), TRPM_INVALID_HANDLER);
1168
1169 return pVM->trpm.s.aGuestTrapHandler[iTrap];
1170}
1171
1172
1173/**
1174 * Set guest trap/interrupt gate handler
1175 * Used for setting up trap gates used for kernel calls.
1176 *
1177 * @returns VBox status code.
1178 * @param pVM The VM to operate on.
1179 * @param iTrap Interrupt/trap number.
1180 * @param pHandler GC handler pointer
1181 */
1182VMMR3DECL(int) TRPMR3SetGuestTrapHandler(PVM pVM, unsigned iTrap, RTRCPTR pHandler)
1183{
1184 /*
1185 * Validate.
1186 */
1187 if (iTrap >= RT_ELEMENTS(pVM->trpm.s.aIdt))
1188 {
1189 AssertMsg(iTrap < TRPM_HANDLER_INT_BASE, ("Illegal gate number %d!\n", iTrap));
1190 return VERR_INVALID_PARAMETER;
1191 }
1192
1193 AssertReturn(pHandler == TRPM_INVALID_HANDLER || PATMIsPatchGCAddr(pVM, pHandler), VERR_INVALID_PARAMETER);
1194
1195 uint16_t cbIDT;
1196 RTGCPTR GCPtrIDT = CPUMGetGuestIDTR(pVM, &cbIDT);
1197 if (iTrap * sizeof(VBOXIDTE) >= cbIDT)
1198 return VERR_INVALID_PARAMETER; /* Silently ignore out of range requests. */
1199
1200 if (pHandler == TRPM_INVALID_HANDLER)
1201 {
1202 /* clear trap handler */
1203 Log(("TRPMR3SetGuestTrapHandler: clear handler %x\n", iTrap));
1204 return trpmClearGuestTrapHandler(pVM, iTrap);
1205 }
1206
1207 /*
1208 * Read the guest IDT entry.
1209 */
1210 VBOXIDTE GuestIdte;
1211 int rc = PGMPhysSimpleReadGCPtr(pVM, &GuestIdte, GCPtrIDT + iTrap * sizeof(GuestIdte), sizeof(GuestIdte));
1212 if (RT_FAILURE(rc))
1213 {
1214 AssertMsgRC(rc, ("Failed to read IDTE! rc=%Rrc\n", rc));
1215 return rc;
1216 }
1217
1218 if (EMIsRawRing0Enabled(pVM))
1219 {
1220 /*
1221 * Only replace handlers for which we are 100% certain there won't be
1222 * any host interrupts.
1223 *
1224 * 0x2E is safe on Windows because it's the system service interrupt gate. Not
1225 * quite certain if this is safe or not on 64-bit Vista, it probably is.
1226 *
1227 * 0x80 is safe on Linux because it's the syscall vector and is part of the
1228 * 32-bit usermode ABI. 64-bit Linux (usually) supports 32-bit processes
1229 * and will therefor never assign hardware interrupts to 0x80.
1230 *
1231 * Exactly why 0x80 is safe on 32-bit Windows is a bit hazy, but it seems
1232 * to work ok... However on 64-bit Vista (SMP?) is doesn't work reliably.
1233 * Booting Linux/BSD guest will cause system lockups on most of the computers.
1234 * -> Update: It seems gate 0x80 is not safe on 32-bits Windows either. See
1235 * defect #3604.
1236 *
1237 * PORTME - Check if your host keeps any of these gates free from hw ints.
1238 *
1239 * Note! SELMR3SyncTSS also has code related to this interrupt handler replacing.
1240 */
1241 /** @todo handle those dependencies better! */
1242 /** @todo Solve this in a proper manner. see defect #1186 */
1243#if defined(RT_OS_WINDOWS) && defined(RT_ARCH_X86)
1244 if (iTrap == 0x2E)
1245#elif defined(RT_OS_LINUX)
1246 if (iTrap == 0x80)
1247#else
1248 if (0)
1249#endif
1250 {
1251 if ( GuestIdte.Gen.u1Present
1252 && ( GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32
1253 || GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
1254 && GuestIdte.Gen.u2DPL == 3)
1255 {
1256 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[iTrap];
1257
1258 GuestIdte.Gen.u5Type2 = VBOX_IDTE_TYPE2_TRAP_32;
1259 GuestIdte.Gen.u16OffsetHigh = pHandler >> 16;
1260 GuestIdte.Gen.u16OffsetLow = pHandler & 0xFFFF;
1261 GuestIdte.Gen.u16SegSel |= 1; //ring 1
1262 *pIdte = GuestIdte;
1263
1264 /* Mark it for relocation purposes. */
1265 ASMBitSet(&pVM->trpm.s.au32IdtPatched[0], iTrap);
1266
1267 /* Also store it in our guest trap array. */
1268 pVM->trpm.s.aGuestTrapHandler[iTrap] = pHandler;
1269
1270 Log(("Setting trap handler %x to %08X (direct)\n", iTrap, pHandler));
1271 return VINF_SUCCESS;
1272 }
1273 /* ok, let's try to install a trampoline handler then. */
1274 }
1275 }
1276
1277 if ( GuestIdte.Gen.u1Present
1278 && ( GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32
1279 || GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
1280 && (GuestIdte.Gen.u2DPL == 3 || GuestIdte.Gen.u2DPL == 0))
1281 {
1282 /*
1283 * Save handler which can be used for a trampoline call inside the GC
1284 */
1285 Log(("Setting trap handler %x to %08X\n", iTrap, pHandler));
1286 pVM->trpm.s.aGuestTrapHandler[iTrap] = pHandler;
1287 return VINF_SUCCESS;
1288 }
1289 return VERR_INVALID_PARAMETER;
1290}
1291
1292
1293/**
1294 * Check if address is a gate handler (interrupt/trap/task/anything).
1295 *
1296 * @returns True is gate handler, false if not.
1297 *
1298 * @param pVM VM handle.
1299 * @param GCPtr GC address to check.
1300 */
1301VMMR3DECL(bool) TRPMR3IsGateHandler(PVM pVM, RTRCPTR GCPtr)
1302{
1303 /*
1304 * Read IDTR and calc last entry.
1305 */
1306 uint16_t cbIDT;
1307 RTGCPTR GCPtrIDTE = CPUMGetGuestIDTR(pVM, &cbIDT);
1308 unsigned cEntries = (cbIDT + 1) / sizeof(VBOXIDTE);
1309 if (!cEntries)
1310 return false;
1311 RTGCPTR GCPtrIDTELast = GCPtrIDTE + (cEntries - 1) * sizeof(VBOXIDTE);
1312
1313 /*
1314 * Outer loop: interate pages.
1315 */
1316 while (GCPtrIDTE <= GCPtrIDTELast)
1317 {
1318 /*
1319 * Convert this page to a HC address.
1320 * (This function checks for not-present pages.)
1321 */
1322 PVBOXIDTE pIDTE;
1323 int rc = PGMPhysGCPtr2R3Ptr(pVM, GCPtrIDTE, (void **)&pIDTE);
1324 if (RT_SUCCESS(rc))
1325 {
1326 /*
1327 * Inner Loop: Iterate the data on this page looking for an entry equal to GCPtr.
1328 * N.B. Member of the Flat Earth Society...
1329 */
1330 while (GCPtrIDTE <= GCPtrIDTELast)
1331 {
1332 if (pIDTE->Gen.u1Present)
1333 {
1334 RTRCPTR GCPtrHandler = VBOXIDTE_OFFSET(*pIDTE);
1335 if (GCPtr == GCPtrHandler)
1336 return true;
1337 }
1338
1339 /* next entry */
1340 if ((GCPtrIDTE & PAGE_OFFSET_MASK) + sizeof(VBOXIDTE) >= PAGE_SIZE)
1341 {
1342 AssertMsg(!(GCPtrIDTE & (sizeof(VBOXIDTE) - 1)),
1343 ("IDT is crossing pages and it's not aligned! GCPtrIDTE=%#x cbIDT=%#x\n", GCPtrIDTE, cbIDT));
1344 GCPtrIDTE += sizeof(VBOXIDTE);
1345 break;
1346 }
1347 GCPtrIDTE += sizeof(VBOXIDTE);
1348 pIDTE++;
1349 }
1350 }
1351 else
1352 {
1353 /* Skip to the next page (if any). Take care not to wrap around the address space. */
1354 if ((GCPtrIDTELast >> PAGE_SHIFT) == (GCPtrIDTE >> PAGE_SHIFT))
1355 return false;
1356 GCPtrIDTE = RT_ALIGN_T(GCPtrIDTE, PAGE_SIZE, RTGCPTR) + PAGE_SIZE + (GCPtrIDTE & (sizeof(VBOXIDTE) - 1));
1357 }
1358 }
1359 return false;
1360}
1361
1362
1363/**
1364 * Inject event (such as external irq or trap)
1365 *
1366 * @returns VBox status code.
1367 * @param pVM The VM to operate on.
1368 * @param enmEvent Trpm event type
1369 */
1370VMMR3DECL(int) TRPMR3InjectEvent(PVM pVM, TRPMEVENT enmEvent)
1371{
1372 PCPUMCTX pCtx;
1373 int rc;
1374
1375 pCtx = CPUMQueryGuestCtxPtr(pVM);
1376 Assert(!PATMIsPatchGCAddr(pVM, (RTGCPTR)pCtx->eip));
1377 Assert(!VM_FF_ISSET(pVM, VM_FF_INHIBIT_INTERRUPTS));
1378
1379 /* Currently only useful for external hardware interrupts. */
1380 Assert(enmEvent == TRPM_HARDWARE_INT);
1381
1382 if (REMR3QueryPendingInterrupt(pVM) == REM_NO_PENDING_IRQ)
1383 {
1384#ifdef TRPM_FORWARD_TRAPS_IN_GC
1385
1386# ifdef LOG_ENABLED
1387 DBGFR3InfoLog(pVM, "cpumguest", "TRPMInject");
1388 DBGFR3DisasInstrCurrentLog(pVM, "TRPMInject");
1389# endif
1390
1391 uint8_t u8Interrupt;
1392 rc = PDMGetInterrupt(pVM, &u8Interrupt);
1393 Log(("TRPMR3InjectEvent: u8Interrupt=%d (%#x) rc=%Rrc\n", u8Interrupt, u8Interrupt, rc));
1394 if (RT_SUCCESS(rc))
1395 {
1396 if (HWACCMR3IsActive(pVM))
1397 {
1398 rc = TRPMAssertTrap(pVM, u8Interrupt, enmEvent);
1399 AssertRC(rc);
1400 STAM_COUNTER_INC(&pVM->trpm.s.paStatForwardedIRQR3[u8Interrupt]);
1401 return VINF_EM_RESCHEDULE_HWACC;
1402 }
1403 /* If the guest gate is not patched, then we will check (again) if we can patch it. */
1404 if (pVM->trpm.s.aGuestTrapHandler[u8Interrupt] == TRPM_INVALID_HANDLER)
1405 {
1406 CSAMR3CheckGates(pVM, u8Interrupt, 1);
1407 Log(("TRPMR3InjectEvent: recheck gate %x -> valid=%d\n", u8Interrupt, TRPMR3GetGuestTrapHandler(pVM, u8Interrupt) != TRPM_INVALID_HANDLER));
1408 }
1409
1410 if (pVM->trpm.s.aGuestTrapHandler[u8Interrupt] != TRPM_INVALID_HANDLER)
1411 {
1412 /* Must check pending forced actions as our IDT or GDT might be out of sync */
1413 EMR3CheckRawForcedActions(pVM);
1414
1415 /* There's a handler -> let's execute it in raw mode */
1416 rc = TRPMForwardTrap(pVM, CPUMCTX2CORE(pCtx), u8Interrupt, 0, TRPM_TRAP_NO_ERRORCODE, enmEvent, -1);
1417 if (rc == VINF_SUCCESS /* Don't use RT_SUCCESS */)
1418 {
1419 Assert(!VM_FF_ISPENDING(pVM, VM_FF_SELM_SYNC_GDT | VM_FF_SELM_SYNC_LDT | VM_FF_TRPM_SYNC_IDT | VM_FF_SELM_SYNC_TSS));
1420
1421 STAM_COUNTER_INC(&pVM->trpm.s.paStatForwardedIRQR3[u8Interrupt]);
1422 return VINF_EM_RESCHEDULE_RAW;
1423 }
1424 }
1425 else
1426 STAM_COUNTER_INC(&pVM->trpm.s.StatForwardFailNoHandler);
1427 REMR3NotifyPendingInterrupt(pVM, u8Interrupt);
1428 }
1429 else
1430 AssertRC(rc);
1431#else
1432 if (HWACCMR3IsActive(pVM))
1433 {
1434 uint8_t u8Interrupt;
1435 rc = PDMGetInterrupt(pVM, &u8Interrupt);
1436 Log(("TRPMR3InjectEvent: u8Interrupt=%d (%#x) rc=%Rrc\n", u8Interrupt, u8Interrupt, rc));
1437 if (RT_SUCCESS(rc))
1438 {
1439 rc = TRPMAssertTrap(pVM, u8Interrupt, TRPM_HARDWARE_INT);
1440 AssertRC(rc);
1441 STAM_COUNTER_INC(&pVM->trpm.s.paStatForwardedIRQR3[u8Interrupt]);
1442 return VINF_EM_RESCHEDULE_HWACC;
1443 }
1444 }
1445 else
1446 AssertRC(rc);
1447#endif
1448 }
1449 /** @todo check if it's safe to translate the patch address to the original guest address.
1450 * this implies a safe state in translated instructions and should take sti successors into account (instruction fusing)
1451 */
1452 /* Note: if it's a PATM address, then we'll go back to raw mode regardless of the return code below. */
1453
1454 /* Fall back to the recompiler */
1455 return VINF_EM_RESCHEDULE_REM; /* (Heed the halted state if this is changed!) */
1456}
1457
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