VirtualBox

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

Last change on this file since 41935 was 41931, checked in by vboxsync, 13 years ago

TRPM: Save state directly to the CPUMCPU context member instead of putting on the stack. this avoid copying the state around before returning to host context to service an IRQ, or before using IEM.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette