VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR0/TRPMR0.cpp@ 7796

Last change on this file since 7796 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.2 KB
Line 
1/* $Id: TRPMR0.cpp 5999 2007-12-07 15:05:06Z vboxsync $ */
2/** @file
3 * TRPM - The Trap Monitor - HC Ring 0
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (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/trpm.h>
24#include "TRPMInternal.h"
25#include <VBox/vm.h>
26#include <VBox/err.h>
27#include <VBox/log.h>
28#include <iprt/assert.h>
29#include <iprt/asm.h>
30
31
32/**
33 * Dispatches an interrupt that arrived while we were in the guest context.
34 *
35 * @param pVM The VM handle.
36 * @remark Must be called with interrupts disabled.
37 */
38TRPMR0DECL(void) TRPMR0DispatchHostInterrupt(PVM pVM)
39{
40 RTUINT uActiveVector = pVM->trpm.s.uActiveVector;
41 pVM->trpm.s.uActiveVector = ~0;
42 AssertMsgReturnVoid(uActiveVector < 256, ("uActiveVector=%#x is invalid! (More assertions to come, please enjoy!)\n", uActiveVector));
43
44#ifdef VBOX_WITH_HYBIRD_32BIT_KERNEL
45 /*
46 * Check if we're in long mode or not.
47 */
48 if ( (ASMCpuId_EDX(0x80000001) & X86_CPUID_AMD_FEATURE_EDX_LONG_MODE)
49 && (ASMRdMsr(MSR_K6_EFER) & MSR_K6_EFER_LMA))
50 {
51 trpmR0DispatchHostInterruptSimple(uActiveVector);
52 return;
53 }
54#endif
55
56 /*
57 * Get the handler pointer (16:32 ptr) / (16:48 ptr).
58 */
59 RTIDTR Idtr;
60 ASMGetIDTR(&Idtr);
61#if HC_ARCH_BITS == 32
62 PVBOXIDTE pIdte = &((PVBOXIDTE)Idtr.pIdt)[uActiveVector];
63#else
64 PVBOXIDTE pIdte = &((PVBOXIDTE)Idtr.pIdt)[uActiveVector * 2];
65#endif
66 AssertMsgReturnVoid(pIdte->Gen.u1Present, ("The IDT entry (%d) is not present!\n", uActiveVector));
67 AssertMsgReturnVoid( pIdte->Gen.u3Type1 == VBOX_IDTE_TYPE1
68 || pIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32,
69 ("The IDT entry (%d) is not 32-bit int gate! type1=%#x type2=%#x\n",
70 uActiveVector, pIdte->Gen.u3Type1, pIdte->Gen.u5Type2));
71#if HC_ARCH_BITS == 32
72 RTFAR32 pfnHandler;
73 pfnHandler.off = (pIdte->Gen.u16OffsetHigh << 16) | pIdte->Gen.u16OffsetLow;
74 pfnHandler.sel = pIdte->Gen.u16SegSel;
75
76 const RTR0UINTREG uRSP = ~(RTR0UINTREG)0;
77
78#else /* 64-bit: */
79 RTFAR64 pfnHandler;
80 pfnHandler.off = (pIdte->Gen.u16OffsetHigh << 16) | pIdte->Gen.u16OffsetLow;
81 pfnHandler.off |= (uint64_t)(*(uint32_t *)(pIdte + 1)) << 32; //cleanup!
82 pfnHandler.sel = pIdte->Gen.u16SegSel;
83
84 RTR0UINTREG uRSP = ~(RTR0UINTREG)0;
85 if (pIdte->au32[1] & 0x7 /*IST*/)
86 {
87 trpmR0DispatchHostInterruptSimple(uActiveVector);
88 return;
89 }
90
91#endif
92
93 /*
94 * Dispatch it.
95 */
96 trpmR0DispatchHostInterrupt(pfnHandler.off, pfnHandler.sel, uRSP);
97}
98
99
100#ifdef VBOX_WITH_IDT_PATCHING
101# ifdef VBOX_WITH_HYBIRD_32BIT_KERNEL
102# error "VBOX_WITH_HYBIRD_32BIT_KERNEL with VBOX_WITH_IDT_PATCHING isn't supported"
103# endif
104
105/**
106 * Changes the VMMR0Entry() call frame and stack used by the IDT patch code
107 * so that we'll dispatch an interrupt rather than returning directly to Ring-3
108 * when VMMR0Entry() returns.
109 *
110 * @param pVM Pointer to the VM.
111 * @param pvRet Pointer to the return address of VMMR0Entry() on the stack.
112 */
113TRPMR0DECL(void) TRPMR0SetupInterruptDispatcherFrame(PVM pVM, void *pvRet)
114{
115 RTUINT uActiveVector = pVM->trpm.s.uActiveVector;
116 pVM->trpm.s.uActiveVector = ~0;
117 AssertMsgReturnVoid(uActiveVector < 256, ("uActiveVector=%#x is invalid! (More assertions to come, please enjoy!)\n", uActiveVector));
118
119#if HC_ARCH_BITS == 32
120 /*
121 * Get the handler pointer (16:32 ptr).
122 */
123 RTIDTR Idtr;
124 ASMGetIDTR(&Idtr);
125 PVBOXIDTE pIdte = &((PVBOXIDTE)Idtr.pIdt)[uActiveVector];
126 AssertMsgReturnVoid(pIdte->Gen.u1Present, ("The IDT entry (%d) is not present!\n", uActiveVector));
127 AssertMsgReturnVoid( pIdte->Gen.u3Type1 == VBOX_IDTE_TYPE1
128 && pIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32,
129 ("The IDT entry (%d) is not 32-bit int gate! type1=%#x type2=%#x\n",
130 uActiveVector, pIdte->Gen.u3Type1, pIdte->Gen.u5Type2));
131
132 RTFAR32 pfnHandler;
133 pfnHandler.off = (pIdte->Gen.u16OffsetHigh << 16) | pIdte->Gen.u16OffsetLow;
134 pfnHandler.sel = pIdte->Gen.u16SegSel;
135
136 /*
137 * The stack frame is as follows:
138 *
139 * 1c iret frame
140 * 18 fs
141 * 14 ds
142 * 10 es
143 * c uArg
144 * 8 uOperation
145 * 4 pVM
146 * 0 return address (pvRet points here)
147 *
148 * We'll change the stackframe so that we will not return
149 * to the caller but to a interrupt dispatcher. We'll also
150 * setup the frame so that ds and es are moved to give room
151 * to a far return (to the handler).
152 */
153 unsigned *pau = (unsigned *)pvRet;
154 pau[0] = (unsigned)trpmR0InterruptDispatcher; /* new return address */
155 pau[3] = pau[6]; /* uArg = fs */
156 pau[2] = pau[5]; /* uOperation = ds */
157 pau[5] = pfnHandler.off; /* ds = retf off */
158 pau[6] = pfnHandler.sel; /* fs = retf sel */
159
160#else /* 64-bit: */
161
162 /*
163 * Get the handler pointer (16:48 ptr).
164 */
165 RTIDTR Idtr;
166 ASMGetIDTR(&Idtr);
167 PVBOXIDTE pIdte = &((PVBOXIDTE)Idtr.pIdt)[uActiveVector * 2];
168
169 AssertMsgReturnVoid(pIdte->Gen.u1Present, ("The IDT entry (%d) is not present!\n", uActiveVector));
170 AssertMsgReturnVoid( pIdte->Gen.u3Type1 == VBOX_IDTE_TYPE1
171 && pIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32, /* == 64 */
172 ("The IDT entry (%d) is not 64-bit int gate! type1=%#x type2=%#x\n",
173 uActiveVector, pIdte->Gen.u3Type1, pIdte->Gen.u5Type2));
174
175 RTFAR64 pfnHandler;
176 pfnHandler.off = (pIdte->Gen.u16OffsetHigh << 16) | pIdte->Gen.u16OffsetLow;
177 pfnHandler.off |= (uint64_t)(*(uint32_t *)(pIdte + 1)) << 32; //cleanup!
178 pfnHandler.sel = pIdte->Gen.u16SegSel;
179
180 if (pIdte->au32[1] & 0x7 /*IST*/)
181 {
182 /** @todo implement IST */
183 }
184
185 /*
186 * The stack frame is as follows:
187 *
188 * 28 iret frame
189 * 20 dummy
190 * 14 uArg
191 * 10 uOperation
192 * 8 pVM
193 * 0 return address (pvRet points here)
194 *
195 * We'll change the stackframe so that we will not return
196 * to the caller but to a interrupt dispatcher. And we'll create
197 * a 64-bit far return frame where dummy and uArg is.
198 */
199 uint64_t *pau = (uint64_t *)pvRet;
200 Assert(pau[1] == (uint64_t)pVM);
201 pau[0] = (uint64_t)trpmR0InterruptDispatcher; /* new return address */
202 pau[3] = pfnHandler.off; /* retf off */
203 pau[4] = pfnHandler.sel; /* retf sel */
204#endif
205}
206
207#endif /* VBOX_WITH_IDT_PATCHING */
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