VirtualBox

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

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

VMM: Fixed almost all the Doxygen warnings.

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