VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/TRPMAll.cpp@ 56013

Last change on this file since 56013 was 56013, checked in by vboxsync, 9 years ago

PGM: Made the virtual handler callbacks return VBOXSTRICTRC and prepared for RC execution.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 39.1 KB
Line 
1/* $Id: TRPMAll.cpp 56013 2015-05-21 17:04:14Z vboxsync $ */
2/** @file
3 * TRPM - Trap Monitor - Any Context.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_TRPM
23#include <VBox/vmm/trpm.h>
24#include <VBox/vmm/pgm.h>
25#include <VBox/vmm/mm.h>
26#include <VBox/vmm/hm.h>
27#include <VBox/vmm/patm.h>
28#include <VBox/vmm/selm.h>
29#include <VBox/vmm/stam.h>
30#include <VBox/vmm/dbgf.h>
31#include "TRPMInternal.h"
32#include <VBox/vmm/vm.h>
33#include <VBox/err.h>
34#include <VBox/vmm/em.h>
35#include <VBox/log.h>
36#include <iprt/assert.h>
37#include <iprt/asm.h>
38#include <iprt/asm-amd64-x86.h>
39#include <iprt/param.h>
40#include <iprt/x86.h>
41#include "internal/pgm.h"
42
43
44
45#if defined(TRPM_TRACK_GUEST_IDT_CHANGES) && !defined(IN_RING0)
46/**
47 * \#PF Handler callback for virtual access handler ranges.
48 *
49 * Important to realize that a physical page in a range can have aliases, and
50 * for ALL and WRITE handlers these will also trigger.
51 *
52 * @returns VINF_SUCCESS if the handler have carried out the operation.
53 * @returns VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the access operation.
54 * @param pVM Pointer to the VM.
55 * @param pVCpu Pointer to the cross context CPU context for the
56 * calling EMT.
57 * @param GCPtr The virtual address the guest is writing to. (not correct if it's an alias!)
58 * @param pvPtr The HC mapping of that address.
59 * @param pvBuf What the guest is reading/writing.
60 * @param cbBuf How much it's reading/writing.
61 * @param enmAccessType The access type.
62 * @param enmOrigin The origin of this call.
63 * @param pvUser User argument.
64 */
65PGM_ALL_CB2_DECL(VBOXSTRICTRC)
66trpmGuestIDTWriteHandler(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, void *pvPtr, void *pvBuf, size_t cbBuf,
67 PGMACCESSTYPE enmAccessType, PGMACCESSORIGIN enmOrigin, void *pvUser)
68{
69 Assert(enmAccessType == PGMACCESSTYPE_WRITE); NOREF(enmAccessType);
70 Log(("trpmGuestIDTWriteHandler: write to %RGv size %d\n", GCPtr, cbBuf)); NOREF(GCPtr); NOREF(cbBuf);
71 NOREF(pvPtr); NOREF(pvUser); NOREF(pvBuf); NOREF(enmOrigin); NOREF(pvUser);
72 Assert(!HMIsEnabled(pVM));
73
74 /** @todo Check which IDT entry and keep the update cost low in TRPMR3SyncIDT() and CSAMCheckGates(). */
75 VMCPU_FF_SET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);
76# ifdef IN_RC
77 STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTFault);
78# endif
79 return VINF_PGM_HANDLER_DO_DEFAULT;
80}
81#endif /* TRPM_TRACK_GUEST_IDT_CHANGES && !IN_RING0 */
82
83
84/**
85 * Query info about the current active trap/interrupt.
86 * If no trap is active active an error code is returned.
87 *
88 * @returns VBox status code.
89 * @param pVCpu Pointer to the VMCPU.
90 * @param pu8TrapNo Where to store the trap number.
91 * @param penmType Where to store the trap type
92 */
93VMMDECL(int) TRPMQueryTrap(PVMCPU pVCpu, uint8_t *pu8TrapNo, TRPMEVENT *penmType)
94{
95 /*
96 * Check if we have a trap at present.
97 */
98 if (pVCpu->trpm.s.uActiveVector != ~0U)
99 {
100 if (pu8TrapNo)
101 *pu8TrapNo = (uint8_t)pVCpu->trpm.s.uActiveVector;
102 if (penmType)
103 *penmType = pVCpu->trpm.s.enmActiveType;
104 return VINF_SUCCESS;
105 }
106
107 return VERR_TRPM_NO_ACTIVE_TRAP;
108}
109
110
111/**
112 * Gets the trap number for the current trap.
113 *
114 * The caller is responsible for making sure there is an active trap which
115 * takes an error code when making this request.
116 *
117 * @returns The current trap number.
118 * @param pVCpu Pointer to the VMCPU.
119 */
120VMMDECL(uint8_t) TRPMGetTrapNo(PVMCPU pVCpu)
121{
122 AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
123 return (uint8_t)pVCpu->trpm.s.uActiveVector;
124}
125
126
127/**
128 * Gets the error code for the current trap.
129 *
130 * The caller is responsible for making sure there is an active trap which
131 * takes an error code when making this request.
132 *
133 * @returns Error code.
134 * @param pVCpu Pointer to the VMCPU.
135 */
136VMMDECL(RTGCUINT) TRPMGetErrorCode(PVMCPU pVCpu)
137{
138 AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
139#ifdef VBOX_STRICT
140 switch (pVCpu->trpm.s.uActiveVector)
141 {
142 case X86_XCPT_TS:
143 case X86_XCPT_NP:
144 case X86_XCPT_SS:
145 case X86_XCPT_GP:
146 case X86_XCPT_PF:
147 case X86_XCPT_AC:
148 case X86_XCPT_DF:
149 break;
150 default:
151 AssertMsgFailed(("This trap (%#x) doesn't have any error code\n", pVCpu->trpm.s.uActiveVector));
152 break;
153 }
154#endif
155 return pVCpu->trpm.s.uActiveErrorCode;
156}
157
158
159/**
160 * Gets the fault address for the current trap.
161 *
162 * The caller is responsible for making sure there is an active trap 0x0e when
163 * making this request.
164 *
165 * @returns Fault address associated with the trap.
166 * @param pVCpu Pointer to the VMCPU.
167 */
168VMMDECL(RTGCUINTPTR) TRPMGetFaultAddress(PVMCPU pVCpu)
169{
170 AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
171 AssertMsg(pVCpu->trpm.s.uActiveVector == X86_XCPT_PF, ("Not page-fault trap!\n"));
172 return pVCpu->trpm.s.uActiveCR2;
173}
174
175
176/**
177 * Gets the instruction-length for the current trap (only relevant for software
178 * interrupts and software exceptions #BP and #OF).
179 *
180 * The caller is responsible for making sure there is an active trap 0x0e when
181 * making this request.
182 *
183 * @returns Fault address associated with the trap.
184 * @param pVCpu Pointer to the VMCPU.
185 */
186VMMDECL(uint8_t) TRPMGetInstrLength(PVMCPU pVCpu)
187{
188 AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
189 return pVCpu->trpm.s.cbInstr;
190}
191
192
193/**
194 * Clears the current active trap/exception/interrupt.
195 *
196 * The caller is responsible for making sure there is an active trap
197 * when making this request.
198 *
199 * @returns VBox status code.
200 * @param pVCpu Pointer to the VMCPU.
201 */
202VMMDECL(int) TRPMResetTrap(PVMCPU pVCpu)
203{
204 /*
205 * Cannot reset non-existing trap!
206 */
207 if (pVCpu->trpm.s.uActiveVector == ~0U)
208 {
209 AssertMsgFailed(("No active trap!\n"));
210 return VERR_TRPM_NO_ACTIVE_TRAP;
211 }
212
213 /*
214 * Reset it.
215 */
216 pVCpu->trpm.s.uActiveVector = ~0U;
217 return VINF_SUCCESS;
218}
219
220
221/**
222 * Assert trap/exception/interrupt.
223 *
224 * The caller is responsible for making sure there is no active trap
225 * when making this request.
226 *
227 * @returns VBox status code.
228 * @param pVCpu Pointer to the VMCPU.
229 * @param u8TrapNo The trap vector to assert.
230 * @param enmType Trap type.
231 */
232VMMDECL(int) TRPMAssertTrap(PVMCPU pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType)
233{
234 Log2(("TRPMAssertTrap: u8TrapNo=%02x type=%d\n", u8TrapNo, enmType));
235
236 /*
237 * Cannot assert a trap when one is already active.
238 */
239 if (pVCpu->trpm.s.uActiveVector != ~0U)
240 {
241 AssertMsgFailed(("CPU%d: Active trap %#x\n", pVCpu->idCpu, pVCpu->trpm.s.uActiveVector));
242 return VERR_TRPM_ACTIVE_TRAP;
243 }
244
245 pVCpu->trpm.s.uActiveVector = u8TrapNo;
246 pVCpu->trpm.s.enmActiveType = enmType;
247 pVCpu->trpm.s.uActiveErrorCode = ~(RTGCUINT)0;
248 pVCpu->trpm.s.uActiveCR2 = 0xdeadface;
249 pVCpu->trpm.s.cbInstr = UINT8_MAX;
250 return VINF_SUCCESS;
251}
252
253
254/**
255 * Assert a page-fault exception.
256 *
257 * The caller is responsible for making sure there is no active trap
258 * when making this request.
259 *
260 * @returns VBox status code.
261 * @param pVCpu Pointer to the VMCPU.
262 * @param uCR2 The new fault address.
263 * @param uErrorCode The error code for the page-fault.
264 */
265VMMDECL(int) TRPMAssertXcptPF(PVMCPU pVCpu, RTGCUINTPTR uCR2, RTGCUINT uErrorCode)
266{
267 Log2(("TRPMAssertXcptPF: uCR2=%RGv uErrorCode=%RGv\n", uCR2, uErrorCode)); /** @todo RTGCUINT to be fixed. */
268
269 /*
270 * Cannot assert a trap when one is already active.
271 */
272 if (pVCpu->trpm.s.uActiveVector != ~0U)
273 {
274 AssertMsgFailed(("CPU%d: Active trap %#x\n", pVCpu->idCpu, pVCpu->trpm.s.uActiveVector));
275 return VERR_TRPM_ACTIVE_TRAP;
276 }
277
278 pVCpu->trpm.s.uActiveVector = X86_XCPT_PF;
279 pVCpu->trpm.s.enmActiveType = TRPM_TRAP;
280 pVCpu->trpm.s.uActiveErrorCode = uErrorCode;
281 pVCpu->trpm.s.uActiveCR2 = uCR2;
282 pVCpu->trpm.s.cbInstr = UINT8_MAX;
283 return VINF_SUCCESS;
284}
285
286
287/**
288 * Sets the error code of the current trap.
289 * (This function is for use in trap handlers and such.)
290 *
291 * The caller is responsible for making sure there is an active trap
292 * which takes an errorcode when making this request.
293 *
294 * @param pVCpu Pointer to the VMCPU.
295 * @param uErrorCode The new error code.
296 */
297VMMDECL(void) TRPMSetErrorCode(PVMCPU pVCpu, RTGCUINT uErrorCode)
298{
299 Log2(("TRPMSetErrorCode: uErrorCode=%RGv\n", uErrorCode)); /** @todo RTGCUINT mess! */
300 AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
301 pVCpu->trpm.s.uActiveErrorCode = uErrorCode;
302#ifdef VBOX_STRICT
303 switch (pVCpu->trpm.s.uActiveVector)
304 {
305 case X86_XCPT_TS: case X86_XCPT_NP: case X86_XCPT_SS: case X86_XCPT_GP: case X86_XCPT_PF:
306 AssertMsg(uErrorCode != ~(RTGCUINT)0, ("Invalid uErrorCode=%#x u8TrapNo=%d\n", uErrorCode, pVCpu->trpm.s.uActiveVector));
307 break;
308 case X86_XCPT_AC: case X86_XCPT_DF:
309 AssertMsg(uErrorCode == 0, ("Invalid uErrorCode=%#x u8TrapNo=%d\n", uErrorCode, pVCpu->trpm.s.uActiveVector));
310 break;
311 default:
312 AssertMsg(uErrorCode == ~(RTGCUINT)0, ("Invalid uErrorCode=%#x u8TrapNo=%d\n", uErrorCode, pVCpu->trpm.s.uActiveVector));
313 break;
314 }
315#endif
316}
317
318
319/**
320 * Sets the fault address of the current #PF trap. (This function is for use in
321 * trap handlers and such.)
322 *
323 * The caller is responsible for making sure there is an active trap 0e
324 * when making this request.
325 *
326 * @param pVCpu Pointer to the VMCPU.
327 * @param uCR2 The new fault address (cr2 register).
328 */
329VMMDECL(void) TRPMSetFaultAddress(PVMCPU pVCpu, RTGCUINTPTR uCR2)
330{
331 Log2(("TRPMSetFaultAddress: uCR2=%RGv\n", uCR2));
332 AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
333 AssertMsg(pVCpu->trpm.s.uActiveVector == X86_XCPT_PF, ("Not trap 0e!\n"));
334 pVCpu->trpm.s.uActiveCR2 = uCR2;
335}
336
337
338/**
339 * Sets the instruction-length of the current trap (relevant for software
340 * interrupts and software exceptions like #BP, #OF).
341 *
342 * The caller is responsible for making sure there is an active trap 0e
343 * when making this request.
344 *
345 * @param pVCpu Pointer to the VMCPU.
346 * @param cbInstr The instruction length.
347 */
348VMMDECL(void) TRPMSetInstrLength(PVMCPU pVCpu, uint8_t cbInstr)
349{
350 Log2(("TRPMSetInstrLength: cbInstr=%u\n", cbInstr));
351 AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
352 AssertMsg( pVCpu->trpm.s.enmActiveType == TRPM_SOFTWARE_INT
353 || ( pVCpu->trpm.s.enmActiveType == TRPM_TRAP
354 && ( pVCpu->trpm.s.uActiveVector == X86_XCPT_BP
355 || pVCpu->trpm.s.uActiveVector == X86_XCPT_OF)),
356 ("Invalid trap type %#x\n", pVCpu->trpm.s.enmActiveType));
357 pVCpu->trpm.s.cbInstr = cbInstr;
358}
359
360
361/**
362 * Checks if the current active trap/interrupt/exception/fault/whatever is a software
363 * interrupt or not.
364 *
365 * The caller is responsible for making sure there is an active trap
366 * when making this request.
367 *
368 * @returns true if software interrupt, false if not.
369 *
370 * @param pVCpu Pointer to the VMCPU.
371 */
372VMMDECL(bool) TRPMIsSoftwareInterrupt(PVMCPU pVCpu)
373{
374 AssertMsg(pVCpu->trpm.s.uActiveVector != ~0U, ("No active trap!\n"));
375 return (pVCpu->trpm.s.enmActiveType == TRPM_SOFTWARE_INT);
376}
377
378
379/**
380 * Check if there is an active trap.
381 *
382 * @returns true if trap active, false if not.
383 * @param pVCpu Pointer to the VMCPU.
384 */
385VMMDECL(bool) TRPMHasTrap(PVMCPU pVCpu)
386{
387 return pVCpu->trpm.s.uActiveVector != ~0U;
388}
389
390
391/**
392 * Query all info about the current active trap/interrupt.
393 * If no trap is active active an error code is returned.
394 *
395 * @returns VBox status code.
396 * @param pVCpu Pointer to the VMCPU.
397 * @param pu8TrapNo Where to store the trap number.
398 * @param pEnmType Where to store the trap type
399 * @param puErrorCode Where to store the error code associated with some traps.
400 * ~0U is stored if the trap has no error code.
401 * @param puCR2 Where to store the CR2 associated with a trap 0E.
402 * @param pcbInstr Where to store the instruction-length
403 * associated with some traps.
404 */
405VMMDECL(int) TRPMQueryTrapAll(PVMCPU pVCpu, uint8_t *pu8TrapNo, TRPMEVENT *pEnmType, PRTGCUINT puErrorCode, PRTGCUINTPTR puCR2,
406 uint8_t *pcbInstr)
407{
408 /*
409 * Check if we have a trap at present.
410 */
411 if (pVCpu->trpm.s.uActiveVector == ~0U)
412 return VERR_TRPM_NO_ACTIVE_TRAP;
413
414 if (pu8TrapNo)
415 *pu8TrapNo = (uint8_t)pVCpu->trpm.s.uActiveVector;
416 if (pEnmType)
417 *pEnmType = pVCpu->trpm.s.enmActiveType;
418 if (puErrorCode)
419 *puErrorCode = pVCpu->trpm.s.uActiveErrorCode;
420 if (puCR2)
421 *puCR2 = pVCpu->trpm.s.uActiveCR2;
422 if (pcbInstr)
423 *pcbInstr = pVCpu->trpm.s.cbInstr;
424 return VINF_SUCCESS;
425}
426
427
428/**
429 * Save the active trap.
430 *
431 * This routine useful when doing try/catch in the hypervisor.
432 * Any function which uses temporary trap handlers should
433 * probably also use this facility to save the original trap.
434 *
435 * @param pVM Pointer to the VM.
436 */
437VMMDECL(void) TRPMSaveTrap(PVMCPU pVCpu)
438{
439 pVCpu->trpm.s.uSavedVector = pVCpu->trpm.s.uActiveVector;
440 pVCpu->trpm.s.enmSavedType = pVCpu->trpm.s.enmActiveType;
441 pVCpu->trpm.s.uSavedErrorCode = pVCpu->trpm.s.uActiveErrorCode;
442 pVCpu->trpm.s.uSavedCR2 = pVCpu->trpm.s.uActiveCR2;
443 pVCpu->trpm.s.cbSavedInstr = pVCpu->trpm.s.cbInstr;
444}
445
446
447/**
448 * Restore a saved trap.
449 *
450 * Multiple restores of a saved trap is possible.
451 *
452 * @param pVM Pointer to the VM.
453 */
454VMMDECL(void) TRPMRestoreTrap(PVMCPU pVCpu)
455{
456 pVCpu->trpm.s.uActiveVector = pVCpu->trpm.s.uSavedVector;
457 pVCpu->trpm.s.enmActiveType = pVCpu->trpm.s.enmSavedType;
458 pVCpu->trpm.s.uActiveErrorCode = pVCpu->trpm.s.uSavedErrorCode;
459 pVCpu->trpm.s.uActiveCR2 = pVCpu->trpm.s.uSavedCR2;
460 pVCpu->trpm.s.cbInstr = pVCpu->trpm.s.cbSavedInstr;
461}
462
463
464#ifdef VBOX_WITH_RAW_MODE_NOT_R0
465/**
466 * Forward trap or interrupt to the guest's handler
467 *
468 *
469 * @returns VBox status code.
470 * or does not return at all (when the trap is actually forwarded)
471 *
472 * @param pVM Pointer to the VM.
473 * @param pRegFrame Pointer to the register frame for the trap.
474 * @param iGate Trap or interrupt gate number
475 * @param cbInstr Instruction size (only relevant for software interrupts)
476 * @param enmError TRPM_TRAP_HAS_ERRORCODE or TRPM_TRAP_NO_ERRORCODE.
477 * @param enmType TRPM event type
478 * @param iOrgTrap The original trap.
479 * @internal
480 */
481VMMDECL(int) TRPMForwardTrap(PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t iGate, uint32_t cbInstr,
482 TRPMERRORCODE enmError, TRPMEVENT enmType, int32_t iOrgTrap)
483{
484 AssertReturn(!HMIsEnabled(pVCpu->CTX_SUFF(pVM)), VERR_TRPM_HM_IPE);
485#ifdef TRPM_FORWARD_TRAPS_IN_GC
486 PVM pVM = pVCpu->CTX_SUFF(pVM);
487 X86EFLAGS eflags;
488 Assert(pVM->cCpus == 1);
489
490 STAM_PROFILE_ADV_START(&pVM->trpm.s.CTX_SUFF_Z(StatForwardProf), a);
491
492# if defined(VBOX_STRICT) || defined(LOG_ENABLED)
493 if (pRegFrame->eflags.Bits.u1VM)
494 Log(("TRPMForwardTrap-VM: eip=%04X:%04X iGate=%d\n", pRegFrame->cs.Sel, pRegFrame->eip, iGate));
495 else
496 Log(("TRPMForwardTrap: eip=%04X:%08X iGate=%d\n", pRegFrame->cs.Sel, pRegFrame->eip, iGate));
497
498 switch (iGate) {
499 case X86_XCPT_PF:
500 if (pRegFrame->eip == pVCpu->trpm.s.uActiveCR2)
501 {
502 RTGCPTR pCallerGC;
503# ifdef IN_RC
504 int rc = MMGCRamRead(pVM, &pCallerGC, (void *)pRegFrame->esp, sizeof(pCallerGC));
505# else
506 int rc = PGMPhysSimpleReadGCPtr(pVCpu, &pCallerGC, (RTGCPTR)pRegFrame->esp, sizeof(pCallerGC));
507# endif
508 if (RT_SUCCESS(rc))
509 Log(("TRPMForwardTrap: caller=%RGv\n", pCallerGC));
510 }
511 /* no break */
512 case X86_XCPT_DF:
513 case X86_XCPT_TS:
514 case X86_XCPT_NP:
515 case X86_XCPT_SS:
516 case X86_XCPT_GP:
517 case X86_XCPT_AC:
518 Assert(enmError == TRPM_TRAP_HAS_ERRORCODE || enmType == TRPM_SOFTWARE_INT);
519 break;
520
521 default:
522 Assert(enmError == TRPM_TRAP_NO_ERRORCODE);
523 break;
524 }
525# endif /* VBOX_STRICT || LOG_ENABLED */
526#ifdef IN_RC
527 AssertReturn(CPUMIsGuestInRawMode(pVCpu), VINF_EM_RESCHEDULE);
528#endif
529
530 /* Retrieve the eflags including the virtualized bits. */
531 /* Note: hackish as the cpumctxcore structure doesn't contain the right value */
532 eflags.u32 = CPUMRawGetEFlags(pVCpu);
533
534 /* VMCPU_FF_INHIBIT_INTERRUPTS should be cleared upfront or don't call this function at all for dispatching hardware interrupts. */
535 Assert(enmType != TRPM_HARDWARE_INT || !VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
536
537 /*
538 * If it's a real guest trap and the guest's page fault handler is marked as safe for GC execution, then we call it directly.
539 * Well, only if the IF flag is set.
540 */
541 /** @todo if the trap handler was modified and marked invalid, then we should *now* go back to the host context and install a new patch. */
542 if ( pVM->trpm.s.aGuestTrapHandler[iGate]
543 && (eflags.Bits.u1IF)
544#ifndef VBOX_RAW_V86
545 && !(eflags.Bits.u1VM) /** @todo implement when needed (illegal for same privilege level transfers). */
546#endif
547 && !PATMIsPatchGCAddr(pVM, pRegFrame->eip)
548 )
549 {
550 uint16_t cbIDT;
551 RTGCPTR GCPtrIDT = (RTGCPTR)CPUMGetGuestIDTR(pVCpu, &cbIDT);
552 uint32_t cpl;
553 VBOXIDTE GuestIdte;
554 RTGCPTR pIDTEntry;
555 int rc;
556
557 Assert(PATMAreInterruptsEnabledByCtx(pVM, CPUMCTX_FROM_CORE(pRegFrame)));
558 Assert(!VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_SELM_SYNC_GDT | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_TRPM_SYNC_IDT | VMCPU_FF_SELM_SYNC_TSS));
559
560 if (GCPtrIDT && iGate * sizeof(VBOXIDTE) >= cbIDT)
561 goto failure;
562
563 /* Get the current privilege level. */
564 cpl = CPUMGetGuestCPL(pVCpu);
565
566 /*
567 * BIG TODO: The checks are not complete. see trap and interrupt dispatching section in Intel docs for details
568 * All very obscure, but still necessary.
569 * Currently only some CS & TSS selector checks are missing.
570 *
571 */
572 pIDTEntry = (RTGCPTR)((RTGCUINTPTR)GCPtrIDT + sizeof(VBOXIDTE) * iGate);
573#ifdef IN_RC
574 rc = MMGCRamRead(pVM, &GuestIdte, (void *)(uintptr_t)pIDTEntry, sizeof(GuestIdte));
575#else
576 rc = PGMPhysSimpleReadGCPtr(pVCpu, &GuestIdte, pIDTEntry, sizeof(GuestIdte));
577#endif
578 if (RT_FAILURE(rc))
579 {
580 /* The page might be out of sync. */ /** @todo might cross a page boundary) */
581 Log(("Page %RGv out of sync -> prefetch and try again\n", pIDTEntry));
582 rc = PGMPrefetchPage(pVCpu, pIDTEntry); /** @todo r=bird: rainy day: this isn't entirely safe because of access bit virtualiziation and CSAM. */
583 if (rc != VINF_SUCCESS)
584 {
585 Log(("TRPMForwardTrap: PGMPrefetchPage failed with rc=%Rrc\n", rc));
586 goto failure;
587 }
588#ifdef IN_RC
589 rc = MMGCRamRead(pVM, &GuestIdte, (void *)(uintptr_t)pIDTEntry, sizeof(GuestIdte));
590#else
591 rc = PGMPhysSimpleReadGCPtr(pVCpu, &GuestIdte, pIDTEntry, sizeof(GuestIdte));
592#endif
593 }
594 if ( RT_SUCCESS(rc)
595 && GuestIdte.Gen.u1Present
596 && (GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_TRAP_32 || GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
597 && (GuestIdte.Gen.u2DPL == 3 || GuestIdte.Gen.u2DPL == 0)
598 && (GuestIdte.Gen.u16SegSel & 0xfffc) /* must not be zero */
599 && (enmType == TRPM_TRAP || enmType == TRPM_HARDWARE_INT || cpl <= GuestIdte.Gen.u2DPL) /* CPL <= DPL if software int */
600 )
601 {
602 RTGCPTR pHandler, dummy;
603 RTGCPTR pTrapStackGC;
604
605 pHandler = (RTGCPTR)VBOXIDTE_OFFSET(GuestIdte);
606
607 /* Note: SELMValidateAndConvertCSAddr checks for code type, memory type, selector validity. */
608 /** @todo dpl <= cpl else GPF */
609
610 /* Note: don't use current eflags as we might be in V86 mode and the IDT always contains protected mode selectors */
611 X86EFLAGS fakeflags;
612 fakeflags.u32 = 0;
613
614 rc = SELMValidateAndConvertCSAddr(pVCpu, fakeflags, 0, GuestIdte.Gen.u16SegSel, NULL, pHandler, &dummy);
615 if (rc == VINF_SUCCESS)
616 {
617 VBOXGDTR gdtr = {0, 0};
618 bool fConforming = false;
619 int idx = 0;
620 uint32_t dpl;
621 uint32_t ss_r0;
622 uint32_t esp_r0;
623 X86DESC Desc;
624 RTGCPTR pGdtEntry;
625
626 CPUMGetGuestGDTR(pVCpu, &gdtr);
627 Assert(gdtr.pGdt && gdtr.cbGdt > GuestIdte.Gen.u16SegSel);
628
629 if (!gdtr.pGdt)
630 goto failure;
631
632 pGdtEntry = gdtr.pGdt + (GuestIdte.Gen.u16SegSel >> X86_SEL_SHIFT) * sizeof(X86DESC);
633#ifdef IN_RC
634 rc = MMGCRamRead(pVM, &Desc, (void *)(uintptr_t)pGdtEntry, sizeof(Desc));
635#else
636 rc = PGMPhysSimpleReadGCPtr(pVCpu, &Desc, pGdtEntry, sizeof(Desc));
637#endif
638 if (RT_FAILURE(rc))
639 {
640 /* The page might be out of sync. */ /** @todo might cross a page boundary) */
641 Log(("Page %RGv out of sync -> prefetch and try again\n", pGdtEntry));
642 rc = PGMPrefetchPage(pVCpu, pGdtEntry); /** @todo r=bird: rainy day: this isn't entirely safe because of access bit virtualiziation and CSAM. */
643 if (rc != VINF_SUCCESS)
644 {
645 Log(("PGMPrefetchPage failed with rc=%Rrc\n", rc));
646 goto failure;
647 }
648#ifdef IN_RC
649 rc = MMGCRamRead(pVM, &Desc, (void *)(uintptr_t)pGdtEntry, sizeof(Desc));
650#else
651 rc = PGMPhysSimpleReadGCPtr(pVCpu, &Desc, pGdtEntry, sizeof(Desc));
652#endif
653 if (RT_FAILURE(rc))
654 {
655 Log(("MMGCRamRead failed with %Rrc\n", rc));
656 goto failure;
657 }
658 }
659
660 if (Desc.Gen.u4Type & X86_SEL_TYPE_CONF)
661 {
662 Log(("Conforming code selector\n"));
663 fConforming = true;
664 }
665 /** @todo check descriptor type!! */
666
667 dpl = Desc.Gen.u2Dpl;
668
669 if (!fConforming && dpl < cpl) /* to inner privilege level */
670 {
671 rc = SELMGetRing1Stack(pVM, &ss_r0, &esp_r0);
672 if (RT_FAILURE(rc))
673 goto failure;
674
675 Assert((ss_r0 & X86_SEL_RPL) == 1);
676
677 if ( !esp_r0
678 || !ss_r0
679 || (ss_r0 & X86_SEL_RPL) != ((dpl == 0) ? 1 : dpl)
680 || SELMToFlatBySelEx(pVCpu, fakeflags, ss_r0, (RTGCPTR)esp_r0, SELMTOFLAT_FLAGS_CPL1,
681 (PRTGCPTR)&pTrapStackGC, NULL) != VINF_SUCCESS
682 )
683 {
684 Log(("Invalid ring 0 stack %04X:%08RX32\n", ss_r0, esp_r0));
685 goto failure;
686 }
687 }
688 else
689 if (fConforming || dpl == cpl) /* to the same privilege level */
690 {
691 ss_r0 = pRegFrame->ss.Sel;
692 esp_r0 = pRegFrame->esp;
693
694 if ( eflags.Bits.u1VM /* illegal */
695 || SELMToFlatBySelEx(pVCpu, fakeflags, ss_r0, (RTGCPTR)esp_r0, SELMTOFLAT_FLAGS_CPL1,
696 (PRTGCPTR)&pTrapStackGC, NULL) != VINF_SUCCESS)
697 {
698 AssertMsgFailed(("Invalid stack %04X:%08RX32??? (VM=%d)\n", ss_r0, esp_r0, eflags.Bits.u1VM));
699 goto failure;
700 }
701 }
702 else
703 {
704 Log(("Invalid cpl-dpl combo %d vs %d\n", cpl, dpl));
705 goto failure;
706 }
707 /*
708 * Build trap stack frame on guest handler's stack
709 */
710 uint32_t *pTrapStack;
711#ifdef IN_RC
712 Assert(eflags.Bits.u1VM || (pRegFrame->ss.Sel & X86_SEL_RPL) != 0);
713 /* Check maximum amount we need (10 when executing in V86 mode) */
714 rc = PGMVerifyAccess(pVCpu, (RTGCUINTPTR)pTrapStackGC - 10*sizeof(uint32_t), 10 * sizeof(uint32_t), X86_PTE_RW);
715 pTrapStack = (uint32_t *)(uintptr_t)pTrapStackGC;
716#else
717 Assert(eflags.Bits.u1VM || (pRegFrame->ss.Sel & X86_SEL_RPL) == 0 || (pRegFrame->ss.Sel & X86_SEL_RPL) == 3 || (EMIsRawRing1Enabled(pVM) && (pRegFrame->ss.Sel & X86_SEL_RPL) == 1));
718 /* Check maximum amount we need (10 when executing in V86 mode) */
719 if ((pTrapStackGC >> PAGE_SHIFT) != ((pTrapStackGC - 10*sizeof(uint32_t)) >> PAGE_SHIFT)) /* fail if we cross a page boundary */
720 goto failure;
721 PGMPAGEMAPLOCK PageMappingLock;
722 rc = PGMPhysGCPtr2CCPtr(pVCpu, pTrapStackGC, (void **)&pTrapStack, &PageMappingLock);
723 if (RT_FAILURE(rc))
724 {
725 AssertRC(rc);
726 goto failure;
727 }
728#endif
729 if (rc == VINF_SUCCESS)
730 {
731 /** if eflags.Bits.u1VM then push gs, fs, ds, es */
732 if (eflags.Bits.u1VM)
733 {
734 Log(("TRAP%02X: (VM) Handler %04X:%RGv Stack %04X:%08X RPL=%d CR2=%08X\n", iGate, GuestIdte.Gen.u16SegSel, pHandler, ss_r0, esp_r0, (pRegFrame->ss.Sel & X86_SEL_RPL), pVCpu->trpm.s.uActiveCR2));
735 pTrapStack[--idx] = pRegFrame->gs.Sel;
736 pTrapStack[--idx] = pRegFrame->fs.Sel;
737 pTrapStack[--idx] = pRegFrame->ds.Sel;
738 pTrapStack[--idx] = pRegFrame->es.Sel;
739
740 /* clear ds, es, fs & gs in current context */
741 pRegFrame->ds.Sel = pRegFrame->es.Sel = pRegFrame->fs.Sel = pRegFrame->gs.Sel = 0;
742 }
743 else
744 Log(("TRAP%02X: Handler %04X:%RGv Stack %04X:%08X RPL=%d CR2=%08X\n", iGate, GuestIdte.Gen.u16SegSel, pHandler, ss_r0, esp_r0, (pRegFrame->ss.Sel & X86_SEL_RPL), pVCpu->trpm.s.uActiveCR2));
745
746 if (!fConforming && dpl < cpl)
747 {
748#ifdef IN_RC /* Only in RC we still see tracing of our ring modifications. */
749 if ( (pRegFrame->ss.Sel & X86_SEL_RPL) == 1
750 && !eflags.Bits.u1VM)
751 pTrapStack[--idx] = pRegFrame->ss.Sel & ~1; /* Mask away traces of raw ring 0 execution (ring 1). */
752 else if ( EMIsRawRing1Enabled(pVM)
753 && (pRegFrame->ss.Sel & X86_SEL_RPL) == 2)
754 pTrapStack[--idx] = (pRegFrame->ss.Sel & ~2) | 1; /* Mask away traces of raw ring 1 execution (ring 2). */
755 else
756#endif /* IN_RC */
757 pTrapStack[--idx] = pRegFrame->ss.Sel;
758
759 pTrapStack[--idx] = pRegFrame->esp;
760 }
761
762 /* Note: We use the eflags copy, that includes the virtualized bits! */
763 /* Note: Not really necessary as we grab include those bits in the trap/irq handler trampoline */
764 pTrapStack[--idx] = eflags.u32;
765
766#ifdef IN_RC /* Only in RC mode we still see tracing of our ring modifications */
767 if ( (pRegFrame->cs.Sel & X86_SEL_RPL) == 1
768 && !eflags.Bits.u1VM)
769 pTrapStack[--idx] = pRegFrame->cs.Sel & ~1; /* Mask away traces of raw ring execution (ring 1). */
770 else if ( EMIsRawRing1Enabled(pVM)
771 && (pRegFrame->cs.Sel & X86_SEL_RPL) == 2)
772 pTrapStack[--idx] = (pRegFrame->cs.Sel & ~2) | 1; /* Mask away traces of raw ring 1 execution (ring 2). */
773 else
774#endif /* IN_RC */
775 pTrapStack[--idx] = pRegFrame->cs.Sel;
776
777 if (enmType == TRPM_SOFTWARE_INT)
778 {
779 Assert(cbInstr);
780 pTrapStack[--idx] = pRegFrame->eip + cbInstr; /* return address = next instruction */
781 }
782 else
783 pTrapStack[--idx] = pRegFrame->eip;
784
785 if (enmError == TRPM_TRAP_HAS_ERRORCODE)
786 {
787 pTrapStack[--idx] = pVCpu->trpm.s.uActiveErrorCode;
788 }
789
790 Assert(esp_r0 > -idx*sizeof(uint32_t));
791 /* Adjust ESP accordingly */
792 esp_r0 += idx*sizeof(uint32_t);
793
794 /* Mask away dangerous flags for the trap/interrupt handler. */
795 eflags.u32 &= ~(X86_EFL_TF | X86_EFL_VM | X86_EFL_RF | X86_EFL_NT);
796#ifdef DEBUG
797 if (DBGFIsStepping(pVCpu))
798 eflags.u32 |= X86_EFL_TF;
799#endif
800
801 /* Turn off interrupts for interrupt gates. */
802 if (GuestIdte.Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32)
803 eflags.Bits.u1IF = 0;
804
805 CPUMRawSetEFlags(pVCpu, eflags.u32);
806
807#ifdef DEBUG
808 for (int j = idx; j < 0; j++)
809 LogFlow(("Stack %RRv pos %02d: %08x\n", &pTrapStack[j], j, pTrapStack[j]));
810
811 Log4(("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n"
812 "eip=%08x esp=%08x ebp=%08x iopl=%d\n"
813 "cs=%04x ds=%04x es=%04x fs=%04x gs=%04x eflags=%08x\n",
814 pRegFrame->eax, pRegFrame->ebx, pRegFrame->ecx, pRegFrame->edx, pRegFrame->esi, pRegFrame->edi,
815 pRegFrame->eip, pRegFrame->esp, pRegFrame->ebp, eflags.Bits.u2IOPL,
816 pRegFrame->cs.Sel, pRegFrame->ds.Sel, pRegFrame->es.Sel,
817 pRegFrame->fs.Sel, pRegFrame->gs.Sel, eflags.u32));
818#endif
819
820 Log(("TRPM: PATM Handler %RRv Adjusted stack %08X new EFLAGS=%08X/%08x idx=%d dpl=%d cpl=%d\n",
821 pVM->trpm.s.aGuestTrapHandler[iGate], esp_r0, eflags.u32, CPUMRawGetEFlags(pVCpu), idx, dpl, cpl));
822
823 /* Make sure the internal guest context structure is up-to-date. */
824 if (iGate == X86_XCPT_PF)
825 CPUMSetGuestCR2(pVCpu, pVCpu->trpm.s.uActiveCR2);
826
827#ifdef IN_RC
828 /* paranoia */
829 Assert(pRegFrame->eflags.Bits.u1IF == 1);
830 eflags.Bits.u1IF = 1;
831 Assert(pRegFrame->eflags.Bits.u2IOPL == 0);
832 eflags.Bits.u2IOPL = 0;
833
834 Assert(eflags.Bits.u1IF);
835 Assert(eflags.Bits.u2IOPL == 0);
836 STAM_COUNTER_INC(&pVM->trpm.s.CTX_SUFF(paStatForwardedIRQ)[iGate]);
837 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.CTX_SUFF_Z(StatForwardProf), a);
838 if (iOrgTrap >= 0 && iOrgTrap < (int)RT_ELEMENTS(pVM->trpm.s.aStatGCTraps))
839 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.aStatGCTraps[iOrgTrap], o);
840
841 PGMRZDynMapReleaseAutoSet(pVCpu);
842 CPUMGCCallGuestTrapHandler(pRegFrame, GuestIdte.Gen.u16SegSel | 1, pVM->trpm.s.aGuestTrapHandler[iGate],
843 eflags.u32, ss_r0, (RTRCPTR)esp_r0);
844 /* does not return */
845#else
846
847 Assert(!CPUMIsGuestInRawMode(pVCpu));
848 pRegFrame->eflags.u32 = eflags.u32;
849 pRegFrame->eip = pVM->trpm.s.aGuestTrapHandler[iGate];
850 pRegFrame->cs.Sel = GuestIdte.Gen.u16SegSel;
851 pRegFrame->esp = esp_r0;
852 pRegFrame->ss.Sel = ss_r0 & ~X86_SEL_RPL; /* set rpl to ring 0 */
853 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.CTX_SUFF_Z(StatForwardProf), a);
854 PGMPhysReleasePageMappingLock(pVM, &PageMappingLock);
855 NOREF(iOrgTrap);
856 return VINF_SUCCESS;
857#endif
858 }
859 else
860 Log(("TRAP%02X: PGMVerifyAccess %RGv failed with %Rrc -> forward to REM\n", iGate, pTrapStackGC, rc));
861 }
862 else
863 Log(("SELMValidateAndConvertCSAddr failed with %Rrc\n", rc));
864 }
865 else
866 Log(("MMRamRead %RGv size %d failed with %Rrc\n", (RTGCUINTPTR)GCPtrIDT + sizeof(VBOXIDTE) * iGate, sizeof(GuestIdte), rc));
867 }
868 else
869 {
870 Log(("Refused to forward trap: eflags=%08x IF=%d\n", eflags.u32, eflags.Bits.u1IF));
871#ifdef VBOX_WITH_STATISTICS
872 if (pVM->trpm.s.aGuestTrapHandler[iGate] == TRPM_INVALID_HANDLER)
873 STAM_COUNTER_INC(&pVM->trpm.s.StatForwardFailNoHandler);
874 else if (PATMIsPatchGCAddr(pVM, pRegFrame->eip))
875 STAM_COUNTER_INC(&pVM->trpm.s.StatForwardFailPatchAddr);
876#endif
877 }
878failure:
879 STAM_COUNTER_INC(&pVM->trpm.s.CTX_SUFF_Z(StatForwardFail));
880 STAM_PROFILE_ADV_STOP(&pVM->trpm.s.CTX_SUFF_Z(StatForwardProf), a);
881
882 Log(("TRAP%02X: forwarding to REM (ss rpl=%d eflags=%08X VMIF=%d handler=%08X\n", iGate, pRegFrame->ss.Sel & X86_SEL_RPL, pRegFrame->eflags.u32, PATMAreInterruptsEnabledByCtx(pVM, CPUMCTX_FROM_CORE(pRegFrame)), pVM->trpm.s.aGuestTrapHandler[iGate]));
883#endif
884 return VINF_EM_RAW_GUEST_TRAP;
885}
886#endif /* VBOX_WITH_RAW_MODE_NOT_R0 */
887
888
889/**
890 * Raises a cpu exception which doesn't take an error code.
891 *
892 * This function may or may not dispatch the exception before returning.
893 *
894 * @returns VBox status code fit for scheduling.
895 * @retval VINF_EM_RAW_GUEST_TRAP if the exception was left pending.
896 * @retval VINF_TRPM_XCPT_DISPATCHED if the exception was raised and dispatched for raw-mode execution.
897 * @retval VINF_EM_RESCHEDULE_REM if the exception was dispatched and cannot be executed in raw-mode.
898 *
899 * @param pVM Pointer to the VM.
900 * @param pCtxCore The CPU context core.
901 * @param enmXcpt The exception.
902 */
903VMMDECL(int) TRPMRaiseXcpt(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, X86XCPT enmXcpt)
904{
905 LogFlow(("TRPMRaiseXcptErr: cs:eip=%RTsel:%RX32 enmXcpt=%#x\n", pCtxCore->cs.Sel, pCtxCore->eip, enmXcpt));
906 NOREF(pCtxCore);
907/** @todo dispatch the trap. */
908 pVCpu->trpm.s.uActiveVector = enmXcpt;
909 pVCpu->trpm.s.enmActiveType = TRPM_TRAP;
910 pVCpu->trpm.s.uActiveErrorCode = 0xdeadbeef;
911 pVCpu->trpm.s.uActiveCR2 = 0xdeadface;
912 pVCpu->trpm.s.cbInstr = UINT8_MAX;
913 return VINF_EM_RAW_GUEST_TRAP;
914}
915
916
917/**
918 * Raises a cpu exception with an errorcode.
919 *
920 * This function may or may not dispatch the exception before returning.
921 *
922 * @returns VBox status code fit for scheduling.
923 * @retval VINF_EM_RAW_GUEST_TRAP if the exception was left pending.
924 * @retval VINF_TRPM_XCPT_DISPATCHED if the exception was raised and dispatched for raw-mode execution.
925 * @retval VINF_EM_RESCHEDULE_REM if the exception was dispatched and cannot be executed in raw-mode.
926 *
927 * @param pVM Pointer to the VM.
928 * @param pCtxCore The CPU context core.
929 * @param enmXcpt The exception.
930 * @param uErr The error code.
931 */
932VMMDECL(int) TRPMRaiseXcptErr(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, X86XCPT enmXcpt, uint32_t uErr)
933{
934 LogFlow(("TRPMRaiseXcptErr: cs:eip=%RTsel:%RX32 enmXcpt=%#x uErr=%RX32\n", pCtxCore->cs.Sel, pCtxCore->eip, enmXcpt, uErr));
935 NOREF(pCtxCore);
936/** @todo dispatch the trap. */
937 pVCpu->trpm.s.uActiveVector = enmXcpt;
938 pVCpu->trpm.s.enmActiveType = TRPM_TRAP;
939 pVCpu->trpm.s.uActiveErrorCode = uErr;
940 pVCpu->trpm.s.uActiveCR2 = 0xdeadface;
941 pVCpu->trpm.s.cbInstr = UINT8_MAX;
942 return VINF_EM_RAW_GUEST_TRAP;
943}
944
945
946/**
947 * Raises a cpu exception with an errorcode and CR2.
948 *
949 * This function may or may not dispatch the exception before returning.
950 *
951 * @returns VBox status code fit for scheduling.
952 * @retval VINF_EM_RAW_GUEST_TRAP if the exception was left pending.
953 * @retval VINF_TRPM_XCPT_DISPATCHED if the exception was raised and dispatched for raw-mode execution.
954 * @retval VINF_EM_RESCHEDULE_REM if the exception was dispatched and cannot be executed in raw-mode.
955 *
956 * @param pVM Pointer to the VM.
957 * @param pCtxCore The CPU context core.
958 * @param enmXcpt The exception.
959 * @param uErr The error code.
960 * @param uCR2 The CR2 value.
961 */
962VMMDECL(int) TRPMRaiseXcptErrCR2(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, X86XCPT enmXcpt, uint32_t uErr, RTGCUINTPTR uCR2)
963{
964 LogFlow(("TRPMRaiseXcptErr: cs:eip=%RTsel:%RX32 enmXcpt=%#x uErr=%RX32 uCR2=%RGv\n", pCtxCore->cs.Sel, pCtxCore->eip, enmXcpt, uErr, uCR2));
965 NOREF(pCtxCore);
966/** @todo dispatch the trap. */
967 pVCpu->trpm.s.uActiveVector = enmXcpt;
968 pVCpu->trpm.s.enmActiveType = TRPM_TRAP;
969 pVCpu->trpm.s.uActiveErrorCode = uErr;
970 pVCpu->trpm.s.uActiveCR2 = uCR2;
971 pVCpu->trpm.s.cbInstr = UINT8_MAX;
972 return VINF_EM_RAW_GUEST_TRAP;
973}
974
975
976#ifdef VBOX_WITH_RAW_MODE
977/**
978 * Clear guest trap/interrupt gate handler
979 *
980 * @returns VBox status code.
981 * @param pVM Pointer to the VM.
982 * @param iTrap Interrupt/trap number.
983 */
984VMMDECL(int) trpmClearGuestTrapHandler(PVM pVM, unsigned iTrap)
985{
986 AssertReturn(!HMIsEnabled(pVM), VERR_TRPM_HM_IPE);
987 AssertMsgReturn(iTrap < RT_ELEMENTS(pVM->trpm.s.aIdt), ("Illegal gate number %d!\n", iTrap), VERR_INVALID_PARAMETER);
988
989 if (ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iTrap))
990# ifdef IN_RING3
991 trpmR3ClearPassThroughHandler(pVM, iTrap);
992# else
993 AssertFailed();
994# endif
995
996 pVM->trpm.s.aGuestTrapHandler[iTrap] = TRPM_INVALID_HANDLER;
997 return VINF_SUCCESS;
998}
999#endif /* VBOX_WITH_RAW_MODE */
1000
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