VirtualBox

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

Last change on this file since 840 was 415, checked in by vboxsync, 18 years ago

Fixing interrupt dispatching on amd64.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.9 KB
Line 
1/* $Id: TRPMR0.cpp 415 2007-01-29 18:04:13Z vboxsync $ */
2/** @file
3 * TRPM - The Trap Monitor - HC Ring 0
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung 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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_TRPM
27#include <VBox/trpm.h>
28#include "TRPMInternal.h"
29#include <VBox/vm.h>
30#include <VBox/err.h>
31#include <VBox/log.h>
32#include <iprt/assert.h>
33#include <iprt/asm.h>
34
35
36/**
37 * Dispatches an interrupt that arrived while we were in the guest context.
38 *
39 * @param pVM The VM handle.
40 * @remark Must be called with interrupts disabled.
41 */
42TRPMR0DECL(void) TRPMR0DispatchHostInterrupt(PVM pVM)
43{
44 RTUINT uActiveVector = pVM->trpm.s.uActiveVector;
45 pVM->trpm.s.uActiveVector = ~0;
46 AssertMsgReturnVoid(uActiveVector < 256, ("uActiveVector=%#x is invalid! (More assertions to come, please enjoy!)\n", uActiveVector));
47
48 /*
49 * Get the handler pointer (16:32 ptr) / (16:48 ptr).
50 */
51 RTIDTR Idtr;
52 ASMGetIDTR(&Idtr);
53#if HC_ARCH_BITS == 32
54 PVBOXIDTE pIdte = &((PVBOXIDTE)Idtr.pIdt)[uActiveVector];
55#else
56 PVBOXIDTE pIdte = &((PVBOXIDTE)Idtr.pIdt)[uActiveVector * 2];
57#endif
58 AssertMsgReturnVoid(pIdte->Gen.u1Present, ("The IDT entry (%d) is not present!\n", uActiveVector));
59 AssertMsgReturnVoid( pIdte->Gen.u3Type1 == VBOX_IDTE_TYPE1
60 || pIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32,
61 ("The IDT entry (%d) is not 32-bit int gate! type1=%#x type2=%#x\n",
62 uActiveVector, pIdte->Gen.u3Type1, pIdte->Gen.u5Type2));
63#if HC_ARCH_BITS == 32
64 RTFAR32 pfnHandler;
65 pfnHandler.off = (pIdte->Gen.u16OffsetHigh << 16) | pIdte->Gen.u16OffsetLow;
66 pfnHandler.sel = pIdte->Gen.u16SegSel;
67
68 const RTR0UINTREG uRSP = ~(RTR0UINTREG)0;
69
70#else /* 64-bit: */
71 RTFAR64 pfnHandler;
72 pfnHandler.off = (pIdte->Gen.u16OffsetHigh << 16) | pIdte->Gen.u16OffsetLow;
73 pfnHandler.off |= (uint64_t)(*(uint32_t *)(pIdte + 1)) << 32; //cleanup!
74 pfnHandler.sel = pIdte->Gen.u16SegSel;
75
76 RTR0UINTREG uRSP = ~(RTR0UINTREG)0;
77 if (pIdte->au32[1] & 0x7 /*IST*/)
78 {
79 /** @todo implement IST */
80 }
81
82#endif
83
84 /*
85 * Dispatch it.
86 */
87 trpmR0DispatchHostInterrupt(pfnHandler.off, pfnHandler.sel, uRSP);
88}
89
90#ifndef VBOX_WITHOUT_IDT_PATCHING
91
92/**
93 * Changes the VMMR0Entry() call frame and stack used by the IDT patch code
94 * so that we'll dispatch an interrupt rather than returning directly to Ring-3
95 * when VMMR0Entry() returns.
96 *
97 * @param pVM Pointer to the VM.
98 * @param pvRet Pointer to the return address of VMMR0Entry() on the stack.
99 */
100TRPMR0DECL(void) TRPMR0SetupInterruptDispatcherFrame(PVM pVM, void *pvRet)
101{
102 RTUINT uActiveVector = pVM->trpm.s.uActiveVector;
103 pVM->trpm.s.uActiveVector = ~0;
104 AssertMsgReturnVoid(uActiveVector < 256, ("uActiveVector=%#x is invalid! (More assertions to come, please enjoy!)\n", uActiveVector));
105
106#if HC_ARCH_BITS == 32
107 /*
108 * Get the handler pointer (16:32 ptr).
109 */
110 RTIDTR Idtr;
111 ASMGetIDTR(&Idtr);
112 PVBOXIDTE pIdte = &((PVBOXIDTE)Idtr.pIdt)[uActiveVector];
113 AssertMsgReturnVoid(pIdte->Gen.u1Present, ("The IDT entry (%d) is not present!\n", uActiveVector));
114 AssertMsgReturnVoid( pIdte->Gen.u3Type1 == VBOX_IDTE_TYPE1
115 && pIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32,
116 ("The IDT entry (%d) is not 32-bit int gate! type1=%#x type2=%#x\n",
117 uActiveVector, pIdte->Gen.u3Type1, pIdte->Gen.u5Type2));
118
119 RTFAR32 pfnHandler;
120 pfnHandler.off = (pIdte->Gen.u16OffsetHigh << 16) | pIdte->Gen.u16OffsetLow;
121 pfnHandler.sel = pIdte->Gen.u16SegSel;
122
123 /*
124 * The stack frame is as follows:
125 *
126 * 1c iret frame
127 * 18 fs
128 * 14 ds
129 * 10 es
130 * c uArg
131 * 8 uOperation
132 * 4 pVM
133 * 0 return address (pvRet points here)
134 *
135 * We'll change the stackframe so that we will not return
136 * to the caller but to a interrupt dispatcher. We'll also
137 * setup the frame so that ds and es are moved to give room
138 * to a far return (to the handler).
139 */
140 unsigned *pau = (unsigned *)pvRet;
141 pau[0] = (unsigned)trpmR0InterruptDispatcher; /* new return address */
142 pau[3] = pau[6]; /* uArg = fs */
143 pau[2] = pau[5]; /* uOperation = ds */
144 pau[5] = pfnHandler.off; /* ds = retf off */
145 pau[6] = pfnHandler.sel; /* fs = retf sel */
146
147#else /* 64-bit: */
148
149 /*
150 * Get the handler pointer (16:48 ptr).
151 */
152 RTIDTR Idtr;
153 ASMGetIDTR(&Idtr);
154 PVBOXIDTE pIdte = &((PVBOXIDTE)Idtr.pIdt)[uActiveVector * 2];
155
156 AssertMsgReturnVoid(pIdte->Gen.u1Present, ("The IDT entry (%d) is not present!\n", uActiveVector));
157 AssertMsgReturnVoid( pIdte->Gen.u3Type1 == VBOX_IDTE_TYPE1
158 && pIdte->Gen.u5Type2 == VBOX_IDTE_TYPE2_INT_32, /* == 64 */
159 ("The IDT entry (%d) is not 64-bit int gate! type1=%#x type2=%#x\n",
160 uActiveVector, pIdte->Gen.u3Type1, pIdte->Gen.u5Type2));
161
162 RTFAR64 pfnHandler;
163 pfnHandler.off = (pIdte->Gen.u16OffsetHigh << 16) | pIdte->Gen.u16OffsetLow;
164 pfnHandler.off |= (uint64_t)(*(uint32_t *)(pIdte + 1)) << 32; //cleanup!
165 pfnHandler.sel = pIdte->Gen.u16SegSel;
166
167 if (pIdte->au32[1] & 0x7 /*IST*/)
168 {
169 /** @todo implement IST */
170 }
171
172 /*
173 * The stack frame is as follows:
174 *
175 * 28 iret frame
176 * 20 dummy
177 * 14 uArg
178 * 10 uOperation
179 * 8 pVM
180 * 0 return address (pvRet points here)
181 *
182 * We'll change the stackframe so that we will not return
183 * to the caller but to a interrupt dispatcher. And we'll create
184 * a 64-bit far return frame where dummy and uArg is.
185 */
186 uint64_t *pau = (uint64_t *)pvRet;
187 Assert(pau[1] == (uint64_t)pVM);
188 pau[0] = (uint64_t)trpmR0InterruptDispatcher; /* new return address */
189 pau[3] = pfnHandler.off; /* retf off */
190 pau[4] = pfnHandler.sel; /* retf sel */
191#endif
192}
193
194#endif /* !VBOX_WITHOUT_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