VirtualBox

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

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

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

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 75.4 KB
Line 
1/* $Id: TRPM.cpp 19141 2009-04-23 13:52:18Z 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 9
434#define TRPM_SAVED_STATE_VERSION_UNI 8 /* SMP support bumped the version */
435
436
437/*******************************************************************************
438* Internal Functions *
439*******************************************************************************/
440static DECLCALLBACK(int) trpmR3Save(PVM pVM, PSSMHANDLE pSSM);
441static DECLCALLBACK(int) trpmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
442static DECLCALLBACK(int) trpmR3GuestIDTWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
443
444
445/**
446 * Initializes the Trap Manager
447 *
448 * @returns VBox status code.
449 * @param pVM The VM to operate on.
450 */
451VMMR3DECL(int) TRPMR3Init(PVM pVM)
452{
453 LogFlow(("TRPMR3Init\n"));
454
455 /*
456 * Assert sizes and alignments.
457 */
458 AssertRelease(!(RT_OFFSETOF(VM, trpm.s) & 31));
459 AssertRelease(!(RT_OFFSETOF(VM, trpm.s.aIdt) & 15));
460 AssertRelease(sizeof(pVM->trpm.s) <= sizeof(pVM->trpm.padding));
461 AssertRelease(RT_ELEMENTS(pVM->trpm.s.aGuestTrapHandler) == sizeof(pVM->trpm.s.au32IdtPatched)*8);
462
463 /*
464 * Initialize members.
465 */
466 pVM->trpm.s.offVM = RT_OFFSETOF(VM, trpm);
467 pVM->trpm.s.offTRPMCPU = RT_OFFSETOF(VM, aCpus[0].trpm) - RT_OFFSETOF(VM, trpm);
468
469 for (unsigned i=0;i<pVM->cCPUs;i++)
470 {
471 PVMCPU pVCpu = &pVM->aCpus[i];
472
473 pVCpu->trpm.s.offVM = RT_OFFSETOF(VM, aCpus[i].trpm);
474 pVCpu->trpm.s.uActiveVector = ~0;
475 }
476
477 pVM->trpm.s.GuestIdtr.pIdt = RTRCPTR_MAX;
478 pVM->trpm.s.pvMonShwIdtRC = RTRCPTR_MAX;
479 pVM->trpm.s.fDisableMonitoring = false;
480 pVM->trpm.s.fSafeToDropGuestIDTMonitoring = false;
481
482 /*
483 * Read the configuration (if any).
484 */
485 PCFGMNODE pTRPMNode = CFGMR3GetChild(CFGMR3GetRoot(pVM), "TRPM");
486 if (pTRPMNode)
487 {
488 bool f;
489 int rc = CFGMR3QueryBool(pTRPMNode, "SafeToDropGuestIDTMonitoring", &f);
490 if (RT_SUCCESS(rc))
491 pVM->trpm.s.fSafeToDropGuestIDTMonitoring = f;
492 }
493
494 /* write config summary to log */
495 if (pVM->trpm.s.fSafeToDropGuestIDTMonitoring)
496 LogRel(("TRPM: Dropping Guest IDT Monitoring.\n"));
497
498 /*
499 * Initialize the IDT.
500 * The handler addresses will be set in the TRPMR3Relocate() function.
501 */
502 Assert(sizeof(pVM->trpm.s.aIdt) == sizeof(g_aIdt));
503 memcpy(&pVM->trpm.s.aIdt[0], &g_aIdt[0], sizeof(pVM->trpm.s.aIdt));
504
505 /*
506 * Register the saved state data unit.
507 */
508 int rc = SSMR3RegisterInternal(pVM, "trpm", 1, TRPM_SAVED_STATE_VERSION, sizeof(TRPM),
509 NULL, trpmR3Save, NULL,
510 NULL, trpmR3Load, NULL);
511 if (RT_FAILURE(rc))
512 return rc;
513
514 /*
515 * Statistics.
516 */
517 STAM_REG(pVM, &pVM->trpm.s.StatRCWriteGuestIDTFault, STAMTYPE_COUNTER, "/TRPM/RC/IDTWritesFault", STAMUNIT_OCCURENCES, "Guest IDT writes the we returned to R3 to handle.");
518 STAM_REG(pVM, &pVM->trpm.s.StatRCWriteGuestIDTHandled, STAMTYPE_COUNTER, "/TRPM/RC/IDTWritesHandled", STAMUNIT_OCCURENCES, "Guest IDT writes that we handled successfully.");
519 STAM_REG(pVM, &pVM->trpm.s.StatSyncIDT, STAMTYPE_PROFILE, "/PROF/TRPM/SyncIDT", STAMUNIT_TICKS_PER_CALL, "Profiling of TRPMR3SyncIDT().");
520
521 /* traps */
522 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x00], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/00", STAMUNIT_TICKS_PER_CALL, "#DE - Divide error.");
523 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).");
524 //STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x02], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/02", STAMUNIT_TICKS_PER_CALL, "NMI");
525 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x03], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/03", STAMUNIT_TICKS_PER_CALL, "#BP - Breakpoint.");
526 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x04], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/04", STAMUNIT_TICKS_PER_CALL, "#OF - Overflow.");
527 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x05], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/05", STAMUNIT_TICKS_PER_CALL, "#BR - Bound range exceeded.");
528 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x06], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/06", STAMUNIT_TICKS_PER_CALL, "#UD - Undefined opcode.");
529 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x07], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/07", STAMUNIT_TICKS_PER_CALL, "#NM - Device not available (FPU).");
530 //STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x08], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/08", STAMUNIT_TICKS_PER_CALL, "#DF - Double fault.");
531 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x09], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/09", STAMUNIT_TICKS_PER_CALL, "#?? - Coprocessor segment overrun (obsolete).");
532 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0a], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0a", STAMUNIT_TICKS_PER_CALL, "#TS - Task switch fault.");
533 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0b], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0b", STAMUNIT_TICKS_PER_CALL, "#NP - Segemnt not present.");
534 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0c], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0c", STAMUNIT_TICKS_PER_CALL, "#SS - Stack segment fault.");
535 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0d], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0d", STAMUNIT_TICKS_PER_CALL, "#GP - General protection fault.");
536 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0e], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0e", STAMUNIT_TICKS_PER_CALL, "#PF - Page fault.");
537 //STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x0f], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/0f", STAMUNIT_TICKS_PER_CALL, "Reserved.");
538 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x10], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/10", STAMUNIT_TICKS_PER_CALL, "#MF - Math fault..");
539 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x11], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/11", STAMUNIT_TICKS_PER_CALL, "#AC - Alignment check.");
540 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x12], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/12", STAMUNIT_TICKS_PER_CALL, "#MC - Machine check.");
541 STAM_REG(pVM, &pVM->trpm.s.aStatGCTraps[0x13], STAMTYPE_PROFILE_ADV, "/TRPM/GC/Traps/13", STAMUNIT_TICKS_PER_CALL, "#XF - SIMD Floating-Point Exception.");
542
543#ifdef VBOX_WITH_STATISTICS
544 rc = MMHyperAlloc(pVM, sizeof(STAMCOUNTER) * 255, 8, MM_TAG_STAM, (void **)&pVM->trpm.s.paStatForwardedIRQR3);
545 AssertRCReturn(rc, rc);
546 pVM->trpm.s.paStatForwardedIRQRC = MMHyperR3ToRC(pVM, pVM->trpm.s.paStatForwardedIRQR3);
547 pVM->trpm.s.paStatForwardedIRQR0 = MMHyperR3ToR0(pVM, pVM->trpm.s.paStatForwardedIRQR3);
548 for (unsigned i = 0; i < 255; i++)
549 STAMR3RegisterF(pVM, &pVM->trpm.s.paStatForwardedIRQR3[i], STAMTYPE_COUNTER, STAMVISIBILITY_USED, STAMUNIT_OCCURENCES, "Forwarded interrupts.",
550 i < 0x20 ? "/TRPM/ForwardRaw/TRAP/%02X" : "/TRPM/ForwardRaw/IRQ/%02X", i);
551#endif
552
553 STAM_REG(pVM, &pVM->trpm.s.StatForwardProfR3, STAMTYPE_PROFILE_ADV, "/TRPM/ForwardRaw/ProfR3", STAMUNIT_TICKS_PER_CALL, "Profiling TRPMForwardTrap.");
554 STAM_REG(pVM, &pVM->trpm.s.StatForwardProfRZ, STAMTYPE_PROFILE_ADV, "/TRPM/ForwardRaw/ProfRZ", STAMUNIT_TICKS_PER_CALL, "Profiling TRPMForwardTrap.");
555 STAM_REG(pVM, &pVM->trpm.s.StatForwardFailNoHandler, STAMTYPE_COUNTER, "/TRPM/ForwardRaw/FailNoHandler", STAMUNIT_OCCURENCES,"Failure to forward interrupt in raw mode.");
556 STAM_REG(pVM, &pVM->trpm.s.StatForwardFailPatchAddr, STAMTYPE_COUNTER, "/TRPM/ForwardRaw/FailPatchAddr", STAMUNIT_OCCURENCES,"Failure to forward interrupt in raw mode.");
557 STAM_REG(pVM, &pVM->trpm.s.StatForwardFailR3, STAMTYPE_COUNTER, "/TRPM/ForwardRaw/FailR3", STAMUNIT_OCCURENCES, "Failure to forward interrupt in raw mode.");
558 STAM_REG(pVM, &pVM->trpm.s.StatForwardFailRZ, STAMTYPE_COUNTER, "/TRPM/ForwardRaw/FailRZ", STAMUNIT_OCCURENCES, "Failure to forward interrupt in raw mode.");
559
560 STAM_REG(pVM, &pVM->trpm.s.StatTrap0dDisasm, STAMTYPE_PROFILE, "/TRPM/RC/Traps/0d/Disasm", STAMUNIT_TICKS_PER_CALL, "Profiling disassembly part of trpmGCTrap0dHandler.");
561 STAM_REG(pVM, &pVM->trpm.s.StatTrap0dRdTsc, STAMTYPE_COUNTER, "/TRPM/RC/Traps/0d/RdTsc", STAMUNIT_OCCURENCES, "Number of RDTSC #GPs.");
562
563 /*
564 * Default action when entering raw mode for the first time
565 */
566 PVMCPU pVCpu = &pVM->aCpus[0]; /* raw mode implies on VCPU */
567 VMCPU_FF_SET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
568 return 0;
569}
570
571
572/**
573 * Applies relocations to data and code managed by this component.
574 *
575 * This function will be called at init and whenever the VMM need
576 * to relocate itself inside the GC.
577 *
578 * @param pVM The VM handle.
579 * @param offDelta Relocation delta relative to old location.
580 */
581VMMR3DECL(void) TRPMR3Relocate(PVM pVM, RTGCINTPTR offDelta)
582{
583 /* Only applies to raw mode which supports only 1 VCPU. */
584 PVMCPU pVCpu = &pVM->aCpus[0];
585
586 LogFlow(("TRPMR3Relocate\n"));
587 /*
588 * Get the trap handler addresses.
589 *
590 * If VMMGC.gc is screwed, so are we. We'll assert here since it elsewise
591 * would make init order impossible if we should assert the presence of these
592 * exports in TRPMR3Init().
593 */
594 RTRCPTR aRCPtrs[TRPM_HANDLER_MAX] = {0};
595 int rc;
596 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerInterupt", &aRCPtrs[TRPM_HANDLER_INT]);
597 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerInterupt in VMMGC.gc!\n"));
598
599 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerGeneric", &aRCPtrs[TRPM_HANDLER_TRAP]);
600 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerGeneric in VMMGC.gc!\n"));
601
602 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerTrap08", &aRCPtrs[TRPM_HANDLER_TRAP_08]);
603 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerTrap08 in VMMGC.gc!\n"));
604
605 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerTrap12", &aRCPtrs[TRPM_HANDLER_TRAP_12]);
606 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerTrap12 in VMMGC.gc!\n"));
607
608 RTSEL SelCS = CPUMGetHyperCS(pVCpu);
609
610 /*
611 * Iterate the idt and set the addresses.
612 */
613 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[0];
614 PVBOXIDTE_GENERIC pIdteTemplate = &g_aIdt[0];
615 for (unsigned i = 0; i < RT_ELEMENTS(pVM->trpm.s.aIdt); i++, pIdte++, pIdteTemplate++)
616 {
617 if ( pIdte->Gen.u1Present
618 && !ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], i)
619 )
620 {
621 Assert(pIdteTemplate->u16OffsetLow < TRPM_HANDLER_MAX);
622 RTGCPTR Offset = aRCPtrs[pIdteTemplate->u16OffsetLow];
623 switch (pIdteTemplate->u16OffsetLow)
624 {
625 /*
626 * Generic handlers have different entrypoints for each possible
627 * vector number. These entrypoints makes a sort of an array with
628 * 8 byte entries where the vector number is the index.
629 * See TRPMGCHandlersA.asm for details.
630 */
631 case TRPM_HANDLER_INT:
632 case TRPM_HANDLER_TRAP:
633 Offset += i * 8;
634 break;
635 case TRPM_HANDLER_TRAP_12:
636 break;
637 case TRPM_HANDLER_TRAP_08:
638 /* Handle #DF Task Gate in special way. */
639 pIdte->Gen.u16SegSel = SELMGetTrap8Selector(pVM);
640 pIdte->Gen.u16OffsetLow = 0;
641 pIdte->Gen.u16OffsetHigh = 0;
642 SELMSetTrap8EIP(pVM, Offset);
643 continue;
644 }
645 /* (non-task gates only ) */
646 pIdte->Gen.u16OffsetLow = Offset & 0xffff;
647 pIdte->Gen.u16OffsetHigh = Offset >> 16;
648 pIdte->Gen.u16SegSel = SelCS;
649 }
650 }
651
652 /*
653 * Update IDTR (limit is including!).
654 */
655 CPUMSetHyperIDTR(pVCpu, VM_RC_ADDR(pVM, &pVM->trpm.s.aIdt[0]), sizeof(pVM->trpm.s.aIdt)-1);
656
657 if (!pVM->trpm.s.fDisableMonitoring)
658 {
659#ifdef TRPM_TRACK_SHADOW_IDT_CHANGES
660 if (pVM->trpm.s.pvMonShwIdtRC != RTRCPTR_MAX)
661 {
662 rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.pvMonShwIdtRC);
663 AssertRC(rc);
664 }
665 pVM->trpm.s.pvMonShwIdtRC = VM_RC_ADDR(pVM, &pVM->trpm.s.aIdt[0]);
666 rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_HYPERVISOR, pVM->trpm.s.pvMonShwIdtRC, pVM->trpm.s.pvMonShwIdtRC + sizeof(pVM->trpm.s.aIdt) - 1,
667 0, 0, "trpmRCShadowIDTWriteHandler", 0, "Shadow IDT write access handler");
668 AssertRC(rc);
669#endif
670 }
671
672 /* Relocate IDT handlers for forwarding guest traps/interrupts. */
673 for (uint32_t iTrap = 0; iTrap < RT_ELEMENTS(pVM->trpm.s.aGuestTrapHandler); iTrap++)
674 {
675 if (pVM->trpm.s.aGuestTrapHandler[iTrap] != TRPM_INVALID_HANDLER)
676 {
677 Log(("TRPMR3Relocate: iGate=%2X Handler %RRv -> %RRv\n", iTrap, pVM->trpm.s.aGuestTrapHandler[iTrap], pVM->trpm.s.aGuestTrapHandler[iTrap] + offDelta));
678 pVM->trpm.s.aGuestTrapHandler[iTrap] += offDelta;
679 }
680
681 if (ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iTrap))
682 {
683 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[iTrap];
684 RTGCPTR pHandler = VBOXIDTE_OFFSET(*pIdte);
685
686 Log(("TRPMR3Relocate: *iGate=%2X Handler %RGv -> %RGv\n", iTrap, pHandler, pHandler + offDelta));
687 pHandler += offDelta;
688
689 pIdte->Gen.u16OffsetHigh = pHandler >> 16;
690 pIdte->Gen.u16OffsetLow = pHandler & 0xFFFF;
691
692 }
693 }
694
695#ifdef VBOX_WITH_STATISTICS
696 pVM->trpm.s.paStatForwardedIRQRC += offDelta;
697 pVM->trpm.s.paStatForwardedIRQR0 = MMHyperR3ToR0(pVM, pVM->trpm.s.paStatForwardedIRQR3);
698#endif
699}
700
701
702/**
703 * Terminates the Trap Manager
704 *
705 * @returns VBox status code.
706 * @param pVM The VM to operate on.
707 */
708VMMR3DECL(int) TRPMR3Term(PVM pVM)
709{
710 NOREF(pVM);
711 return 0;
712}
713
714
715/**
716 * The VM is being reset.
717 *
718 * For the TRPM component this means that any IDT write monitors
719 * needs to be removed, any pending trap cleared, and the IDT reset.
720 *
721 * @param pVM VM handle.
722 */
723VMMR3DECL(void) TRPMR3Reset(PVM pVM)
724{
725 /*
726 * Deregister any virtual handlers.
727 */
728#ifdef TRPM_TRACK_GUEST_IDT_CHANGES
729 if (pVM->trpm.s.GuestIdtr.pIdt != RTRCPTR_MAX)
730 {
731 if (!pVM->trpm.s.fSafeToDropGuestIDTMonitoring)
732 {
733 int rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.GuestIdtr.pIdt);
734 AssertRC(rc);
735 }
736 pVM->trpm.s.GuestIdtr.pIdt = RTRCPTR_MAX;
737 }
738 pVM->trpm.s.GuestIdtr.cbIdt = 0;
739#endif
740
741 /*
742 * Reinitialize other members calling the relocator to get things right.
743 */
744 for (unsigned i=0;i<pVM->cCPUs;i++)
745 {
746 PVMCPU pVCpu = &pVM->aCpus[i];
747 pVCpu->trpm.s.uActiveVector = ~0;
748 }
749 memcpy(&pVM->trpm.s.aIdt[0], &g_aIdt[0], sizeof(pVM->trpm.s.aIdt));
750 memset(pVM->trpm.s.aGuestTrapHandler, 0, sizeof(pVM->trpm.s.aGuestTrapHandler));
751 TRPMR3Relocate(pVM, 0);
752
753 /*
754 * Default action when entering raw mode for the first time
755 */
756 PVMCPU pVCpu = &pVM->aCpus[0]; /* raw mode implies on VCPU */
757 VMCPU_FF_SET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
758}
759
760
761/**
762 * Execute state save operation.
763 *
764 * @returns VBox status code.
765 * @param pVM VM Handle.
766 * @param pSSM SSM operation handle.
767 */
768static DECLCALLBACK(int) trpmR3Save(PVM pVM, PSSMHANDLE pSSM)
769{
770 PTRPM pTrpm = &pVM->trpm.s;
771 LogFlow(("trpmR3Save:\n"));
772
773 /*
774 * Active and saved traps.
775 */
776 for (unsigned i=0;i<pVM->cCPUs;i++)
777 {
778 PTRPMCPU pTrpmCpu = &pVM->aCpus[i].trpm.s;
779
780 SSMR3PutUInt(pSSM, pTrpmCpu->uActiveVector);
781 SSMR3PutUInt(pSSM, pTrpmCpu->enmActiveType);
782 SSMR3PutGCUInt(pSSM, pTrpmCpu->uActiveErrorCode);
783 SSMR3PutGCUIntPtr(pSSM, pTrpmCpu->uActiveCR2);
784 SSMR3PutGCUInt(pSSM, pTrpmCpu->uSavedVector);
785 SSMR3PutUInt(pSSM, pTrpmCpu->enmSavedType);
786 SSMR3PutGCUInt(pSSM, pTrpmCpu->uSavedErrorCode);
787 SSMR3PutGCUIntPtr(pSSM, pTrpmCpu->uSavedCR2);
788 SSMR3PutGCUInt(pSSM, pTrpmCpu->uPrevVector);
789 }
790 SSMR3PutBool(pSSM, pTrpm->fDisableMonitoring);
791 PVMCPU pVCpu = &pVM->aCpus[0]; /* raw mode implies 1 VCPU */
792 SSMR3PutUInt(pSSM, VMCPU_FF_ISSET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT));
793 SSMR3PutMem(pSSM, &pTrpm->au32IdtPatched[0], sizeof(pTrpm->au32IdtPatched));
794 SSMR3PutU32(pSSM, ~0); /* separator. */
795
796 /*
797 * Save any trampoline gates.
798 */
799 for (uint32_t iTrap = 0; iTrap < RT_ELEMENTS(pTrpm->aGuestTrapHandler); iTrap++)
800 {
801 if (pTrpm->aGuestTrapHandler[iTrap])
802 {
803 SSMR3PutU32(pSSM, iTrap);
804 SSMR3PutGCPtr(pSSM, pTrpm->aGuestTrapHandler[iTrap]);
805 SSMR3PutMem(pSSM, &pTrpm->aIdt[iTrap], sizeof(pTrpm->aIdt[iTrap]));
806 }
807 }
808
809 return SSMR3PutU32(pSSM, ~0); /* terminator */
810}
811
812
813/**
814 * Execute state load operation.
815 *
816 * @returns VBox status code.
817 * @param pVM VM Handle.
818 * @param pSSM SSM operation handle.
819 * @param u32Version Data layout version.
820 */
821static DECLCALLBACK(int) trpmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
822{
823 LogFlow(("trpmR3Load:\n"));
824
825 /*
826 * Validate version.
827 */
828 if ( u32Version != TRPM_SAVED_STATE_VERSION
829 && u32Version != TRPM_SAVED_STATE_VERSION_UNI)
830 {
831 AssertMsgFailed(("trpmR3Load: Invalid version u32Version=%d!\n", u32Version));
832 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
833 }
834
835 /*
836 * Call the reset function to kick out any handled gates and other potential trouble.
837 */
838 TRPMR3Reset(pVM);
839
840 /*
841 * Active and saved traps.
842 */
843 PTRPM pTrpm = &pVM->trpm.s;
844
845 if (u32Version == TRPM_SAVED_STATE_VERSION)
846 {
847 for (unsigned i=0;i<pVM->cCPUs;i++)
848 {
849 PTRPMCPU pTrpmCpu = &pVM->aCpus[i].trpm.s;
850 SSMR3GetUInt(pSSM, &pTrpmCpu->uActiveVector);
851 SSMR3GetUInt(pSSM, (uint32_t *)&pTrpmCpu->enmActiveType);
852 SSMR3GetGCUInt(pSSM, &pTrpmCpu->uActiveErrorCode);
853 SSMR3GetGCUIntPtr(pSSM, &pTrpmCpu->uActiveCR2);
854 SSMR3GetGCUInt(pSSM, &pTrpmCpu->uSavedVector);
855 SSMR3GetUInt(pSSM, (uint32_t *)&pTrpmCpu->enmSavedType);
856 SSMR3GetGCUInt(pSSM, &pTrpmCpu->uSavedErrorCode);
857 SSMR3GetGCUIntPtr(pSSM, &pTrpmCpu->uSavedCR2);
858 SSMR3GetGCUInt(pSSM, &pTrpmCpu->uPrevVector);
859 }
860
861 SSMR3GetBool(pSSM, &pVM->trpm.s.fDisableMonitoring);
862 }
863 else
864 {
865 PTRPMCPU pTrpmCpu = &pVM->aCpus[0].trpm.s;
866 SSMR3GetUInt(pSSM, &pTrpmCpu->uActiveVector);
867 SSMR3GetUInt(pSSM, (uint32_t *)&pTrpmCpu->enmActiveType);
868 SSMR3GetGCUInt(pSSM, &pTrpmCpu->uActiveErrorCode);
869 SSMR3GetGCUIntPtr(pSSM, &pTrpmCpu->uActiveCR2);
870 SSMR3GetGCUInt(pSSM, &pTrpmCpu->uSavedVector);
871 SSMR3GetUInt(pSSM, (uint32_t *)&pTrpmCpu->enmSavedType);
872 SSMR3GetGCUInt(pSSM, &pTrpmCpu->uSavedErrorCode);
873 SSMR3GetGCUIntPtr(pSSM, &pTrpmCpu->uSavedCR2);
874 SSMR3GetGCUInt(pSSM, &pTrpmCpu->uPrevVector);
875
876 RTGCUINT fDisableMonitoring;
877 SSMR3GetGCUInt(pSSM, &fDisableMonitoring);
878 pTrpm->fDisableMonitoring = !!fDisableMonitoring;
879 }
880
881 RTUINT fSyncIDT;
882 int rc = SSMR3GetUInt(pSSM, &fSyncIDT);
883 if (RT_FAILURE(rc))
884 return rc;
885 if (fSyncIDT & ~1)
886 {
887 AssertMsgFailed(("fSyncIDT=%#x\n", fSyncIDT));
888 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
889 }
890 if (fSyncIDT)
891 {
892 PVMCPU pVCpu = &pVM->aCpus[0]; /* raw mode implies 1 VCPU */
893 VMCPU_FF_SET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
894 }
895 /* else: cleared by reset call above. */
896
897 SSMR3GetMem(pSSM, &pTrpm->au32IdtPatched[0], sizeof(pTrpm->au32IdtPatched));
898
899 /* check the separator */
900 uint32_t u32Sep;
901 rc = SSMR3GetU32(pSSM, &u32Sep);
902 if (RT_FAILURE(rc))
903 return rc;
904 if (u32Sep != (uint32_t)~0)
905 {
906 AssertMsgFailed(("u32Sep=%#x (first)\n", u32Sep));
907 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
908 }
909
910 /*
911 * Restore any trampoline gates.
912 */
913 for (;;)
914 {
915 /* gate number / terminator */
916 uint32_t iTrap;
917 rc = SSMR3GetU32(pSSM, &iTrap);
918 if (RT_FAILURE(rc))
919 return rc;
920 if (iTrap == (uint32_t)~0)
921 break;
922 if ( iTrap >= RT_ELEMENTS(pTrpm->aIdt)
923 || pTrpm->aGuestTrapHandler[iTrap])
924 {
925 AssertMsgFailed(("iTrap=%#x\n", iTrap));
926 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
927 }
928
929 /* restore the IDT entry. */
930 RTGCPTR GCPtrHandler;
931 SSMR3GetGCPtr(pSSM, &GCPtrHandler);
932 VBOXIDTE Idte;
933 rc = SSMR3GetMem(pSSM, &Idte, sizeof(Idte));
934 if (RT_FAILURE(rc))
935 return rc;
936 Assert(GCPtrHandler);
937 pTrpm->aIdt[iTrap] = Idte;
938 }
939
940 return VINF_SUCCESS;
941}
942
943
944/**
945 * Check if gate handlers were updated
946 * (callback for the VMCPU_FF_TRPM_SYNC_IDT forced action).
947 *
948 * @returns VBox status code.
949 * @param pVM The VM handle.
950 * @param pVCpu The VMCPU handle.
951 */
952VMMR3DECL(int) TRPMR3SyncIDT(PVM pVM, PVMCPU pVCpu)
953{
954 STAM_PROFILE_START(&pVM->trpm.s.StatSyncIDT, a);
955 const bool fRawRing0 = EMIsRawRing0Enabled(pVM);
956 int rc;
957
958 if (pVM->trpm.s.fDisableMonitoring)
959 {
960 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
961 return VINF_SUCCESS; /* Nothing to do */
962 }
963
964 if (fRawRing0 && CSAMIsEnabled(pVM))
965 {
966 /* Clear all handlers */
967 Log(("TRPMR3SyncIDT: Clear all trap handlers.\n"));
968 /** @todo inefficient, but simple */
969 for (unsigned iGate = 0; iGate < 256; iGate++)
970 trpmClearGuestTrapHandler(pVM, iGate);
971
972 /* Scan them all (only the first time) */
973 CSAMR3CheckGates(pVM, 0, 256);
974 }
975
976 /*
977 * Get the IDTR.
978 */
979 VBOXIDTR IDTR;
980 IDTR.pIdt = CPUMGetGuestIDTR(pVCpu, &IDTR.cbIdt);
981 if (!IDTR.cbIdt)
982 {
983 Log(("No IDT entries...\n"));
984 return DBGFSTOP(pVM);
985 }
986
987#ifdef TRPM_TRACK_GUEST_IDT_CHANGES
988 /*
989 * Check if Guest's IDTR has changed.
990 */
991 if ( IDTR.pIdt != pVM->trpm.s.GuestIdtr.pIdt
992 || IDTR.cbIdt != pVM->trpm.s.GuestIdtr.cbIdt)
993 {
994 Log(("TRPMR3UpdateFromCPUM: Guest's IDT is changed to pIdt=%08X cbIdt=%08X\n", IDTR.pIdt, IDTR.cbIdt));
995 if (!pVM->trpm.s.fSafeToDropGuestIDTMonitoring)
996 {
997 /*
998 * [Re]Register write virtual handler for guest's IDT.
999 */
1000 if (pVM->trpm.s.GuestIdtr.pIdt != RTRCPTR_MAX)
1001 {
1002 rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.GuestIdtr.pIdt);
1003 AssertRCReturn(rc, rc);
1004 }
1005 /* limit is including */
1006 rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, IDTR.pIdt, IDTR.pIdt + IDTR.cbIdt /* already inclusive */,
1007 0, trpmR3GuestIDTWriteHandler, "trpmRCGuestIDTWriteHandler", 0, "Guest IDT write access handler");
1008
1009 if (rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT)
1010 {
1011 /* Could be a conflict with CSAM */
1012 CSAMR3RemovePage(pVM, IDTR.pIdt);
1013 if (PAGE_ADDRESS(IDTR.pIdt) != PAGE_ADDRESS(IDTR.pIdt + IDTR.cbIdt))
1014 CSAMR3RemovePage(pVM, IDTR.pIdt + IDTR.cbIdt);
1015
1016 rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, IDTR.pIdt, IDTR.pIdt + IDTR.cbIdt /* already inclusive */,
1017 0, trpmR3GuestIDTWriteHandler, "trpmRCGuestIDTWriteHandler", 0, "Guest IDT write access handler");
1018 }
1019
1020 AssertRCReturn(rc, rc);
1021 }
1022
1023 /* Update saved Guest IDTR. */
1024 pVM->trpm.s.GuestIdtr = IDTR;
1025 }
1026#endif
1027
1028 /*
1029 * Sync the interrupt gate.
1030 * Should probably check/sync the others too, but for now we'll handle that in #GP.
1031 */
1032 X86DESC Idte3;
1033 rc = PGMPhysSimpleReadGCPtr(pVCpu, &Idte3, IDTR.pIdt + sizeof(Idte3) * 3, sizeof(Idte3));
1034 if (RT_FAILURE(rc))
1035 {
1036 AssertMsgRC(rc, ("Failed to read IDT[3]! rc=%Rrc\n", rc));
1037 return DBGFSTOP(pVM);
1038 }
1039 AssertRCReturn(rc, rc);
1040 if (fRawRing0)
1041 pVM->trpm.s.aIdt[3].Gen.u2DPL = RT_MAX(Idte3.Gen.u2Dpl, 1);
1042 else
1043 pVM->trpm.s.aIdt[3].Gen.u2DPL = Idte3.Gen.u2Dpl;
1044
1045 /*
1046 * Clear the FF and we're done.
1047 */
1048 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
1049 STAM_PROFILE_STOP(&pVM->trpm.s.StatSyncIDT, a);
1050 return VINF_SUCCESS;
1051}
1052
1053
1054/**
1055 * Disable IDT monitoring and syncing
1056 *
1057 * @param pVM The VM to operate on.
1058 */
1059VMMR3DECL(void) TRPMR3DisableMonitoring(PVM pVM)
1060{
1061 /*
1062 * Deregister any virtual handlers.
1063 */
1064#ifdef TRPM_TRACK_GUEST_IDT_CHANGES
1065 if (pVM->trpm.s.GuestIdtr.pIdt != RTRCPTR_MAX)
1066 {
1067 if (!pVM->trpm.s.fSafeToDropGuestIDTMonitoring)
1068 {
1069 int rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.GuestIdtr.pIdt);
1070 AssertRC(rc);
1071 }
1072 pVM->trpm.s.GuestIdtr.pIdt = RTRCPTR_MAX;
1073 }
1074 pVM->trpm.s.GuestIdtr.cbIdt = 0;
1075#endif
1076
1077#ifdef TRPM_TRACK_SHADOW_IDT_CHANGES
1078 if (pVM->trpm.s.pvMonShwIdtRC != RTRCPTR_MAX)
1079 {
1080 int rc = PGMHandlerVirtualDeregister(pVM, pVM->trpm.s.pvMonShwIdtRC);
1081 AssertRC(rc);
1082 pVM->trpm.s.pvMonShwIdtRC = RTRCPTR_MAX;
1083 }
1084#endif
1085
1086 PVMCPU pVCpu = &pVM->aCpus[0]; /* raw mode implies on VCPU */
1087 VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
1088
1089 pVM->trpm.s.fDisableMonitoring = true;
1090}
1091
1092
1093/**
1094 * \#PF Handler callback for virtual access handler ranges.
1095 *
1096 * Important to realize that a physical page in a range can have aliases, and
1097 * for ALL and WRITE handlers these will also trigger.
1098 *
1099 * @returns VINF_SUCCESS if the handler have carried out the operation.
1100 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
1101 * @param pVM VM Handle.
1102 * @param GCPtr The virtual address the guest is writing to. (not correct if it's an alias!)
1103 * @param pvPtr The HC mapping of that address.
1104 * @param pvBuf What the guest is reading/writing.
1105 * @param cbBuf How much it's reading/writing.
1106 * @param enmAccessType The access type.
1107 * @param pvUser User argument.
1108 */
1109static DECLCALLBACK(int) trpmR3GuestIDTWriteHandler(PVM pVM, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
1110{
1111 Assert(enmAccessType == PGMACCESSTYPE_WRITE);
1112 Log(("trpmR3GuestIDTWriteHandler: write to %RGv size %d\n", GCPtr, cbBuf));
1113 VMCPU_FF_SET(VMMGetCpu(pVM), VMCPU_FF_TRPM_SYNC_IDT);
1114 return VINF_PGM_HANDLER_DO_DEFAULT;
1115}
1116
1117
1118/**
1119 * Clear passthrough interrupt gate handler (reset to default handler)
1120 *
1121 * @returns VBox status code.
1122 * @param pVM The VM to operate on.
1123 * @param iTrap Trap/interrupt gate number.
1124 */
1125VMMR3DECL(int) trpmR3ClearPassThroughHandler(PVM pVM, unsigned iTrap)
1126{
1127 /* Only applies to raw mode which supports only 1 VCPU. */
1128 PVMCPU pVCpu = &pVM->aCpus[0];
1129
1130 /** @todo cleanup trpmR3ClearPassThroughHandler()! */
1131 RTRCPTR aGCPtrs[TRPM_HANDLER_MAX];
1132 int rc;
1133
1134 memset(aGCPtrs, 0, sizeof(aGCPtrs));
1135
1136 rc = PDMR3LdrGetSymbolRC(pVM, VMMGC_MAIN_MODULE_NAME, "TRPMGCHandlerInterupt", &aGCPtrs[TRPM_HANDLER_INT]);
1137 AssertReleaseMsgRC(rc, ("Couldn't find TRPMGCHandlerInterupt in VMMGC.gc!\n"));
1138
1139 if ( iTrap < TRPM_HANDLER_INT_BASE
1140 || iTrap >= RT_ELEMENTS(pVM->trpm.s.aIdt))
1141 {
1142 AssertMsg(iTrap < TRPM_HANDLER_INT_BASE, ("Illegal gate number %#x!\n", iTrap));
1143 return VERR_INVALID_PARAMETER;
1144 }
1145 memcpy(&pVM->trpm.s.aIdt[iTrap], &g_aIdt[iTrap], sizeof(pVM->trpm.s.aIdt[0]));
1146
1147 /* Unmark it for relocation purposes. */
1148 ASMBitClear(&pVM->trpm.s.au32IdtPatched[0], iTrap);
1149
1150 RTSEL SelCS = CPUMGetHyperCS(pVCpu);
1151 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[iTrap];
1152 PVBOXIDTE_GENERIC pIdteTemplate = &g_aIdt[iTrap];
1153 if (pIdte->Gen.u1Present)
1154 {
1155 Assert(pIdteTemplate->u16OffsetLow == TRPM_HANDLER_INT);
1156 Assert(sizeof(RTRCPTR) == sizeof(aGCPtrs[0]));
1157 RTRCPTR Offset = (RTRCPTR)aGCPtrs[pIdteTemplate->u16OffsetLow];
1158
1159 /*
1160 * Generic handlers have different entrypoints for each possible
1161 * vector number. These entrypoints make a sort of an array with
1162 * 8 byte entries where the vector number is the index.
1163 * See TRPMGCHandlersA.asm for details.
1164 */
1165 Offset += iTrap * 8;
1166
1167 if (pIdte->Gen.u5Type2 != VBOX_IDTE_TYPE2_TASK)
1168 {
1169 pIdte->Gen.u16OffsetLow = Offset & 0xffff;
1170 pIdte->Gen.u16OffsetHigh = Offset >> 16;
1171 pIdte->Gen.u16SegSel = SelCS;
1172 }
1173 }
1174
1175 return VINF_SUCCESS;
1176}
1177
1178
1179/**
1180 * Check if address is a gate handler (interrupt or trap).
1181 *
1182 * @returns gate nr or ~0 is not found
1183 *
1184 * @param pVM VM handle.
1185 * @param GCPtr GC address to check.
1186 */
1187VMMR3DECL(uint32_t) TRPMR3QueryGateByHandler(PVM pVM, RTRCPTR GCPtr)
1188{
1189 for (uint32_t iTrap = 0; iTrap < RT_ELEMENTS(pVM->trpm.s.aGuestTrapHandler); iTrap++)
1190 {
1191 if (pVM->trpm.s.aGuestTrapHandler[iTrap] == GCPtr)
1192 return iTrap;
1193
1194 /* redundant */
1195 if (ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iTrap))
1196 {
1197 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[iTrap];
1198 RTGCPTR pHandler = VBOXIDTE_OFFSET(*pIdte);
1199
1200 if (pHandler == GCPtr)
1201 return iTrap;
1202 }
1203 }
1204 return ~0;
1205}
1206
1207
1208/**
1209 * Get guest trap/interrupt gate handler
1210 *
1211 * @returns Guest trap handler address or TRPM_INVALID_HANDLER if none installed
1212 * @param pVM The VM to operate on.
1213 * @param iTrap Interrupt/trap number.
1214 */
1215VMMR3DECL(RTRCPTR) TRPMR3GetGuestTrapHandler(PVM pVM, unsigned iTrap)
1216{
1217 AssertReturn(iTrap < RT_ELEMENTS(pVM->trpm.s.aIdt), TRPM_INVALID_HANDLER);
1218
1219 return pVM->trpm.s.aGuestTrapHandler[iTrap];
1220}
1221
1222
1223/**
1224 * Set guest trap/interrupt gate handler
1225 * Used for setting up trap gates used for kernel calls.
1226 *
1227 * @returns VBox status code.
1228 * @param pVM The VM to operate on.
1229 * @param iTrap Interrupt/trap number.
1230 * @param pHandler GC handler pointer
1231 */
1232VMMR3DECL(int) TRPMR3SetGuestTrapHandler(PVM pVM, unsigned iTrap, RTRCPTR pHandler)
1233{
1234 /* Only valid in raw mode which implies 1 VCPU */
1235 Assert(PATMIsEnabled(pVM) && pVM->cCPUs == 1);
1236 PVMCPU pVCpu = &pVM->aCpus[0];
1237
1238 /*
1239 * Validate.
1240 */
1241 if (iTrap >= RT_ELEMENTS(pVM->trpm.s.aIdt))
1242 {
1243 AssertMsg(iTrap < TRPM_HANDLER_INT_BASE, ("Illegal gate number %d!\n", iTrap));
1244 return VERR_INVALID_PARAMETER;
1245 }
1246
1247 AssertReturn(pHandler == TRPM_INVALID_HANDLER || PATMIsPatchGCAddr(pVM, pHandler), VERR_INVALID_PARAMETER);
1248
1249 uint16_t cbIDT;
1250 RTGCPTR GCPtrIDT = CPUMGetGuestIDTR(pVCpu, &cbIDT);
1251 if (iTrap * sizeof(VBOXIDTE) >= cbIDT)
1252 return VERR_INVALID_PARAMETER; /* Silently ignore out of range requests. */
1253
1254 if (pHandler == TRPM_INVALID_HANDLER)
1255 {
1256 /* clear trap handler */
1257 Log(("TRPMR3SetGuestTrapHandler: clear handler %x\n", iTrap));
1258 return trpmClearGuestTrapHandler(pVM, iTrap);
1259 }
1260
1261 /*
1262 * Read the guest IDT entry.
1263 */
1264 VBOXIDTE GuestIdte;
1265 int rc = PGMPhysSimpleReadGCPtr(pVCpu, &GuestIdte, GCPtrIDT + iTrap * sizeof(GuestIdte), sizeof(GuestIdte));
1266 if (RT_FAILURE(rc))
1267 {
1268 AssertMsgRC(rc, ("Failed to read IDTE! rc=%Rrc\n", rc));
1269 return rc;
1270 }
1271
1272 if (EMIsRawRing0Enabled(pVM))
1273 {
1274 /*
1275 * Only replace handlers for which we are 100% certain there won't be
1276 * any host interrupts.
1277 *
1278 * 0x2E is safe on Windows because it's the system service interrupt gate. Not
1279 * quite certain if this is safe or not on 64-bit Vista, it probably is.
1280 *
1281 * 0x80 is safe on Linux because it's the syscall vector and is part of the
1282 * 32-bit usermode ABI. 64-bit Linux (usually) supports 32-bit processes
1283 * and will therefor never assign hardware interrupts to 0x80.
1284 *
1285 * Exactly why 0x80 is safe on 32-bit Windows is a bit hazy, but it seems
1286 * to work ok... However on 64-bit Vista (SMP?) is doesn't work reliably.
1287 * Booting Linux/BSD guest will cause system lockups on most of the computers.
1288 * -> Update: It seems gate 0x80 is not safe on 32-bits Windows either. See
1289 * defect #3604.
1290 *
1291 * PORTME - Check if your host keeps any of these gates free from hw ints.
1292 *
1293 * Note! SELMR3SyncTSS also has code related to this interrupt handler replacing.
1294 */
1295 /** @todo handle those dependencies better! */
1296 /** @todo Solve this in a proper manner. see defect #1186 */
1297#if defined(RT_OS_WINDOWS) && defined(RT_ARCH_X86)
1298 if (iTrap == 0x2E)
1299#elif defined(RT_OS_LINUX)
1300 if (iTrap == 0x80)
1301#else
1302 if (0)
1303#endif
1304 {
1305 if ( GuestIdte.Gen.u1Present
1306 && ( GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32
1307 || GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
1308 && GuestIdte.Gen.u2DPL == 3)
1309 {
1310 PVBOXIDTE pIdte = &pVM->trpm.s.aIdt[iTrap];
1311
1312 GuestIdte.Gen.u5Type2 = VBOX_IDTE_TYPE2_TRAP_32;
1313 GuestIdte.Gen.u16OffsetHigh = pHandler >> 16;
1314 GuestIdte.Gen.u16OffsetLow = pHandler & 0xFFFF;
1315 GuestIdte.Gen.u16SegSel |= 1; //ring 1
1316 *pIdte = GuestIdte;
1317
1318 /* Mark it for relocation purposes. */
1319 ASMBitSet(&pVM->trpm.s.au32IdtPatched[0], iTrap);
1320
1321 /* Also store it in our guest trap array. */
1322 pVM->trpm.s.aGuestTrapHandler[iTrap] = pHandler;
1323
1324 Log(("Setting trap handler %x to %08X (direct)\n", iTrap, pHandler));
1325 return VINF_SUCCESS;
1326 }
1327 /* ok, let's try to install a trampoline handler then. */
1328 }
1329 }
1330
1331 if ( GuestIdte.Gen.u1Present
1332 && ( GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32
1333 || GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
1334 && (GuestIdte.Gen.u2DPL == 3 || GuestIdte.Gen.u2DPL == 0))
1335 {
1336 /*
1337 * Save handler which can be used for a trampoline call inside the GC
1338 */
1339 Log(("Setting trap handler %x to %08X\n", iTrap, pHandler));
1340 pVM->trpm.s.aGuestTrapHandler[iTrap] = pHandler;
1341 return VINF_SUCCESS;
1342 }
1343 return VERR_INVALID_PARAMETER;
1344}
1345
1346
1347/**
1348 * Check if address is a gate handler (interrupt/trap/task/anything).
1349 *
1350 * @returns True is gate handler, false if not.
1351 *
1352 * @param pVM VM handle.
1353 * @param GCPtr GC address to check.
1354 */
1355VMMR3DECL(bool) TRPMR3IsGateHandler(PVM pVM, RTRCPTR GCPtr)
1356{
1357 /* Only valid in raw mode which implies 1 VCPU */
1358 Assert(PATMIsEnabled(pVM) && pVM->cCPUs == 1);
1359 PVMCPU pVCpu = &pVM->aCpus[0];
1360
1361 /*
1362 * Read IDTR and calc last entry.
1363 */
1364 uint16_t cbIDT;
1365 RTGCPTR GCPtrIDTE = CPUMGetGuestIDTR(pVCpu, &cbIDT);
1366 unsigned cEntries = (cbIDT + 1) / sizeof(VBOXIDTE);
1367 if (!cEntries)
1368 return false;
1369 RTGCPTR GCPtrIDTELast = GCPtrIDTE + (cEntries - 1) * sizeof(VBOXIDTE);
1370
1371 /*
1372 * Outer loop: interate pages.
1373 */
1374 while (GCPtrIDTE <= GCPtrIDTELast)
1375 {
1376 /*
1377 * Convert this page to a HC address.
1378 * (This function checks for not-present pages.)
1379 */
1380 PCVBOXIDTE pIDTE;
1381 PGMPAGEMAPLOCK Lock;
1382 int rc = PGMPhysGCPtr2CCPtrReadOnly(pVCpu, GCPtrIDTE, (const void **)&pIDTE, &Lock);
1383 if (RT_SUCCESS(rc))
1384 {
1385 /*
1386 * Inner Loop: Iterate the data on this page looking for an entry equal to GCPtr.
1387 * N.B. Member of the Flat Earth Society...
1388 */
1389 while (GCPtrIDTE <= GCPtrIDTELast)
1390 {
1391 if (pIDTE->Gen.u1Present)
1392 {
1393 RTRCPTR GCPtrHandler = VBOXIDTE_OFFSET(*pIDTE);
1394 if (GCPtr == GCPtrHandler)
1395 {
1396 PGMPhysReleasePageMappingLock(pVM, &Lock);
1397 return true;
1398 }
1399 }
1400
1401 /* next entry */
1402 if ((GCPtrIDTE & PAGE_OFFSET_MASK) + sizeof(VBOXIDTE) >= PAGE_SIZE)
1403 {
1404 AssertMsg(!(GCPtrIDTE & (sizeof(VBOXIDTE) - 1)),
1405 ("IDT is crossing pages and it's not aligned! GCPtrIDTE=%#x cbIDT=%#x\n", GCPtrIDTE, cbIDT));
1406 GCPtrIDTE += sizeof(VBOXIDTE);
1407 break;
1408 }
1409 GCPtrIDTE += sizeof(VBOXIDTE);
1410 pIDTE++;
1411 }
1412 PGMPhysReleasePageMappingLock(pVM, &Lock);
1413 }
1414 else
1415 {
1416 /* Skip to the next page (if any). Take care not to wrap around the address space. */
1417 if ((GCPtrIDTELast >> PAGE_SHIFT) == (GCPtrIDTE >> PAGE_SHIFT))
1418 return false;
1419 GCPtrIDTE = RT_ALIGN_T(GCPtrIDTE, PAGE_SIZE, RTGCPTR) + PAGE_SIZE + (GCPtrIDTE & (sizeof(VBOXIDTE) - 1));
1420 }
1421 }
1422 return false;
1423}
1424
1425
1426/**
1427 * Inject event (such as external irq or trap)
1428 *
1429 * @returns VBox status code.
1430 * @param pVM The VM to operate on.
1431 * @param pVCpu The VMCPU to operate on.
1432 * @param enmEvent Trpm event type
1433 */
1434VMMR3DECL(int) TRPMR3InjectEvent(PVM pVM, PVMCPU pVCpu, TRPMEVENT enmEvent)
1435{
1436 PCPUMCTX pCtx;
1437 int rc;
1438
1439 pCtx = CPUMQueryGuestCtxPtr(pVCpu);
1440 Assert(!PATMIsPatchGCAddr(pVM, (RTGCPTR)pCtx->eip));
1441 Assert(!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
1442
1443 /* Currently only useful for external hardware interrupts. */
1444 Assert(enmEvent == TRPM_HARDWARE_INT);
1445
1446 if (REMR3QueryPendingInterrupt(pVM, pVCpu) == REM_NO_PENDING_IRQ)
1447 {
1448#ifdef TRPM_FORWARD_TRAPS_IN_GC
1449
1450# ifdef LOG_ENABLED
1451 DBGFR3InfoLog(pVM, "cpumguest", "TRPMInject");
1452 DBGFR3DisasInstrCurrentLog(pVM, "TRPMInject");
1453# endif
1454
1455 uint8_t u8Interrupt;
1456 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
1457 Log(("TRPMR3InjectEvent: u8Interrupt=%d (%#x) rc=%Rrc\n", u8Interrupt, u8Interrupt, rc));
1458 if (RT_SUCCESS(rc))
1459 {
1460 if (HWACCMR3IsActive(pVM))
1461 {
1462 rc = TRPMAssertTrap(pVCpu, u8Interrupt, enmEvent);
1463 AssertRC(rc);
1464 STAM_COUNTER_INC(&pVM->trpm.s.paStatForwardedIRQR3[u8Interrupt]);
1465 return VINF_EM_RESCHEDULE_HWACC;
1466 }
1467 /* If the guest gate is not patched, then we will check (again) if we can patch it. */
1468 if (pVM->trpm.s.aGuestTrapHandler[u8Interrupt] == TRPM_INVALID_HANDLER)
1469 {
1470 CSAMR3CheckGates(pVM, u8Interrupt, 1);
1471 Log(("TRPMR3InjectEvent: recheck gate %x -> valid=%d\n", u8Interrupt, TRPMR3GetGuestTrapHandler(pVM, u8Interrupt) != TRPM_INVALID_HANDLER));
1472 }
1473
1474 if (pVM->trpm.s.aGuestTrapHandler[u8Interrupt] != TRPM_INVALID_HANDLER)
1475 {
1476 /* Must check pending forced actions as our IDT or GDT might be out of sync */
1477 rc = EMR3CheckRawForcedActions(pVM, pVCpu);
1478 if (rc == VINF_SUCCESS)
1479 {
1480 /* There's a handler -> let's execute it in raw mode */
1481 rc = TRPMForwardTrap(pVCpu, CPUMCTX2CORE(pCtx), u8Interrupt, 0, TRPM_TRAP_NO_ERRORCODE, enmEvent, -1);
1482 if (rc == VINF_SUCCESS /* Don't use RT_SUCCESS */)
1483 {
1484 Assert(!VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_TRPM_SYNC_IDT | VMCPU_FF_SELM_SYNC_TSS));
1485
1486 STAM_COUNTER_INC(&pVM->trpm.s.paStatForwardedIRQR3[u8Interrupt]);
1487 return VINF_EM_RESCHEDULE_RAW;
1488 }
1489 }
1490 }
1491 else
1492 STAM_COUNTER_INC(&pVM->trpm.s.StatForwardFailNoHandler);
1493 REMR3NotifyPendingInterrupt(pVM, pVCpu, u8Interrupt);
1494 }
1495 else
1496 AssertRC(rc);
1497#else
1498 if (HWACCMR3IsActive(pVM))
1499 {
1500 uint8_t u8Interrupt;
1501 rc = PDMGetInterrupt(pVCpu, &u8Interrupt);
1502 Log(("TRPMR3InjectEvent: u8Interrupt=%d (%#x) rc=%Rrc\n", u8Interrupt, u8Interrupt, rc));
1503 if (RT_SUCCESS(rc))
1504 {
1505 rc = TRPMAssertTrap(pVM, u8Interrupt, TRPM_HARDWARE_INT);
1506 AssertRC(rc);
1507 STAM_COUNTER_INC(&pVM->trpm.s.paStatForwardedIRQR3[u8Interrupt]);
1508 return VINF_EM_RESCHEDULE_HWACC;
1509 }
1510 }
1511 else
1512 AssertRC(rc);
1513#endif
1514 }
1515 /** @todo check if it's safe to translate the patch address to the original guest address.
1516 * this implies a safe state in translated instructions and should take sti successors into account (instruction fusing)
1517 */
1518 /* Note: if it's a PATM address, then we'll go back to raw mode regardless of the return code below. */
1519
1520 /* Fall back to the recompiler */
1521 return VINF_EM_RESCHEDULE_REM; /* (Heed the halted state if this is changed!) */
1522}
1523
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