VirtualBox

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

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

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

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