VirtualBox

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

Last change on this file since 2935 was 2715, checked in by vboxsync, 18 years ago

One other case where we have to check for pending forced actions before forwarding a trap or interrupt.

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