VirtualBox

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

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

Added an extra argument to TRPMForwardTrap so the trpm profiling started in the trap handler assembly code are stopped correctly. Enabled the #UD forwarding for ring-0 traps (dtrace experiment).

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